]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
* ./bootstrap: bootstrap now requires the --config flag. With no arguments
[vlc] / src / input / input_ext-plugins.c
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 $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31
32 #include "stream_control.h"
33 #include "input_ext-intf.h"
34 #include "input_ext-dec.h"
35 #include "input_ext-plugins.h"
36
37
38 /*
39  * Buffers management : internal functions
40  *
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.
44  */
45
46 #define BUFFERS_CACHE_SIZE 500
47 #define DATA_CACHE_SIZE 1000
48 #define PES_CACHE_SIZE 1000
49
50 /*****************************************************************************
51  * data_buffer_t: shared data type
52  *****************************************************************************/
53 struct data_buffer_t
54 {
55     data_buffer_t * p_next;
56
57     /* number of data packets this buffer is referenced from - when it falls
58      * down to 0, the buffer is freed */
59     int i_refcount;
60
61     /* size of the current buffer (starting right after this byte) */
62     size_t i_size;
63 };
64
65 /*****************************************************************************
66  * input_buffers_t: defines a LIFO per data type to keep
67  *****************************************************************************/
68 #define PACKETS_LIFO( TYPE, NAME )                                          \
69 struct                                                                      \
70 {                                                                           \
71     TYPE * p_stack;                                                         \
72     unsigned int i_depth;                                                   \
73 } NAME;
74
75 struct input_buffers_t
76 {
77     vlc_mutex_t lock;
78     PACKETS_LIFO( pes_packet_t, pes )
79     PACKETS_LIFO( data_packet_t, data )
80     PACKETS_LIFO( data_buffer_t, buffers )
81     size_t i_allocated;
82 };
83
84
85 /*****************************************************************************
86  * input_BuffersInit: initialize the cache structures, return a pointer to it
87  *****************************************************************************/
88 void * __input_BuffersInit( vlc_object_t *p_this )
89 {
90     input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
91
92     if( p_buffers == NULL )
93     {
94         return NULL;
95     }
96
97     memset( p_buffers, 0, sizeof( input_buffers_t ) );
98     vlc_mutex_init( p_this, &p_buffers->lock );
99
100     return p_buffers;
101 }
102
103 /*****************************************************************************
104  * input_BuffersEnd: free all cached structures
105  *****************************************************************************/
106 #define BUFFERS_END_PACKETS_LOOP                                            \
107     while( p_packet != NULL )                                               \
108     {                                                                       \
109         p_next = p_packet->p_next;                                          \
110         free( p_packet );                                                   \
111         p_packet = p_next;                                                  \
112     }
113
114 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
115 {
116     if( p_buffers != NULL )
117     {
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 );
121
122         {
123             /* Free PES */
124             pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
125             BUFFERS_END_PACKETS_LOOP;
126         }
127
128         {
129             /* Free data packets */
130             data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
131             BUFFERS_END_PACKETS_LOOP;
132         }
133
134         {
135             /* Free buffers */
136             data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
137             while( p_buf != NULL )
138             {
139                 p_next = p_buf->p_next;
140                 p_buffers->i_allocated -= p_buf->i_size;
141                 free( p_buf );
142                 p_buf = p_next;
143             }
144         } 
145
146         if( p_buffers->i_allocated )
147         {
148             msg_Err( p_input, "%d bytes have not been freed, "
149                               "expect memory leak", p_buffers->i_allocated );
150         }
151
152         vlc_mutex_destroy( &p_buffers->lock );
153         free( p_buffers );
154     }
155 }
156
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,
161                                          size_t i_size )
162 {
163     data_buffer_t * p_buf;
164
165     /* Safety check */
166     if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
167     {
168         return NULL;
169     } 
170
171     if( p_buffers->buffers.p_stack != NULL )
172     {
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--;
177
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 )
180         {
181             p_buffers->i_allocated -= p_buf->i_size;
182             free( p_buf );
183             p_buf = malloc( sizeof(input_buffers_t) + i_size );
184             if( p_buf == NULL )
185             {
186                 return NULL;
187             }
188             p_buf->i_size = i_size;
189             p_buffers->i_allocated += i_size;
190         }
191     }
192     else
193     {
194         /* Allocate a new buffer */
195         p_buf = malloc( sizeof(input_buffers_t) + i_size );
196         if( p_buf == NULL )
197         {
198             return NULL;
199         }
200         p_buf->i_size = i_size;
201         p_buffers->i_allocated += i_size;
202     }
203
204     /* Initialize data */
205     p_buf->p_next = NULL;
206     p_buf->i_refcount = 0;
207
208     return p_buf;
209 }
210
211 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
212 {
213     data_buffer_t * p_buf;
214
215     vlc_mutex_lock( &p_buffers->lock );
216     p_buf = NewBuffer( p_buffers, i_size );
217     vlc_mutex_unlock( &p_buffers->lock );
218
219     return p_buf;
220 }
221
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 )
227 {
228     /* Decrement refcount */
229     if( --p_buf->i_refcount > 0 )
230     {
231         return;
232     }
233
234     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
235     {
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++;
240     }
241     else
242     {
243         p_buffers->i_allocated -= p_buf->i_size;
244         free( p_buf );
245     }
246 }
247
248 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
249 {
250     vlc_mutex_lock( &p_buffers->lock );
251     ReleaseBuffer( p_buffers, p_buf );
252     vlc_mutex_unlock( &p_buffers->lock );
253 }
254
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 )
260 {
261     data_packet_t * p_data;
262
263     if( p_buffers->data.p_stack != NULL )
264     {
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--;
269     }
270     else
271     {
272         /* Allocate a new packet */
273         p_data = malloc( sizeof(data_packet_t) );
274         if( p_data == NULL )
275         {
276             return NULL;
277         }
278     }
279
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;
286     p_buf->i_refcount++;
287
288     return p_data;
289 }
290
291 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
292                                    data_buffer_t * p_buf )
293 {
294     data_packet_t * p_data;
295
296     vlc_mutex_lock( &p_buffers->lock );
297     p_data = ShareBuffer( p_buffers, p_buf );
298     vlc_mutex_unlock( &p_buffers->lock );
299
300     return p_data;
301 }
302
303 /*****************************************************************************
304  * input_NewPacket: allocate a packet along with a buffer
305  *****************************************************************************/
306 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
307                                          size_t i_size )
308 {
309     data_buffer_t * p_buf;
310     data_packet_t * p_data;
311
312     p_buf = NewBuffer( p_buffers, i_size );
313
314     if( p_buf == NULL )
315     {
316         return NULL;
317     }
318
319     p_data = ShareBuffer( p_buffers, p_buf );
320     if( p_data == NULL )
321     {
322         ReleaseBuffer( p_buffers, p_buf );
323     }
324     return p_data;
325 }
326
327 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
328 {
329     data_packet_t * p_data;
330
331     vlc_mutex_lock( &p_buffers->lock );
332     p_data = NewPacket( p_buffers, i_size );
333     vlc_mutex_unlock( &p_buffers->lock );
334
335     return p_data;
336 }
337
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 )
343 {
344     while( p_data != NULL )
345     {
346         data_packet_t * p_next = p_data->p_next;
347
348         ReleaseBuffer( p_buffers, p_data->p_buffer );
349
350         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
351         {
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++;
356         }
357         else
358         {
359             free( p_data );
360         }
361
362         p_data = p_next;
363     }
364 }
365
366 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
367 {
368     vlc_mutex_lock( &p_buffers->lock );
369     DeletePacket( p_buffers, p_data );
370     vlc_mutex_unlock( &p_buffers->lock );
371 }
372
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 )
377 {
378     pes_packet_t * p_pes;
379
380     if( p_buffers->pes.p_stack != NULL )
381     {
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--;
386     }
387     else
388     {
389         /* Allocate a new packet */
390         p_pes = malloc( sizeof(pes_packet_t) );
391         if( p_pes == NULL )
392         {
393             return NULL;
394         }
395     }
396
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;
403
404     return p_pes;
405 }
406
407 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
408 {
409     pes_packet_t * p_pes;
410
411     vlc_mutex_lock( &p_buffers->lock );
412     p_pes = NewPES( p_buffers );
413     vlc_mutex_unlock( &p_buffers->lock );
414
415     return p_pes;
416 }
417
418 /*****************************************************************************
419  * input_DeletePES: put a pes and all data packets and all buffers back into
420  *                  the cache
421  *****************************************************************************/
422 static inline void DeletePES( input_buffers_t * p_buffers,
423                               pes_packet_t * p_pes )
424 {
425     while( p_pes != NULL )
426     {
427         pes_packet_t * p_next = p_pes->p_next;
428
429         /* Delete all data packets */
430         if( p_pes->p_first != NULL )
431         {
432             DeletePacket( p_buffers, p_pes->p_first );
433         }
434
435         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
436         {
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++;
441         }
442         else
443         {
444             free( p_pes );
445         }
446
447         p_pes = p_next;
448     }
449 }
450
451 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
452 {
453     vlc_mutex_lock( &p_buffers->lock );
454     DeletePES( p_buffers, p_pes );
455     vlc_mutex_unlock( &p_buffers->lock );
456 }
457
458
459 /*
460  * Buffers management : external functions
461  *
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).
466  */
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 )
471 {
472     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
473     data_buffer_t * p_buf;
474     ssize_t i_ret;
475
476     vlc_mutex_lock( &p_input->p_method_data->lock );
477
478     p_buf = NewBuffer( p_input->p_method_data,
479                        i_remains + p_input->i_bufsize );
480     if( p_buf == NULL )
481     {
482         msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
483         return -1;
484     }
485     p_buf->i_refcount = 1;
486
487     if( p_input->p_data_buffer != NULL )
488     {
489         if( i_remains )
490         {
491             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
492                                        p_input->p_current_data,
493                                        (size_t)i_remains );
494         }
495         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
496     }
497
498     /* Do not hold the lock during pf_read (blocking call). */
499     vlc_mutex_unlock( &p_input->p_method_data->lock );
500
501     i_ret = p_input->pf_read( p_input,
502                               (byte_t *)p_buf + sizeof(data_buffer_t)
503                                + i_remains,
504                               p_input->i_bufsize );
505     if( i_ret < 0 ) i_ret = 0;
506
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;
510
511     return (ssize_t)i_remains + i_ret;
512 }
513
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 )
520 {
521     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
522     {
523         /* Go to the next buffer */
524         size_t i_ret = input_FillBuffer( p_input );
525
526         if( i_size == -1 )
527         {
528             return -1;
529         }
530         else if( i_ret < i_size )
531         {
532             i_size = i_ret;
533         }
534     }
535     *pp_byte = p_input->p_current_data;
536     return i_size;
537 }
538
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 )
545 {
546     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
547     {
548         /* Go to the next buffer */
549         size_t i_ret = input_FillBuffer( p_input );
550
551         if( i_ret == -1 )
552         {
553             return -1;
554         }
555         else if( i_ret < i_size )
556         {
557             i_size = i_ret;
558         }
559     }
560
561     if ( !i_size )
562     {
563         return 0;
564     }
565
566     *pp_data = input_ShareBuffer( p_input->p_method_data,
567                                   p_input->p_data_buffer );
568
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;
572
573     p_input->p_current_data += i_size;
574
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 );
579  
580     return i_size;
581 }
582
583 /*****************************************************************************
584  * input_AccessInit: initialize access plug-in wrapper structures
585  *****************************************************************************/
586 int input_AccessInit( input_thread_t * p_input )
587 {
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;
593     return 0;
594 }
595
596 /*****************************************************************************
597  * input_AccessReinit: reinit structures after a random seek
598  *****************************************************************************/
599 void input_AccessReinit( input_thread_t * p_input )
600 {
601     if( p_input->p_data_buffer != NULL )
602     {
603         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
604     }
605     p_input->p_data_buffer = NULL;
606     p_input->p_current_data = NULL;
607     p_input->p_last_data = NULL;
608 }
609
610 /*****************************************************************************
611  * input_AccessEnd: free access plug-in wrapper structures
612  *****************************************************************************/
613 void input_AccessEnd( input_thread_t * p_input )
614 {
615     if( p_input->p_data_buffer != NULL )
616     {
617         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
618     }
619
620     input_BuffersEnd( p_input, p_input->p_method_data );
621 }
622