]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
* modules/packetizer/mpeg4audio.c, modules/packetizer/mpegvideo.c: compilation fix.
[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-2004 VideoLAN
5  * $Id: input_ext-plugins.c,v 1.40 2004/01/25 17:16:06 zorglub 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_Warn( p_input, "%u 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 = NULL;
474     ssize_t i_ret;
475
476     vlc_mutex_lock( &p_input->p_method_data->lock );
477
478     while( p_buf == NULL )
479     {
480         p_buf = NewBuffer( p_input->p_method_data,
481                            i_remains + p_input->i_bufsize );
482         if( p_buf == NULL )
483         {
484             vlc_mutex_unlock( &p_input->p_method_data->lock );
485             msg_Err( p_input,
486                      "failed allocating a new buffer (decoder stuck?)" );
487             msleep( INPUT_IDLE_SLEEP );
488
489             if( p_input->b_die || p_input->b_error || p_input->b_eof )
490             {
491                 return -1;
492             }
493             vlc_mutex_lock( &p_input->p_method_data->lock );
494         }
495     }
496
497     p_buf->i_refcount = 1;
498
499     if( p_input->p_data_buffer != NULL )
500     {
501         if( i_remains )
502         {
503             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
504                                        p_input->p_current_data,
505                                        (size_t)i_remains );
506         }
507         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
508     }
509
510     p_input->p_data_buffer = p_buf;
511     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
512     p_input->p_last_data = p_input->p_current_data + i_remains;
513
514     /* Do not hold the lock during pf_read (blocking call). */
515     vlc_mutex_unlock( &p_input->p_method_data->lock );
516
517     i_ret = p_input->pf_read( p_input,
518                               (byte_t *)p_buf + sizeof(data_buffer_t)
519                                + i_remains,
520                               p_input->i_bufsize );
521     if( i_ret < 0 && i_remains == 0 )
522     {
523         /* Our internal buffers are empty, we can signal the error */
524         return -1;
525     }
526
527     if( i_ret < 0 ) i_ret = 0;
528
529     p_input->p_last_data += i_ret;
530
531     return (ssize_t)i_remains + i_ret;
532 }
533
534 /*****************************************************************************
535  * input_Peek: give a pointer to the next available bytes in the buffer
536  *             (min. i_size bytes)
537  * Returns the number of bytes read, or -1 in case of error
538  *****************************************************************************/
539 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
540 {
541     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
542     {
543         /* Go to the next buffer */
544         ssize_t i_ret = input_FillBuffer( p_input );
545
546         if( i_ret < 0 )
547         {
548             return -1;
549         }
550
551         if( i_ret < (ssize_t)i_size )
552         {
553             i_size = i_ret;
554         }
555     }
556     *pp_byte = p_input->p_current_data;
557     return i_size;
558 }
559
560 /*****************************************************************************
561  * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
562  * Returns the number of bytes read, or -1 in case of error
563  *****************************************************************************/
564 ssize_t input_SplitBuffer( input_thread_t * p_input,
565                            data_packet_t ** pp_data, size_t i_size )
566 {
567     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
568     {
569         /* Go to the next buffer */
570         ssize_t i_ret = input_FillBuffer( p_input );
571
572         if( i_ret < 0 )
573         {
574             return -1;
575         }
576
577         if( i_ret < (ssize_t)i_size )
578         {
579             i_size = i_ret;
580         }
581     }
582
583     if ( i_size < 0)
584     {
585         return 0;
586     }
587
588     *pp_data = input_ShareBuffer( p_input->p_method_data,
589                                   p_input->p_data_buffer );
590
591     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
592         = p_input->p_current_data;
593     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
594
595     p_input->p_current_data += i_size;
596
597     /* Update stream position */
598     vlc_mutex_lock( &p_input->stream.stream_lock );
599     p_input->stream.p_selected_area->i_tell += i_size;
600     vlc_mutex_unlock( &p_input->stream.stream_lock );
601
602     return i_size;
603 }
604
605 /*****************************************************************************
606  * input_AccessInit: initialize access plug-in wrapper structures
607  *****************************************************************************/
608 int input_AccessInit( input_thread_t * p_input )
609 {
610     p_input->p_method_data = input_BuffersInit( p_input );
611     if( p_input->p_method_data == NULL ) return -1;
612     p_input->p_data_buffer = NULL;
613     p_input->p_current_data = NULL;
614     p_input->p_last_data = NULL;
615     return 0;
616 }
617
618 /*****************************************************************************
619  * input_AccessReinit: reinit structures before a random seek
620  *****************************************************************************/
621 void input_AccessReinit( input_thread_t * p_input )
622 {
623     if( p_input->p_data_buffer != NULL )
624     {
625         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
626     }
627     p_input->p_data_buffer = NULL;
628     p_input->p_current_data = NULL;
629     p_input->p_last_data = NULL;
630 }
631
632 /*****************************************************************************
633  * input_AccessEnd: free access plug-in wrapper structures
634  *****************************************************************************/
635 void input_AccessEnd( input_thread_t * p_input )
636 {
637     if( p_input->p_data_buffer != NULL )
638     {
639         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
640     }
641
642     input_BuffersEnd( p_input, p_input->p_method_data );
643 }
644