]> git.sesse.net Git - vlc/blob - src/input/input_dec.c
* all: modified files for video transcoding. Still needed configure.ac.in
[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.56 2003/01/22 10:44:50 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             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'",
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  * input_ExtractPES
219  *****************************************************************************
220  * Extract a PES from the fifo. If pp_pes is NULL then the PES is just
221  * deleted, otherwise *pp_pes will point to this PES.
222  ****************************************************************************/
223 void input_ExtractPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
224 {
225     pes_packet_t *p_pes;
226
227     vlc_mutex_lock( &p_fifo->data_lock );
228
229     if( p_fifo->p_first == NULL )
230     {
231         if( p_fifo->b_die )
232         {
233             vlc_mutex_unlock( &p_fifo->data_lock );
234             if( pp_pes ) *pp_pes = NULL;
235             return;
236         }
237
238         /* Signal the input thread we're waiting. This is only
239          * needed in case of slave clock (ES plug-in) but it won't
240          * harm. */
241         vlc_cond_signal( &p_fifo->data_wait );
242
243         /* Wait for the input to tell us when we received a packet. */
244         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
245     }
246
247     p_pes = p_fifo->p_first;
248     p_fifo->p_first = p_pes->p_next;
249     p_pes->p_next = NULL;
250     p_fifo->i_depth--;
251
252     if( !p_fifo->p_first )
253     {
254         /* No PES in the FIFO. p_last is no longer valid. */
255         p_fifo->pp_last = &p_fifo->p_first;
256     }
257
258     vlc_mutex_unlock( &p_fifo->data_lock );
259
260     if( pp_pes )
261         *pp_pes = p_pes;
262     else
263         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
264 }
265
266 /****************************************************************************
267  * input_FlushPESFifo
268  *****************************************************************************
269  * Empties the PES fifo of the decoder.
270  ****************************************************************************/
271 void input_FlushPESFifo( decoder_fifo_t *p_fifo )
272 {
273     pes_packet_t * p_pes;
274
275     vlc_mutex_lock( &p_fifo->data_lock );
276     while( p_fifo->p_first )
277     {
278         p_pes = p_fifo->p_first;
279         p_fifo->p_first = p_fifo->p_first->p_next;
280         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
281     }
282     /* No PES in the FIFO. p_last is no longer valid. */
283     p_fifo->pp_last = &p_fifo->p_first;
284     vlc_mutex_unlock( &p_fifo->data_lock );
285 }
286
287 /*****************************************************************************
288  * input_EscapeDiscontinuity: send a NULL packet to the decoders
289  *****************************************************************************/
290 void input_EscapeDiscontinuity( input_thread_t * p_input )
291 {
292     unsigned int i_es, i;
293
294     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
295     {
296         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
297
298         if( p_es->p_decoder_fifo != NULL )
299         {
300             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
301             {
302                 input_NullPacket( p_input, p_es );
303             }
304         }
305     }
306 }
307
308 /*****************************************************************************
309  * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
310  *****************************************************************************/
311 void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
312 {
313     unsigned int i_es, i;
314
315     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
316     {
317         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
318
319         if( p_es->p_decoder_fifo != NULL && p_es->i_cat == AUDIO_ES )
320         {
321             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
322             {
323                 input_NullPacket( p_input, p_es );
324             }
325         }
326     }
327 }
328
329 /*****************************************************************************
330  * CreateDecoderFifo: create a decoder_fifo_t
331  *****************************************************************************/
332 static decoder_fifo_t * CreateDecoderFifo( input_thread_t * p_input,
333                                            es_descriptor_t * p_es )
334 {
335     decoder_fifo_t * p_fifo;
336
337     /* Decoder FIFO */
338     p_fifo = vlc_object_create( p_input, VLC_OBJECT_DECODER );
339     if( p_fifo == NULL )
340     {
341         msg_Err( p_input, "out of memory" );
342         return NULL;
343     }
344
345     /* Select a new ES */
346     INSERT_ELEM( p_input->stream.pp_selected_es,
347                  p_input->stream.i_selected_es_number,
348                  p_input->stream.i_selected_es_number,
349                  p_es );
350
351     /* Initialize the p_fifo structure */
352     vlc_mutex_init( p_input, &p_fifo->data_lock );
353     vlc_cond_init( p_input, &p_fifo->data_wait );
354     p_es->p_decoder_fifo = p_fifo;
355
356     p_fifo->i_id = p_es->i_id;
357     p_fifo->i_fourcc = p_es->i_fourcc;
358     p_fifo->p_demux_data   = p_es->p_demux_data;
359     p_fifo->p_waveformatex = p_es->p_waveformatex;
360     p_fifo->p_bitmapinfoheader = p_es->p_bitmapinfoheader;
361     p_fifo->p_stream_ctrl = &p_input->stream.control;
362     p_fifo->p_sout = p_input->stream.p_sout;
363
364     p_fifo->p_first = NULL;
365     p_fifo->pp_last = &p_fifo->p_first;
366     p_fifo->i_depth = 0;
367     p_fifo->b_die = p_fifo->b_error = 0;
368     p_fifo->p_packets_mgt = p_input->p_method_data;
369
370     vlc_object_attach( p_fifo, p_input );
371
372     return p_fifo;
373 }
374
375 /*****************************************************************************
376  * DeleteDecoderFifo: destroy a decoder_fifo_t
377  *****************************************************************************/
378 static void DeleteDecoderFifo( decoder_fifo_t * p_fifo )
379 {
380     vlc_object_detach( p_fifo );
381
382     msg_Dbg( p_fifo, "killing decoder for 0x%x, fourcc `%4.4s', %d PES in FIFO",
383                      p_fifo->i_id, (char*)&p_fifo->i_fourcc, p_fifo->i_depth );
384
385     /* Free all packets still in the decoder fifo. */
386     input_DeletePES( p_fifo->p_packets_mgt,
387                      p_fifo->p_first );
388
389     /* Destroy the lock and cond */
390     vlc_cond_destroy( &p_fifo->data_wait );
391     vlc_mutex_destroy( &p_fifo->data_lock );
392 }
393