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