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.32 2003/05/27 22:42:58 hartman 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_Warn( p_input, "%u 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,
162 vlc_bool_t b_forced )
164 data_buffer_t * p_buf;
167 if( !b_forced && p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
172 if( p_buffers->buffers.p_stack != NULL )
174 /* Take the buffer from the cache */
175 p_buf = p_buffers->buffers.p_stack;
176 p_buffers->buffers.p_stack = p_buf->p_next;
177 p_buffers->buffers.i_depth--;
179 /* Reallocate the packet if it is too small or too large */
180 if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
182 p_buffers->i_allocated -= p_buf->i_size;
184 p_buf = malloc( sizeof(input_buffers_t) + i_size );
189 p_buf->i_size = i_size;
190 p_buffers->i_allocated += i_size;
195 /* Allocate a new buffer */
196 p_buf = malloc( sizeof(input_buffers_t) + i_size );
201 p_buf->i_size = i_size;
202 p_buffers->i_allocated += i_size;
205 /* Initialize data */
206 p_buf->p_next = NULL;
207 p_buf->i_refcount = 0;
212 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
214 data_buffer_t * p_buf;
216 vlc_mutex_lock( &p_buffers->lock );
217 p_buf = NewBuffer( p_buffers, i_size, VLC_FALSE );
218 vlc_mutex_unlock( &p_buffers->lock );
223 /*****************************************************************************
224 * input_ReleaseBuffer: put a buffer back into the cache
225 *****************************************************************************/
226 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
227 data_buffer_t * p_buf )
229 /* Decrement refcount */
230 if( --p_buf->i_refcount > 0 )
235 if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
237 /* Cache not full : store the buffer in it */
238 p_buf->p_next = p_buffers->buffers.p_stack;
239 p_buffers->buffers.p_stack = p_buf;
240 p_buffers->buffers.i_depth++;
244 p_buffers->i_allocated -= p_buf->i_size;
249 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
251 vlc_mutex_lock( &p_buffers->lock );
252 ReleaseBuffer( p_buffers, p_buf );
253 vlc_mutex_unlock( &p_buffers->lock );
256 /*****************************************************************************
257 * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
258 *****************************************************************************/
259 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
260 data_buffer_t * p_buf )
262 data_packet_t * p_data;
264 if( p_buffers->data.p_stack != NULL )
266 /* Take the packet from the cache */
267 p_data = p_buffers->data.p_stack;
268 p_buffers->data.p_stack = p_data->p_next;
269 p_buffers->data.i_depth--;
273 /* Allocate a new packet */
274 p_data = malloc( sizeof(data_packet_t) );
281 p_data->p_buffer = p_buf;
282 p_data->p_next = NULL;
283 p_data->b_discard_payload = 0;
284 p_data->p_payload_start = p_data->p_demux_start
285 = (byte_t *)p_buf + sizeof(input_buffers_t);
286 p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
292 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
293 data_buffer_t * p_buf )
295 data_packet_t * p_data;
297 vlc_mutex_lock( &p_buffers->lock );
298 p_data = ShareBuffer( p_buffers, p_buf );
299 vlc_mutex_unlock( &p_buffers->lock );
304 /*****************************************************************************
305 * input_NewPacket: allocate a packet along with a buffer
306 *****************************************************************************/
307 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
309 vlc_bool_t b_forced )
311 data_buffer_t * p_buf;
312 data_packet_t * p_data;
314 p_buf = NewBuffer( p_buffers, i_size, b_forced );
321 p_data = ShareBuffer( p_buffers, p_buf );
324 ReleaseBuffer( p_buffers, p_buf );
329 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
331 data_packet_t * p_data;
333 vlc_mutex_lock( &p_buffers->lock );
334 p_data = NewPacket( p_buffers, i_size, VLC_FALSE );
335 vlc_mutex_unlock( &p_buffers->lock );
340 data_packet_t * input_NewPacketForce( input_buffers_t * p_buffers, size_t i_size )
342 data_packet_t * p_data;
344 vlc_mutex_lock( &p_buffers->lock );
345 p_data = NewPacket( p_buffers, i_size, VLC_TRUE);
346 vlc_mutex_unlock( &p_buffers->lock );
351 /*****************************************************************************
352 * input_DeletePacket: deallocate a packet and its buffers
353 *****************************************************************************/
354 static inline void DeletePacket( input_buffers_t * p_buffers,
355 data_packet_t * p_data )
357 while( p_data != NULL )
359 data_packet_t * p_next = p_data->p_next;
361 ReleaseBuffer( p_buffers, p_data->p_buffer );
363 if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
365 /* Cache not full : store the packet in it */
366 p_data->p_next = p_buffers->data.p_stack;
367 p_buffers->data.p_stack = p_data;
368 p_buffers->data.i_depth++;
379 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
381 vlc_mutex_lock( &p_buffers->lock );
382 DeletePacket( p_buffers, p_data );
383 vlc_mutex_unlock( &p_buffers->lock );
386 /*****************************************************************************
387 * input_NewPES: return a pointer to a new PES packet
388 *****************************************************************************/
389 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
391 pes_packet_t * p_pes;
393 if( p_buffers->pes.p_stack != NULL )
395 /* Take the packet from the cache */
396 p_pes = p_buffers->pes.p_stack;
397 p_buffers->pes.p_stack = p_pes->p_next;
398 p_buffers->pes.i_depth--;
402 /* Allocate a new packet */
403 p_pes = malloc( sizeof(pes_packet_t) );
410 p_pes->p_next = NULL;
411 p_pes->b_data_alignment = p_pes->b_discontinuity = VLC_FALSE;
412 p_pes->i_pts = p_pes->i_dts = 0;
413 p_pes->p_first = p_pes->p_last = NULL;
414 p_pes->i_pes_size = 0;
415 p_pes->i_nb_data = 0;
420 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
422 pes_packet_t * p_pes;
424 vlc_mutex_lock( &p_buffers->lock );
425 p_pes = NewPES( p_buffers );
426 vlc_mutex_unlock( &p_buffers->lock );
431 /*****************************************************************************
432 * input_DeletePES: put a pes and all data packets and all buffers back into
434 *****************************************************************************/
435 static inline void DeletePES( input_buffers_t * p_buffers,
436 pes_packet_t * p_pes )
438 while( p_pes != NULL )
440 pes_packet_t * p_next = p_pes->p_next;
442 /* Delete all data packets */
443 if( p_pes->p_first != NULL )
445 DeletePacket( p_buffers, p_pes->p_first );
448 if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
450 /* Cache not full : store the packet in it */
451 p_pes->p_next = p_buffers->pes.p_stack;
452 p_buffers->pes.p_stack = p_pes;
453 p_buffers->pes.i_depth++;
464 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
466 vlc_mutex_lock( &p_buffers->lock );
467 DeletePES( p_buffers, p_pes );
468 vlc_mutex_unlock( &p_buffers->lock );
473 * Buffers management : external functions
475 * These functions make the glu between the access plug-in (pf_read) and
476 * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
477 * with a call to pf_read, then allow the demux plug-in to have a peep at
478 * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
480 /*****************************************************************************
481 * input_FillBuffer: fill in p_data_buffer with data from pf_read
482 *****************************************************************************/
483 ssize_t input_FillBuffer( input_thread_t * p_input )
485 ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
486 data_buffer_t * p_buf;
489 vlc_mutex_lock( &p_input->p_method_data->lock );
491 p_buf = NewBuffer( p_input->p_method_data,
492 i_remains + p_input->i_bufsize, VLC_FALSE );
495 vlc_mutex_unlock( &p_input->p_method_data->lock );
496 msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
497 msleep( INPUT_IDLE_SLEEP );
500 p_buf->i_refcount = 1;
502 if( p_input->p_data_buffer != NULL )
506 p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
507 p_input->p_current_data,
510 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
513 /* Do not hold the lock during pf_read (blocking call). */
514 vlc_mutex_unlock( &p_input->p_method_data->lock );
516 i_ret = p_input->pf_read( p_input,
517 (byte_t *)p_buf + sizeof(data_buffer_t)
519 p_input->i_bufsize );
520 if( i_ret < 0 && i_remains == 0 )
522 /* Our internal buffers are empty, we can signal the error */
526 if( i_ret < 0 ) i_ret = 0;
528 p_input->p_data_buffer = p_buf;
529 p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
530 p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
532 return (ssize_t)i_remains + i_ret;
535 /*****************************************************************************
536 * input_Peek: give a pointer to the next available bytes in the buffer
537 * (min. i_size bytes)
538 * Returns the number of bytes read, or -1 in case of error
539 *****************************************************************************/
540 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
542 if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
544 /* Go to the next buffer */
545 ssize_t i_ret = input_FillBuffer( p_input );
552 if( i_ret < (ssize_t)i_size )
557 *pp_byte = p_input->p_current_data;
561 /*****************************************************************************
562 * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
563 * Returns the number of bytes read, or -1 in case of error
564 *****************************************************************************/
565 ssize_t input_SplitBuffer( input_thread_t * p_input,
566 data_packet_t ** pp_data, size_t i_size )
568 if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
570 /* Go to the next buffer */
571 ssize_t i_ret = input_FillBuffer( p_input );
578 if( i_ret < (ssize_t)i_size )
589 *pp_data = input_ShareBuffer( p_input->p_method_data,
590 p_input->p_data_buffer );
592 (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
593 = p_input->p_current_data;
594 (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
596 p_input->p_current_data += i_size;
598 /* Update stream position */
599 vlc_mutex_lock( &p_input->stream.stream_lock );
600 p_input->stream.p_selected_area->i_tell += i_size;
601 vlc_mutex_unlock( &p_input->stream.stream_lock );
606 /*****************************************************************************
607 * input_AccessInit: initialize access plug-in wrapper structures
608 *****************************************************************************/
609 int input_AccessInit( input_thread_t * p_input )
611 p_input->p_method_data = input_BuffersInit( p_input );
612 if( p_input->p_method_data == NULL ) return -1;
613 p_input->p_data_buffer = NULL;
614 p_input->p_current_data = NULL;
615 p_input->p_last_data = NULL;
619 /*****************************************************************************
620 * input_AccessReinit: reinit structures before a random seek
621 *****************************************************************************/
622 void input_AccessReinit( input_thread_t * p_input )
624 if( p_input->p_data_buffer != NULL )
626 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
628 p_input->p_data_buffer = NULL;
629 p_input->p_current_data = NULL;
630 p_input->p_last_data = NULL;
633 /*****************************************************************************
634 * input_AccessEnd: free access plug-in wrapper structures
635 *****************************************************************************/
636 void input_AccessEnd( input_thread_t * p_input )
638 if( p_input->p_data_buffer != NULL )
640 ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
643 input_BuffersEnd( p_input, p_input->p_method_data );