]> git.sesse.net Git - vlc/blob - src/input/input_dec.c
e9c4c1fb6f57fedc22bdb9e8066f563a1b402c7a
[vlc] / src / input / input_dec.c
1 /*****************************************************************************
2  * input_dec.c: Functions for the management of decoders
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: input_dec.c,v 1.51 2002/11/11 14:39:12 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>                                    /* memcpy(), memset() */
29
30 #include <vlc/vlc.h>
31
32 #include "stream_control.h"
33 #include "input_ext-dec.h"
34 #include "input_ext-intf.h"
35 #include "input_ext-plugins.h"
36
37 static decoder_fifo_t * CreateDecoderFifo( input_thread_t *,
38                                            es_descriptor_t * );
39 static void             DeleteDecoderFifo( decoder_fifo_t * );
40
41 /*****************************************************************************
42  * input_RunDecoder: spawns a new decoder thread
43  *****************************************************************************/
44 decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
45                                    es_descriptor_t * p_es )
46 {
47     decoder_fifo_t *p_fifo;
48     int i_priority;
49
50     /* Create the decoder configuration structure */
51     p_fifo = CreateDecoderFifo( p_input, p_es );
52
53     if( p_fifo == NULL )
54     {
55         msg_Err( p_input, "could not create decoder fifo" );
56         return NULL;
57     }
58
59     /* Get a suitable module */
60     p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
61     if( p_fifo->p_module == NULL )
62     {
63         msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'",
64                        (char*)&p_fifo->i_fourcc );
65         DeleteDecoderFifo( p_fifo );
66         vlc_object_destroy( p_fifo );
67         return NULL;
68     }
69
70     if ( p_es->i_cat == AUDIO_ES )
71     {
72         i_priority = VLC_THREAD_PRIORITY_AUDIO;
73     }
74     else
75     {
76         i_priority = VLC_THREAD_PRIORITY_VIDEO;
77     }
78
79     /* Spawn the decoder thread */
80     if( vlc_thread_create( p_fifo, "decoder", p_fifo->pf_run,
81                            i_priority, VLC_FALSE ) )
82     {
83         msg_Err( p_fifo, "cannot spawn decoder thread \"%s\"",
84                          p_fifo->p_module->psz_object_name );
85         module_Unneed( p_fifo, p_fifo->p_module );
86         return NULL;
87     }
88
89     p_input->stream.b_changed = 1;
90
91     return p_fifo;
92 }
93
94
95 /*****************************************************************************
96  * input_EndDecoder: kills a decoder thread and waits until it's finished
97  *****************************************************************************/
98 void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
99 {
100     int i_dummy;
101
102     p_es->p_decoder_fifo->b_die = 1;
103
104     /* Make sure the thread leaves the NextDataPacket() function by
105      * sending it a few null packets. */
106     for( i_dummy = 0; i_dummy < PADDING_PACKET_NUMBER; i_dummy++ )
107     {
108         input_NullPacket( p_input, p_es );
109     }
110
111     if( p_es->p_pes != NULL )
112     {
113         input_DecodePES( p_es->p_decoder_fifo, p_es->p_pes );
114     }
115
116     /* Waiting for the thread to exit */
117     /* I thought that unlocking was better since thread join can be long
118      * but it actually creates late pictures and freezes --stef */
119     /* vlc_mutex_unlock( &p_input->stream.stream_lock ); */
120     vlc_thread_join( p_es->p_decoder_fifo );
121     /* vlc_mutex_lock( &p_input->stream.stream_lock ); */
122
123     /* Delete decoder configuration */
124     DeleteDecoderFifo( p_es->p_decoder_fifo );
125
126     /* Unneed module */
127     module_Unneed( p_es->p_decoder_fifo, p_es->p_decoder_fifo->p_module );
128
129     /* Delete the fifo */
130     vlc_object_destroy( p_es->p_decoder_fifo );
131
132     /* Tell the input there is no more decoder */
133     p_es->p_decoder_fifo = NULL;
134
135     p_input->stream.b_changed = 1;
136 }
137
138 /*****************************************************************************
139  * input_DecodePES
140  *****************************************************************************
141  * Put a PES in the decoder's fifo.
142  *****************************************************************************/
143 void input_DecodePES( decoder_fifo_t * p_decoder_fifo, pes_packet_t * p_pes )
144 {
145     vlc_mutex_lock( &p_decoder_fifo->data_lock );
146
147     p_pes->p_next = NULL;
148     *p_decoder_fifo->pp_last = p_pes;
149     p_decoder_fifo->pp_last = &p_pes->p_next;
150     p_decoder_fifo->i_depth++;
151
152     /* Warn the decoder that it's got work to do. */
153     vlc_cond_signal( &p_decoder_fifo->data_wait );
154     vlc_mutex_unlock( &p_decoder_fifo->data_lock );
155 }
156
157 /****************************************************************************
158  * input_ExtractPES
159  *****************************************************************************
160  * Extract a PES from the fifo. If pp_pes is NULL then the PES is just
161  * deleted, otherwise *pp_pes will point to this PES.
162  ****************************************************************************/
163 void input_ExtractPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
164 {
165     pes_packet_t *p_pes;
166
167     vlc_mutex_lock( &p_fifo->data_lock );
168
169     if( p_fifo->p_first == NULL )
170     {
171         if( p_fifo->b_die )
172         {
173             vlc_mutex_unlock( &p_fifo->data_lock );
174             if( pp_pes ) *pp_pes = NULL;
175             return;
176         }
177
178         /* Signal the input thread we're waiting. This is only
179          * needed in case of slave clock (ES plug-in) but it won't
180          * harm. */
181         vlc_cond_signal( &p_fifo->data_wait );
182
183         /* Wait for the input to tell us when we received a packet. */
184         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
185     }
186
187     p_pes = p_fifo->p_first;
188     p_fifo->p_first = p_pes->p_next;
189     p_pes->p_next = NULL;
190     p_fifo->i_depth--;
191
192     if( !p_fifo->p_first )
193     {
194         /* No PES in the FIFO. p_last is no longer valid. */
195         p_fifo->pp_last = &p_fifo->p_first;
196     }
197
198     vlc_mutex_unlock( &p_fifo->data_lock );
199
200     if( pp_pes )
201         *pp_pes = p_pes;
202     else
203         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
204 }
205
206 /****************************************************************************
207  * input_FlushPESFifo
208  *****************************************************************************
209  * Empties the PES fifo of the decoder.
210  ****************************************************************************/
211 void input_FlushPESFifo( decoder_fifo_t *p_fifo )
212 {
213     pes_packet_t * p_pes;
214
215     vlc_mutex_lock( &p_fifo->data_lock );
216     while( p_fifo->p_first )
217     {
218         p_pes = p_fifo->p_first;
219         p_fifo->p_first = p_fifo->p_first->p_next;
220         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
221     }
222     /* No PES in the FIFO. p_last is no longer valid. */
223     p_fifo->pp_last = &p_fifo->p_first;
224     vlc_mutex_unlock( &p_fifo->data_lock );
225 }
226
227 /*****************************************************************************
228  * input_EscapeDiscontinuity: send a NULL packet to the decoders
229  *****************************************************************************/
230 void input_EscapeDiscontinuity( input_thread_t * p_input )
231 {
232     int     i_es, i;
233
234     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
235     {
236         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
237
238         if( p_es->p_decoder_fifo != NULL )
239         {
240             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
241             {
242                 input_NullPacket( p_input, p_es );
243             }
244         }
245     }
246 }
247
248 /*****************************************************************************
249  * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
250  *****************************************************************************/
251 void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
252 {
253     int     i_es, i;
254
255     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
256     {
257         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
258
259         if( p_es->p_decoder_fifo != NULL && p_es->i_cat == AUDIO_ES )
260         {
261             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
262             {
263                 input_NullPacket( p_input, p_es );
264             }
265         }
266     }
267 }
268
269 /*****************************************************************************
270  * CreateDecoderFifo: create a decoder_fifo_t
271  *****************************************************************************/
272 static decoder_fifo_t * CreateDecoderFifo( input_thread_t * p_input,
273                                            es_descriptor_t * p_es )
274 {
275     decoder_fifo_t * p_fifo;
276
277     /* Decoder FIFO */
278     p_fifo = vlc_object_create( p_input, VLC_OBJECT_DECODER );
279     if( p_fifo == NULL )
280     {
281         msg_Err( p_input, "out of memory" );
282         return NULL;
283     }
284
285     /* Select a new ES */
286     INSERT_ELEM( p_input->stream.pp_selected_es,
287                  p_input->stream.i_selected_es_number,
288                  p_input->stream.i_selected_es_number,
289                  p_es );
290
291     /* Initialize the p_fifo structure */
292     vlc_mutex_init( p_input, &p_fifo->data_lock );
293     vlc_cond_init( p_input, &p_fifo->data_wait );
294     p_es->p_decoder_fifo = p_fifo;
295
296     p_fifo->i_id = p_es->i_id;
297     p_fifo->i_fourcc = p_es->i_fourcc;
298     p_fifo->p_demux_data = p_es->p_demux_data;
299     
300     p_fifo->p_stream_ctrl = &p_input->stream.control;
301     p_fifo->p_sout = p_input->stream.p_sout;
302
303     p_fifo->p_first = NULL;
304     p_fifo->pp_last = &p_fifo->p_first;
305     p_fifo->i_depth = 0;
306     p_fifo->b_die = p_fifo->b_error = 0;
307     p_fifo->p_packets_mgt = p_input->p_method_data;
308
309     vlc_object_attach( p_fifo, p_input );
310
311     return p_fifo;
312 }
313
314 /*****************************************************************************
315  * DeleteDecoderFifo: destroy a decoder_fifo_t
316  *****************************************************************************/
317 static void DeleteDecoderFifo( decoder_fifo_t * p_fifo )
318 {
319     vlc_object_detach( p_fifo );
320
321     msg_Dbg( p_fifo, "killing decoder for 0x%x, fourcc `%4.4s', %d PES in FIFO",
322                      p_fifo->i_id, (char*)&p_fifo->i_fourcc, p_fifo->i_depth );
323
324     /* Free all packets still in the decoder fifo. */
325     input_DeletePES( p_fifo->p_packets_mgt,
326                      p_fifo->p_first );
327
328     /* Destroy the lock and cond */
329     vlc_cond_destroy( &p_fifo->data_wait );
330     vlc_mutex_destroy( &p_fifo->data_lock );
331 }
332