]> git.sesse.net Git - vlc/blob - src/input/input_dec.c
7489d7aa7c07ded49a53f3485ba8cd8738e28772
[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.59 2003/03/04 13:21:19 massiot 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             vlc_bool_t b_reencode = VLC_FALSE;
80
81             if( p_es->i_cat == AUDIO_ES )
82             {
83                 char *psz_sout_acodec = config_GetPsz( p_input, "sout-acodec" );
84                 if( psz_sout_acodec != NULL && *psz_sout_acodec != '\0' )
85                 {
86                     msg_Dbg( p_input, "audio reencoding requested -> unsupported" );
87                     b_reencode = VLC_TRUE;
88                 }
89             }
90             else if( p_es->i_cat == VIDEO_ES )
91             {
92                 char *psz_sout_vcodec = config_GetPsz( p_input, "sout-vcodec" );
93                 if( psz_sout_vcodec != NULL && *psz_sout_vcodec != '\0' )
94                 {
95                     msg_Dbg( p_input, "video reencoding requested" );
96                     /* force encoder video output */
97                     config_PutPsz( p_input, "vout", "encoder" );
98                     b_reencode = VLC_TRUE;
99                 }
100             }
101
102             if( !b_reencode )
103             {
104                 /* we don't want to reencode so search for a packetizer */
105                 p_fifo->p_module =
106                     module_Need( p_fifo, "packetizer", "$packetizer" );
107             }
108             else
109             {
110                 /* get a suitable decoder module to do reencoding*/
111                 p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
112             }
113         }
114     }
115     else
116     {
117         /* default Get a suitable decoder module */
118         p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
119     }
120
121     if( p_fifo->p_module == NULL )
122     {
123         msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'.\nVLC probably does not support this sound or video format.",
124                        (char*)&p_fifo->i_fourcc );
125         DeleteDecoderFifo( p_fifo );
126         vlc_object_destroy( p_fifo );
127         return NULL;
128     }
129
130     if ( p_es->i_cat == AUDIO_ES )
131     {
132         i_priority = VLC_THREAD_PRIORITY_AUDIO;
133     }
134     else
135     {
136         i_priority = VLC_THREAD_PRIORITY_VIDEO;
137     }
138
139     /* Spawn the decoder thread */
140     if( vlc_thread_create( p_fifo, "decoder", p_fifo->pf_run,
141                            i_priority, VLC_FALSE ) )
142     {
143         msg_Err( p_fifo, "cannot spawn decoder thread \"%s\"",
144                          p_fifo->p_module->psz_object_name );
145         module_Unneed( p_fifo, p_fifo->p_module );
146         return NULL;
147     }
148
149     p_input->stream.b_changed = 1;
150
151     return p_fifo;
152 }
153
154
155 /*****************************************************************************
156  * input_EndDecoder: kills a decoder thread and waits until it's finished
157  *****************************************************************************/
158 void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
159 {
160     int i_dummy;
161
162     p_es->p_decoder_fifo->b_die = 1;
163
164     /* Make sure the thread leaves the NextDataPacket() function by
165      * sending it a few null packets. */
166     for( i_dummy = 0; i_dummy < PADDING_PACKET_NUMBER; i_dummy++ )
167     {
168         input_NullPacket( p_input, p_es );
169     }
170
171     if( p_es->p_pes != NULL )
172     {
173         input_DecodePES( p_es->p_decoder_fifo, p_es->p_pes );
174     }
175
176     /* Waiting for the thread to exit */
177     /* I thought that unlocking was better since thread join can be long
178      * but it actually creates late pictures and freezes --stef */
179     /* vlc_mutex_unlock( &p_input->stream.stream_lock ); */
180     vlc_thread_join( p_es->p_decoder_fifo );
181     /* vlc_mutex_lock( &p_input->stream.stream_lock ); */
182
183     /* Delete decoder configuration */
184     DeleteDecoderFifo( p_es->p_decoder_fifo );
185
186     /* Unneed module */
187     module_Unneed( p_es->p_decoder_fifo, p_es->p_decoder_fifo->p_module );
188
189     /* Delete the fifo */
190     vlc_object_destroy( p_es->p_decoder_fifo );
191
192     /* Tell the input there is no more decoder */
193     p_es->p_decoder_fifo = NULL;
194
195     p_input->stream.b_changed = 1;
196 }
197
198 /*****************************************************************************
199  * input_DecodePES
200  *****************************************************************************
201  * Put a PES in the decoder's fifo.
202  *****************************************************************************/
203 void input_DecodePES( decoder_fifo_t * p_decoder_fifo, pes_packet_t * p_pes )
204 {
205     vlc_mutex_lock( &p_decoder_fifo->data_lock );
206
207     p_pes->p_next = NULL;
208     *p_decoder_fifo->pp_last = p_pes;
209     p_decoder_fifo->pp_last = &p_pes->p_next;
210     p_decoder_fifo->i_depth++;
211
212     /* Warn the decoder that it's got work to do. */
213     vlc_cond_signal( &p_decoder_fifo->data_wait );
214     vlc_mutex_unlock( &p_decoder_fifo->data_lock );
215 }
216
217 /*****************************************************************************
218  * Create a NULL packet for padding in case of a data loss
219  *****************************************************************************/
220 void input_NullPacket( input_thread_t * p_input,
221                        es_descriptor_t * p_es )
222 {
223     data_packet_t *             p_pad_data;
224     pes_packet_t *              p_pes;
225
226     if( (p_pad_data = input_NewPacketForce( p_input->p_method_data,
227                     PADDING_PACKET_SIZE)) == NULL )
228     {
229         msg_Err( p_input, "no new packet" );
230         p_input->b_error = 1;
231         return;
232     }
233
234     memset( p_pad_data->p_payload_start, 0, PADDING_PACKET_SIZE );
235     p_pad_data->b_discard_payload = 1;
236     p_pes = p_es->p_pes;
237
238     if( p_pes != NULL )
239     {
240         p_pes->b_discontinuity = 1;
241         p_pes->p_last->p_next = p_pad_data;
242         p_pes->p_last = p_pad_data;
243         p_pes->i_nb_data++;
244     }
245     else
246     {
247         if( (p_pes = input_NewPES( p_input->p_method_data )) == NULL )
248         {
249             msg_Err( p_input, "no PES packet" );
250             p_input->b_error = 1;
251             return;
252         }
253
254         p_pes->i_rate = p_input->stream.control.i_rate;
255         p_pes->p_first = p_pes->p_last = p_pad_data;
256         p_pes->i_nb_data = 1;
257         p_pes->b_discontinuity = 1;
258         input_DecodePES( p_es->p_decoder_fifo, p_pes );
259     }
260 }
261
262 /*****************************************************************************
263  * input_EscapeDiscontinuity: send a NULL packet to the decoders
264  *****************************************************************************/
265 void input_EscapeDiscontinuity( input_thread_t * p_input )
266 {
267     unsigned int i_es, i;
268
269     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
270     {
271         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
272
273         if( p_es->p_decoder_fifo != NULL )
274         {
275             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
276             {
277                 input_NullPacket( p_input, p_es );
278             }
279         }
280     }
281 }
282
283 /*****************************************************************************
284  * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
285  *****************************************************************************/
286 void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
287 {
288     unsigned int i_es, i;
289
290     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
291     {
292         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
293
294         if( p_es->p_decoder_fifo != NULL && p_es->i_cat == AUDIO_ES )
295         {
296             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
297             {
298                 input_NullPacket( p_input, p_es );
299             }
300         }
301     }
302 }
303
304 /*****************************************************************************
305  * CreateDecoderFifo: create a decoder_fifo_t
306  *****************************************************************************/
307 static decoder_fifo_t * CreateDecoderFifo( input_thread_t * p_input,
308                                            es_descriptor_t * p_es )
309 {
310     decoder_fifo_t * p_fifo;
311
312     /* Decoder FIFO */
313     p_fifo = vlc_object_create( p_input, VLC_OBJECT_DECODER );
314     if( p_fifo == NULL )
315     {
316         msg_Err( p_input, "out of memory" );
317         return NULL;
318     }
319
320     /* Select a new ES */
321     INSERT_ELEM( p_input->stream.pp_selected_es,
322                  p_input->stream.i_selected_es_number,
323                  p_input->stream.i_selected_es_number,
324                  p_es );
325
326     /* Initialize the p_fifo structure */
327     vlc_mutex_init( p_input, &p_fifo->data_lock );
328     vlc_cond_init( p_input, &p_fifo->data_wait );
329     p_es->p_decoder_fifo = p_fifo;
330
331     p_fifo->i_id = p_es->i_id;
332     p_fifo->i_fourcc = p_es->i_fourcc;
333     p_fifo->p_demux_data   = p_es->p_demux_data;
334     p_fifo->p_waveformatex = p_es->p_waveformatex;
335     p_fifo->p_bitmapinfoheader = p_es->p_bitmapinfoheader;
336     p_fifo->p_stream_ctrl = &p_input->stream.control;
337     p_fifo->p_sout = p_input->stream.p_sout;
338
339     p_fifo->p_first = NULL;
340     p_fifo->pp_last = &p_fifo->p_first;
341     p_fifo->i_depth = 0;
342     p_fifo->b_die = p_fifo->b_error = 0;
343     p_fifo->p_packets_mgt = p_input->p_method_data;
344
345     vlc_object_attach( p_fifo, p_input );
346
347     return p_fifo;
348 }
349
350 /*****************************************************************************
351  * DeleteDecoderFifo: destroy a decoder_fifo_t
352  *****************************************************************************/
353 static void DeleteDecoderFifo( decoder_fifo_t * p_fifo )
354 {
355     vlc_object_detach( p_fifo );
356
357     msg_Dbg( p_fifo, "killing decoder for 0x%x, fourcc `%4.4s', %d PES in FIFO",
358                      p_fifo->i_id, (char*)&p_fifo->i_fourcc, p_fifo->i_depth );
359
360     /* Free all packets still in the decoder fifo. */
361     input_DeletePES( p_fifo->p_packets_mgt,
362                      p_fifo->p_first );
363
364     /* Destroy the lock and cond */
365     vlc_cond_destroy( &p_fifo->data_wait );
366     vlc_mutex_destroy( &p_fifo->data_lock );
367 }
368