]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
* src/input/input_ext-plugins.c: forgot to re-lock a mutex.
[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.35 2003/07/27 15:49:27 gbazin 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                                          vlc_bool_t b_forced )
163 {
164     data_buffer_t * p_buf;
165
166     /* Safety check */
167     if( !b_forced && p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
168     {
169         return NULL;
170     }
171
172     if( p_buffers->buffers.p_stack != NULL )
173     {
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--;
178
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 )
181         {
182             p_buffers->i_allocated -= p_buf->i_size;
183             free( p_buf );
184             p_buf = malloc( sizeof(input_buffers_t) + i_size );
185             if( p_buf == NULL )
186             {
187                 return NULL;
188             }
189             p_buf->i_size = i_size;
190             p_buffers->i_allocated += i_size;
191         }
192     }
193     else
194     {
195         /* Allocate a new buffer */
196         p_buf = malloc( sizeof(input_buffers_t) + i_size );
197         if( p_buf == NULL )
198         {
199             return NULL;
200         }
201         p_buf->i_size = i_size;
202         p_buffers->i_allocated += i_size;
203     }
204
205     /* Initialize data */
206     p_buf->p_next = NULL;
207     p_buf->i_refcount = 0;
208
209     return p_buf;
210 }
211
212 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
213 {
214     data_buffer_t * p_buf;
215
216     vlc_mutex_lock( &p_buffers->lock );
217     p_buf = NewBuffer( p_buffers, i_size, VLC_FALSE );
218     vlc_mutex_unlock( &p_buffers->lock );
219
220     return p_buf;
221 }
222
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 )
228 {
229     /* Decrement refcount */
230     if( --p_buf->i_refcount > 0 )
231     {
232         return;
233     }
234
235     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
236     {
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++;
241     }
242     else
243     {
244         p_buffers->i_allocated -= p_buf->i_size;
245         free( p_buf );
246     }
247 }
248
249 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
250 {
251     vlc_mutex_lock( &p_buffers->lock );
252     ReleaseBuffer( p_buffers, p_buf );
253     vlc_mutex_unlock( &p_buffers->lock );
254 }
255
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 )
261 {
262     data_packet_t * p_data;
263
264     if( p_buffers->data.p_stack != NULL )
265     {
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--;
270     }
271     else
272     {
273         /* Allocate a new packet */
274         p_data = malloc( sizeof(data_packet_t) );
275         if( p_data == NULL )
276         {
277             return NULL;
278         }
279     }
280
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;
287     p_buf->i_refcount++;
288
289     return p_data;
290 }
291
292 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
293                                    data_buffer_t * p_buf )
294 {
295     data_packet_t * p_data;
296
297     vlc_mutex_lock( &p_buffers->lock );
298     p_data = ShareBuffer( p_buffers, p_buf );
299     vlc_mutex_unlock( &p_buffers->lock );
300
301     return p_data;
302 }
303
304 /*****************************************************************************
305  * input_NewPacket: allocate a packet along with a buffer
306  *****************************************************************************/
307 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
308                                          size_t i_size,
309                                          vlc_bool_t b_forced )
310 {
311     data_buffer_t * p_buf;
312     data_packet_t * p_data;
313
314     p_buf = NewBuffer( p_buffers, i_size, b_forced );
315
316     if( p_buf == NULL )
317     {
318         return NULL;
319     }
320
321     p_data = ShareBuffer( p_buffers, p_buf );
322     if( p_data == NULL )
323     {
324         ReleaseBuffer( p_buffers, p_buf );
325     }
326     return p_data;
327 }
328
329 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
330 {
331     data_packet_t * p_data;
332
333     vlc_mutex_lock( &p_buffers->lock );
334     p_data = NewPacket( p_buffers, i_size, VLC_FALSE );
335     vlc_mutex_unlock( &p_buffers->lock );
336
337     return p_data;
338 }
339
340 data_packet_t * input_NewPacketForce( input_buffers_t * p_buffers, size_t i_size )
341 {
342     data_packet_t * p_data;
343
344     vlc_mutex_lock( &p_buffers->lock );
345     p_data = NewPacket( p_buffers, i_size, VLC_TRUE);
346     vlc_mutex_unlock( &p_buffers->lock );
347
348     return p_data;
349 }
350
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 )
356 {
357     while( p_data != NULL )
358     {
359         data_packet_t * p_next = p_data->p_next;
360
361         ReleaseBuffer( p_buffers, p_data->p_buffer );
362
363         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
364         {
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++;
369         }
370         else
371         {
372             free( p_data );
373         }
374
375         p_data = p_next;
376     }
377 }
378
379 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
380 {
381     vlc_mutex_lock( &p_buffers->lock );
382     DeletePacket( p_buffers, p_data );
383     vlc_mutex_unlock( &p_buffers->lock );
384 }
385
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 )
390 {
391     pes_packet_t * p_pes;
392
393     if( p_buffers->pes.p_stack != NULL )
394     {
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--;
399     }
400     else
401     {
402         /* Allocate a new packet */
403         p_pes = malloc( sizeof(pes_packet_t) );
404         if( p_pes == NULL )
405         {
406             return NULL;
407         }
408     }
409
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;
416
417     return p_pes;
418 }
419
420 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
421 {
422     pes_packet_t * p_pes;
423
424     vlc_mutex_lock( &p_buffers->lock );
425     p_pes = NewPES( p_buffers );
426     vlc_mutex_unlock( &p_buffers->lock );
427
428     return p_pes;
429 }
430
431 /*****************************************************************************
432  * input_DeletePES: put a pes and all data packets and all buffers back into
433  *                  the cache
434  *****************************************************************************/
435 static inline void DeletePES( input_buffers_t * p_buffers,
436                               pes_packet_t * p_pes )
437 {
438     while( p_pes != NULL )
439     {
440         pes_packet_t * p_next = p_pes->p_next;
441
442         /* Delete all data packets */
443         if( p_pes->p_first != NULL )
444         {
445             DeletePacket( p_buffers, p_pes->p_first );
446         }
447
448         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
449         {
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++;
454         }
455         else
456         {
457             free( p_pes );
458         }
459
460         p_pes = p_next;
461     }
462 }
463
464 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
465 {
466     vlc_mutex_lock( &p_buffers->lock );
467     DeletePES( p_buffers, p_pes );
468     vlc_mutex_unlock( &p_buffers->lock );
469 }
470
471
472 /*
473  * Buffers management : external functions
474  *
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).
479  */
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 )
484 {
485     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
486     data_buffer_t * p_buf = NULL;
487     ssize_t i_ret;
488
489     vlc_mutex_lock( &p_input->p_method_data->lock );
490
491     while( p_buf == NULL )
492     {
493         p_buf = NewBuffer( p_input->p_method_data,
494                            i_remains + p_input->i_bufsize, VLC_FALSE );
495         if( p_buf == NULL )
496         {
497             vlc_mutex_unlock( &p_input->p_method_data->lock );
498             msg_Err( p_input,
499                      "failed allocating a new buffer (decoder stuck?)" );
500             msleep( INPUT_IDLE_SLEEP );
501
502             if( p_input->b_die || p_input->b_error || p_input->b_eof )
503             {
504                 return -1;
505             }
506             vlc_mutex_lock( &p_input->p_method_data->lock );
507         }
508     }
509
510     p_buf->i_refcount = 1;
511
512     if( p_input->p_data_buffer != NULL )
513     {
514         if( i_remains )
515         {
516             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
517                                        p_input->p_current_data,
518                                        (size_t)i_remains );
519         }
520         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
521     }
522
523     /* Do not hold the lock during pf_read (blocking call). */
524     vlc_mutex_unlock( &p_input->p_method_data->lock );
525
526     i_ret = p_input->pf_read( p_input,
527                               (byte_t *)p_buf + sizeof(data_buffer_t)
528                                + i_remains,
529                               p_input->i_bufsize );
530     if( i_ret < 0 && i_remains == 0 )
531     {
532         /* Our internal buffers are empty, we can signal the error */
533         return -1;
534     }
535
536     if( i_ret < 0 ) i_ret = 0;
537
538     p_input->p_data_buffer = p_buf;
539     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
540     p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
541
542     return (ssize_t)i_remains + i_ret;
543 }
544
545 /*****************************************************************************
546  * input_Peek: give a pointer to the next available bytes in the buffer
547  *             (min. i_size bytes)
548  * Returns the number of bytes read, or -1 in case of error
549  *****************************************************************************/
550 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
551 {
552     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
553     {
554         /* Go to the next buffer */
555         ssize_t i_ret = input_FillBuffer( p_input );
556
557         if( i_ret < 0 )
558         {
559             return -1;
560         }
561
562         if( i_ret < (ssize_t)i_size )
563         {
564             i_size = i_ret;
565         }
566     }
567     *pp_byte = p_input->p_current_data;
568     return i_size;
569 }
570
571 /*****************************************************************************
572  * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
573  * Returns the number of bytes read, or -1 in case of error
574  *****************************************************************************/
575 ssize_t input_SplitBuffer( input_thread_t * p_input,
576                            data_packet_t ** pp_data, size_t i_size )
577 {
578     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
579     {
580         /* Go to the next buffer */
581         ssize_t i_ret = input_FillBuffer( p_input );
582
583         if( i_ret < 0 )
584         {
585             return -1;
586         }
587
588         if( i_ret < (ssize_t)i_size )
589         {
590             i_size = i_ret;
591         }
592     }
593
594     if ( !i_size )
595     {
596         return 0;
597     }
598
599     *pp_data = input_ShareBuffer( p_input->p_method_data,
600                                   p_input->p_data_buffer );
601
602     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
603         = p_input->p_current_data;
604     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
605
606     p_input->p_current_data += i_size;
607
608     /* Update stream position */
609     vlc_mutex_lock( &p_input->stream.stream_lock );
610     p_input->stream.p_selected_area->i_tell += i_size;
611     vlc_mutex_unlock( &p_input->stream.stream_lock );
612  
613     return i_size;
614 }
615
616 /*****************************************************************************
617  * input_AccessInit: initialize access plug-in wrapper structures
618  *****************************************************************************/
619 int input_AccessInit( input_thread_t * p_input )
620 {
621     p_input->p_method_data = input_BuffersInit( p_input );
622     if( p_input->p_method_data == NULL ) return -1;
623     p_input->p_data_buffer = NULL;
624     p_input->p_current_data = NULL;
625     p_input->p_last_data = NULL;
626     return 0;
627 }
628
629 /*****************************************************************************
630  * input_AccessReinit: reinit structures before a random seek
631  *****************************************************************************/
632 void input_AccessReinit( input_thread_t * p_input )
633 {
634     if( p_input->p_data_buffer != NULL )
635     {
636         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
637     }
638     p_input->p_data_buffer = NULL;
639     p_input->p_current_data = NULL;
640     p_input->p_last_data = NULL;
641 }
642
643 /*****************************************************************************
644  * input_AccessEnd: free access plug-in wrapper structures
645  *****************************************************************************/
646 void input_AccessEnd( input_thread_t * p_input )
647 {
648     if( p_input->p_data_buffer != NULL )
649     {
650         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
651     }
652
653     input_BuffersEnd( p_input, p_input->p_method_data );
654 }
655