1 /*****************************************************************************
2 * input_ext-plugins.c: useful functions for access and demux plug-ins
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: input_ext-plugins.c,v 1.24 2002/11/13 20:51:05 sam Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include "stream_control.h"
33 #include "input_ext-intf.h"
34 #include "input_ext-dec.h"
35 #include "input_ext-plugins.h"
39 * Buffers management : internal functions
41 * All functions are static, but exported versions with mutex protection
42 * start with input_*. Not all of these exported functions are actually used,
43 * but they are included here for completeness.
46 #define BUFFERS_CACHE_SIZE 500
47 #define DATA_CACHE_SIZE 1000
48 #define PES_CACHE_SIZE 1000
50 /*****************************************************************************
51 * data_buffer_t: shared data type
52 *****************************************************************************/
55 data_buffer_t * p_next;
57 /* number of data packets this buffer is referenced from - when it falls
58 * down to 0, the buffer is freed */
61 /* size of the current buffer (starting right after this byte) */
65 /*****************************************************************************
66 * input_buffers_t: defines a LIFO per data type to keep
67 *****************************************************************************/
68 #define PACKETS_LIFO( TYPE, NAME ) \
72 unsigned int i_depth; \
75 struct input_buffers_t
78 PACKETS_LIFO( pes_packet_t, pes )
79 PACKETS_LIFO( data_packet_t, data )
80 PACKETS_LIFO( data_buffer_t, buffers )
85 /*****************************************************************************
86 * input_BuffersInit: initialize the cache structures, return a pointer to it
87 *****************************************************************************/
88 void * __input_BuffersInit( vlc_object_t *p_this )
90 input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
92 if( p_buffers == NULL )
97 memset( p_buffers, 0, sizeof( input_buffers_t ) );
98 vlc_mutex_init( p_this, &p_buffers->lock );
103 /*****************************************************************************
104 * input_BuffersEnd: free all cached structures
105 *****************************************************************************/
106 #define BUFFERS_END_PACKETS_LOOP \
107 while( p_packet != NULL ) \
109 p_next = p_packet->p_next; \
114 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
116 if( p_buffers != NULL )
118 msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
119 msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
120 msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
124 pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
125 BUFFERS_END_PACKETS_LOOP;
129 /* Free data packets */
130 data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
131 BUFFERS_END_PACKETS_LOOP;
136 data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
137 while( p_buf != NULL )
139 p_next = p_buf->p_next;
140 p_buffers->i_allocated -= p_buf->i_size;
146 if( p_buffers->i_allocated )
148 msg_Err( p_input, "%d bytes have not been freed, "
149 "expect memory leak", p_buffers->i_allocated );
152 vlc_mutex_destroy( &p_buffers->lock );
157 /*****************************************************************************
158 * input_NewBuffer: return a pointer to a data buffer of the appropriate size
159 *****************************************************************************/
160 static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
163 data_buffer_t * p_buf;
166 if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
171 if( p_buffers->buffers.p_stack != NULL )
173 /* Take the buffer from the cache */
174 p_buf = p_buffers->buffers.p_stack;
175 p_buffers->buffers.p_stack = p_buf->p_next;
176 p_buffers->buffers.i_depth--;
178 /* Reallocate the packet if it is too small or too large */
179 if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
181 p_buffers->i_allocated -= p_buf->i_size;
183 p_buf = malloc( sizeof(input_buffers_t) + i_size );
188 p_buf->i_size = i_size;
189 p_buffers->i_allocated += i_size;
194 /* Allocate a new buffer */
195 p_buf = malloc( sizeof(input_buffers_t) + i_size );
200 p_buf->i_size = i_size;
201 p_buffers->i_allocated += i_size;
204 /* Initialize data */
205 p_buf->p_next = NULL;
206 p_buf->i_refcount = 0;
211 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
213 data_buffer_t * p_buf;
215 vlc_mutex_lock( &p_buffers->lock );
216 p_buf = NewBuffer( p_buffers, i_size );
217 vlc_mutex_unlock( &p_buffers->lock );
222 /*****************************************************************************
223 * input_ReleaseBuffer: put a buffer back into the cache
224 *****************************************************************************/
225 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
226 data_buffer_t * p_buf )
228 /* Decrement refcount */
229 if( --p_buf->i_refcount > 0 )
234 if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
236 /* Cache not full : store the buffer in it */
237 p_buf->p_next = p_buffers->buffers.p_stack;
238 p_buffers->buffers.p_stack = p_buf;
239 p_buffers->buffers.i_depth++;
243 p_buffers->i_allocated -= p_buf->i_size;
248 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
250 vlc_mutex_lock( &p_buffers->lock );
251 ReleaseBuffer( p_buffers, p_buf );
252 vlc_mutex_unlock( &p_buffers->lock );
255 /*****************************************************************************
256 * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
257 *****************************************************************************/
258 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
259 data_buffer_t * p_buf )
261 data_packet_t * p_data;
263 if( p_buffers->data.p_stack != NULL )
265 /* Take the packet from the cache */
266 p_data = p_buffers->data.p_stack;
267 p_buffers->data.p_stack = p_data->p_next;
268 p_buffers->data.i_depth--;
272 /* Allocate a new packet */
273 p_data = malloc( sizeof(data_packet_t) );
280 p_data->p_buffer = p_buf;
281 p_data->p_next = NULL;
282 p_data->b_discard_payload = 0;
283 p_data->p_payload_start = p_data->p_demux_start
284 = (byte_t *)p_buf + sizeof(input_buffers_t);
285 p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
291 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
292 data_buffer_t * p_buf )
294 data_packet_t * p_data;
296 vlc_mutex_lock( &p_buffers->lock );
297 p_data = ShareBuffer( p_buffers, p_buf );
298 vlc_mutex_unlock( &p_buffers->lock );
303 /*****************************************************************************
304 * input_NewPacket: allocate a packet along with a buffer
305 *****************************************************************************/
306 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
309 data_buffer_t * p_buf;
310 data_packet_t * p_data;
312 p_buf = NewBuffer( p_buffers, i_size );
319 p_data = ShareBuffer( p_buffers, p_buf );
322 ReleaseBuffer( p_buffers, p_buf );
327 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
329 data_packet_t * p_data;
331 vlc_mutex_lock( &p_buffers->lock );
332 p_data = NewPacket( p_buffers, i_size );
333 vlc_mutex_unlock( &p_buffers->lock );
338 /*****************************************************************************
339 * input_DeletePacket: deallocate a packet and its buffers
340 *****************************************************************************/
341 static inline void DeletePacket( input_buffers_t * p_buffers,
342 data_packet_t * p_data )
344 while( p_data != NULL )
346 data_packet_t * p_next = p_data->p_next;
348 ReleaseBuffer( p_buffers, p_data->p_buffer );
350 if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
352 /* Cache not full : store the packet in it */
353 p_data->p_next = p_buffers->data.p_stack;
354 p_buffers->data.p_stack = p_data;
355 p_buffers->data.i_depth++;
366 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
368 vlc_mutex_lock( &p_buffers->lock );
369 DeletePacket( p_buffers, p_data );
370 vlc_mutex_unlock( &p_buffers->lock );
373 /*****************************************************************************
374 * input_NewPES: return a pointer to a new PES packet
375 *****************************************************************************/
376 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
378 pes_packet_t * p_pes;
380 if( p_buffers->pes.p_stack != NULL )
382 /* Take the packet from the cache */
383 p_pes = p_buffers->pes.p_stack;
384 p_buffers->pes.p_stack = p_pes->p_next;
385 p_buffers->pes.i_depth--;
389 /* Allocate a new packet */
390 p_pes = malloc( sizeof(pes_packet_t) );
397 p_pes->p_next = NULL;
398 p_pes->b_data_alignment = p_pes->b_discontinuity = VLC_FALSE;
399 p_pes->i_pts = p_pes->i_dts = 0;
400 p_pes->p_first = p_pes->p_last = NULL;
401 p_pes->i_pes_size = 0;
402 p_pes->i_nb_data = 0;
407 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
409 pes_packet_t * p_pes;
411 vlc_mutex_lock( &p_buffers->lock );
412 p_pes = NewPES( p_buffers );
413 vlc_mutex_unlock( &p_buffers->lock );
418 /*****************************************************************************
419 * input_DeletePES: put a pes and all data packets and all buffers back into
421 *****************************************************************************/
422 static inline void DeletePES( input_buffers_t * p_buffers,
423 pes_packet_t * p_pes )
425 while( p_pes != NULL )
427 pes_packet_t * p_next = p_pes->p_next;
429 /* Delete all data packets */
430 if( p_pes->p_first != NULL )
432 DeletePacket( p_buffers, p_pes->p_first );
435 if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
437 /* Cache not full : store the packet in it */
438 p_pes->p_next = p_buffers->pes.p_stack;
439 p_buffers->pes.p_stack = p_pes;
440 p_buffers->pes.i_depth++;
451 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
453 vlc_mutex_lock( &p_buffers->lock );
454 DeletePES( p_buffers, p_pes );
455 vlc_mutex_unlock( &p_buffers->lock );
460 * Buffers management : external functions
462 * These functions make the glu between the access plug-in (pf_read) and
463 * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
464 * with a call to pf_read, then allow the demux plug-in to have a peep at
465 * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
467 /*****************************************************************************
468 * input_FillBuffer: fill in p_data_buffer with data from pf_read
469 *****************************************************************************/
470 ssize_t input_FillBuffer( input_thread_t * p_input )
472 ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
473 data_buffer_t * p_buf;
476 vlc_mutex_lock( &p_input->p_method_data->lock );
478 p_buf = NewBuffer( p_input->p_method_data,
479 i_remains + p_input->i_bufsize );
482 msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
485 p_buf->i_refcount = 1;
487 if( p_input->p_data_buffer != NULL )
491 p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
492 p_input->p_current_data,
495 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
498 /* Do not hold the lock during pf_read (blocking call). */
499 vlc_mutex_unlock( &p_input->p_method_data->lock );
501 i_ret = p_input->pf_read( p_input,
502 (byte_t *)p_buf + sizeof(data_buffer_t)
504 p_input->i_bufsize );
505 if( i_ret < 0 ) i_ret = 0;
507 p_input->p_data_buffer = p_buf;
508 p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
509 p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
511 return (ssize_t)i_remains + i_ret;
514 /*****************************************************************************
515 * input_Peek: give a pointer to the next available bytes in the buffer
516 * (min. i_size bytes)
517 * Returns the number of bytes read, or -1 in case of error
518 *****************************************************************************/
519 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
521 if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
523 /* Go to the next buffer */
524 size_t i_ret = input_FillBuffer( p_input );
530 else if( i_ret < i_size )
535 *pp_byte = p_input->p_current_data;
539 /*****************************************************************************
540 * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
541 * Returns the number of bytes read, or -1 in case of error
542 *****************************************************************************/
543 ssize_t input_SplitBuffer( input_thread_t * p_input,
544 data_packet_t ** pp_data, size_t i_size )
546 if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
548 /* Go to the next buffer */
549 size_t i_ret = input_FillBuffer( p_input );
555 else if( i_ret < i_size )
566 *pp_data = input_ShareBuffer( p_input->p_method_data,
567 p_input->p_data_buffer );
569 (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
570 = p_input->p_current_data;
571 (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
573 p_input->p_current_data += i_size;
575 /* Update stream position */
576 vlc_mutex_lock( &p_input->stream.stream_lock );
577 p_input->stream.p_selected_area->i_tell += i_size;
578 vlc_mutex_unlock( &p_input->stream.stream_lock );
583 /*****************************************************************************
584 * input_AccessInit: initialize access plug-in wrapper structures
585 *****************************************************************************/
586 int input_AccessInit( input_thread_t * p_input )
588 p_input->p_method_data = input_BuffersInit( p_input );
589 if( p_input->p_method_data == NULL ) return -1;
590 p_input->p_data_buffer = NULL;
591 p_input->p_current_data = NULL;
592 p_input->p_last_data = NULL;
596 /*****************************************************************************
597 * input_AccessReinit: reinit structures after a random seek
598 *****************************************************************************/
599 void input_AccessReinit( input_thread_t * p_input )
601 if( p_input->p_data_buffer != NULL )
603 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
605 p_input->p_data_buffer = NULL;
606 p_input->p_current_data = NULL;
607 p_input->p_last_data = NULL;
610 /*****************************************************************************
611 * input_AccessEnd: free access plug-in wrapper structures
612 *****************************************************************************/
613 void input_AccessEnd( input_thread_t * p_input )
615 if( p_input->p_data_buffer != NULL )
617 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
620 input_BuffersEnd( p_input, p_input->p_method_data );