]> git.sesse.net Git - vlc/blob - src/input/input_dec.c
* all: new sout scheme. Now a chain of module are created that can
[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.60 2003/04/13 20:00:21 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 for packetizer module */
62     psz_sout = config_GetPsz( p_input, "sout" );
63     if( !p_es->b_force_decoder && psz_sout != NULL && *psz_sout != 0 )
64     {
65         vlc_bool_t b_sout = VLC_TRUE;
66
67         if( p_es->i_cat == AUDIO_ES )
68         {
69             b_sout = config_GetInt( p_input, "sout-audio" );
70         }
71         else if( p_es->i_cat == VIDEO_ES )
72         {
73             b_sout = config_GetInt( p_input, "sout-video" );
74         }
75
76         if( b_sout )
77         {
78             p_fifo->p_module =
79                 module_Need( p_fifo, "packetizer", "$packetizer" );
80         }
81     }
82     else
83     {
84         /* default Get a suitable decoder module */
85         p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
86     }
87
88     if( psz_sout )
89     {
90         free( psz_sout );
91     }
92
93     if( p_fifo->p_module == NULL )
94     {
95         msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'.\nVLC probably does not support this sound or video format.",
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  * Create a NULL packet for padding in case of a data loss
191  *****************************************************************************/
192 void input_NullPacket( input_thread_t * p_input,
193                        es_descriptor_t * p_es )
194 {
195     data_packet_t *             p_pad_data;
196     pes_packet_t *              p_pes;
197
198     if( (p_pad_data = input_NewPacketForce( p_input->p_method_data,
199                     PADDING_PACKET_SIZE)) == NULL )
200     {
201         msg_Err( p_input, "no new packet" );
202         p_input->b_error = 1;
203         return;
204     }
205
206     memset( p_pad_data->p_payload_start, 0, PADDING_PACKET_SIZE );
207     p_pad_data->b_discard_payload = 1;
208     p_pes = p_es->p_pes;
209
210     if( p_pes != NULL )
211     {
212         p_pes->b_discontinuity = 1;
213         p_pes->p_last->p_next = p_pad_data;
214         p_pes->p_last = p_pad_data;
215         p_pes->i_nb_data++;
216     }
217     else
218     {
219         if( (p_pes = input_NewPES( p_input->p_method_data )) == NULL )
220         {
221             msg_Err( p_input, "no PES packet" );
222             p_input->b_error = 1;
223             return;
224         }
225
226         p_pes->i_rate = p_input->stream.control.i_rate;
227         p_pes->p_first = p_pes->p_last = p_pad_data;
228         p_pes->i_nb_data = 1;
229         p_pes->b_discontinuity = 1;
230         input_DecodePES( p_es->p_decoder_fifo, p_pes );
231     }
232 }
233
234 /*****************************************************************************
235  * input_EscapeDiscontinuity: send a NULL packet to the decoders
236  *****************************************************************************/
237 void input_EscapeDiscontinuity( input_thread_t * p_input )
238 {
239     unsigned int i_es, i;
240
241     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
242     {
243         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
244
245         if( p_es->p_decoder_fifo != NULL )
246         {
247             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
248             {
249                 input_NullPacket( p_input, p_es );
250             }
251         }
252     }
253 }
254
255 /*****************************************************************************
256  * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
257  *****************************************************************************/
258 void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
259 {
260     unsigned int i_es, i;
261
262     for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
263     {
264         es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
265
266         if( p_es->p_decoder_fifo != NULL && p_es->i_cat == AUDIO_ES )
267         {
268             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
269             {
270                 input_NullPacket( p_input, p_es );
271             }
272         }
273     }
274 }
275
276 /*****************************************************************************
277  * CreateDecoderFifo: create a decoder_fifo_t
278  *****************************************************************************/
279 static decoder_fifo_t * CreateDecoderFifo( input_thread_t * p_input,
280                                            es_descriptor_t * p_es )
281 {
282     decoder_fifo_t * p_fifo;
283
284     /* Decoder FIFO */
285     p_fifo = vlc_object_create( p_input, VLC_OBJECT_DECODER );
286     if( p_fifo == NULL )
287     {
288         msg_Err( p_input, "out of memory" );
289         return NULL;
290     }
291
292     /* Select a new ES */
293     INSERT_ELEM( p_input->stream.pp_selected_es,
294                  p_input->stream.i_selected_es_number,
295                  p_input->stream.i_selected_es_number,
296                  p_es );
297
298     /* Initialize the p_fifo structure */
299     vlc_mutex_init( p_input, &p_fifo->data_lock );
300     vlc_cond_init( p_input, &p_fifo->data_wait );
301     p_es->p_decoder_fifo = p_fifo;
302
303     p_fifo->i_id = p_es->i_id;
304     p_fifo->i_fourcc = p_es->i_fourcc;
305     p_fifo->p_demux_data   = p_es->p_demux_data;
306     p_fifo->p_waveformatex = p_es->p_waveformatex;
307     p_fifo->p_bitmapinfoheader = p_es->p_bitmapinfoheader;
308     p_fifo->p_stream_ctrl = &p_input->stream.control;
309     p_fifo->p_sout = p_input->stream.p_sout;
310
311     p_fifo->p_first = NULL;
312     p_fifo->pp_last = &p_fifo->p_first;
313     p_fifo->i_depth = 0;
314     p_fifo->b_die = p_fifo->b_error = 0;
315     p_fifo->p_packets_mgt = p_input->p_method_data;
316
317     vlc_object_attach( p_fifo, p_input );
318
319     return p_fifo;
320 }
321
322 /*****************************************************************************
323  * DeleteDecoderFifo: destroy a decoder_fifo_t
324  *****************************************************************************/
325 static void DeleteDecoderFifo( decoder_fifo_t * p_fifo )
326 {
327     vlc_object_detach( p_fifo );
328
329     msg_Dbg( p_fifo, "killing decoder for 0x%x, fourcc `%4.4s', %d PES in FIFO",
330                      p_fifo->i_id, (char*)&p_fifo->i_fourcc, p_fifo->i_depth );
331
332     /* Free all packets still in the decoder fifo. */
333     input_DeletePES( p_fifo->p_packets_mgt,
334                      p_fifo->p_first );
335
336     /* Destroy the lock and cond */
337     vlc_cond_destroy( &p_fifo->data_wait );
338     vlc_mutex_destroy( &p_fifo->data_lock );
339 }
340