]> git.sesse.net Git - vlc/blob - src/input/input_dec.c
* Borrowed MPlayer's fast memcpy() routines. Best is autodetected, choose
[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.19 2001/12/03 16:18:37 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 "defs.h"
28
29 #include <stdlib.h>
30 #include <string.h>                                    /* memcpy(), memset() */
31 #include <sys/types.h>                                              /* off_t */
32
33 #include "config.h"
34 #include "common.h"
35 #include "intf_msg.h"
36 #include "threads.h"
37 #include "mtime.h"
38
39 #include "stream_control.h"
40 #include "input_ext-dec.h"
41 #include "input_ext-intf.h"
42 #include "input_ext-plugins.h"
43
44 #include "modules.h"
45
46 static decoder_config_t * CreateDecoderConfig( input_thread_t * p_input,
47                                                es_descriptor_t * p_es );
48 static void DeleteDecoderConfig( decoder_config_t * p_config );
49
50 /*****************************************************************************
51  * input_RunDecoder: spawns a new decoder thread
52  *****************************************************************************/
53 vlc_thread_t input_RunDecoder( input_thread_t * p_input,
54                                es_descriptor_t * p_es )
55 {
56     probedata_t probedata;
57     vlc_thread_t thread_id;
58
59     /* Get a suitable module */
60     probedata.i_type = p_es->i_type;
61
62     p_es->p_module = module_Need( MODULE_CAPABILITY_DEC, &probedata );
63     if( p_es->p_module == NULL )
64     {
65         intf_ErrMsg( "input error: no suitable decoder module for type 0x%x",
66                       p_es->i_type );
67         return( 0 );
68     }
69
70     /* Create the decoder configuration structure */
71     p_es->p_config = CreateDecoderConfig( p_input, p_es );
72
73     if( p_es->p_config == NULL )
74     {
75         intf_ErrMsg( "input error: could not create decoder config" );
76         module_Unneed( p_es->p_module );
77         return( 0 );
78     }
79
80     /* Spawn the decoder thread */
81     if ( vlc_thread_create( &thread_id, "decoder",
82          (vlc_thread_func_t)p_es->p_module->
83              p_functions->dec.functions.dec.pf_run,
84          (void *)p_es->p_config) ) 
85     {
86         intf_ErrMsg( "input error: can't spawn decoder thread \"%s\"",
87                      p_es->p_module->psz_name );
88         free( p_es->p_config );
89         module_Unneed( p_es->p_module );
90         return( 0 );
91     }
92
93     intf_DbgMsg( "input debug: decoder \"%s\"thread created", 
94                  p_es->p_module->psz_name );
95     
96     return thread_id;
97 }
98
99
100 /*****************************************************************************
101  * input_EndDecoder: kills a decoder thread and waits until it's finished
102  *****************************************************************************/
103 void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
104 {
105     int i_dummy;
106
107     p_es->p_decoder_fifo->b_die = 1;
108
109     /* Make sure the thread leaves the NextDataPacket() function by
110      * sending it a few null packets. */
111     for( i_dummy = 0; i_dummy < PADDING_PACKET_NUMBER; i_dummy++ )
112     {
113         input_NullPacket( p_input, p_es );
114     }
115
116     if( p_es->p_pes != NULL )
117     {
118         input_DecodePES( p_es->p_decoder_fifo, p_es->p_pes );
119     }
120
121     /* Waiting for the thread to exit */
122     /* I thought that unlocking was better since thread join can be long
123      * but it actually creates late pictures and freezes --stef */
124 //    vlc_mutex_unlock( &p_input->stream.stream_lock );
125     vlc_thread_join( p_es->thread_id );
126 //    vlc_mutex_lock( &p_input->stream.stream_lock );
127
128     /* Delete decoder configuration */
129     DeleteDecoderConfig( p_es->p_config );
130
131     /* Unneed module */
132     module_Unneed( p_es->p_module );
133
134     /* Tell the input there is no more decoder */
135     p_es->p_decoder_fifo = NULL;
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     if( !DECODER_FIFO_ISFULL( *p_decoder_fifo ) )
148     {
149         p_decoder_fifo->buffer[p_decoder_fifo->i_end] = p_pes;
150         DECODER_FIFO_INCEND( *p_decoder_fifo );
151
152         /* Warn the decoder that it's got work to do. */
153         vlc_cond_signal( &p_decoder_fifo->data_wait );
154     }
155     else
156     {
157         /* The FIFO is full !!! This should not happen. */
158         p_decoder_fifo->pf_delete_pes( p_decoder_fifo->p_packets_mgt,
159                                        p_pes );
160         intf_ErrMsg( "PES trashed - decoder fifo full !" );
161     }
162     vlc_mutex_unlock( &p_decoder_fifo->data_lock );
163 }
164
165 /*****************************************************************************
166  * input_EscapeDiscontinuity: send a NULL packet to the decoders
167  *****************************************************************************/
168 void input_EscapeDiscontinuity( input_thread_t * p_input,
169                                 pgrm_descriptor_t * p_pgrm )
170 {
171     int     i_es, i;
172
173     for( i_es = 0; i_es < p_pgrm->i_es_number; i_es++ )
174     {
175         es_descriptor_t * p_es = p_pgrm->pp_es[i_es];
176
177         if( p_es->p_decoder_fifo != NULL )
178         {
179             for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
180             {
181                 input_NullPacket( p_input, p_es );
182             }
183         }
184     }
185 }
186
187 /*****************************************************************************
188  * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders
189  *****************************************************************************/
190 void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
191 {
192     int     i_pgrm, i_es, i;
193
194     for( i_pgrm = 0; i_pgrm < p_input->stream.i_pgrm_number; i_pgrm++ )
195     {
196         pgrm_descriptor_t * p_pgrm = p_input->stream.pp_programs[i_pgrm];
197
198         for( i_es = 0; i_es < p_pgrm->i_es_number; i_es++ )
199         {
200             es_descriptor_t * p_es = p_pgrm->pp_es[i_es];
201
202             if( p_es->p_decoder_fifo != NULL && p_es->b_audio )
203             {
204                 for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
205                 {
206                     input_NullPacket( p_input, p_es );
207                 }
208             }
209         }
210     }
211 }
212
213 /*****************************************************************************
214  * CreateDecoderConfig: create a decoder_config_t
215  *****************************************************************************/
216 static decoder_config_t * CreateDecoderConfig( input_thread_t * p_input,
217                                                es_descriptor_t * p_es )
218 {
219     decoder_config_t * p_config;
220
221     p_config = (decoder_config_t *)malloc( sizeof(decoder_config_t) );
222     if( p_config == NULL )
223     {
224         intf_ErrMsg( "Unable to allocate memory in CreateDecoderConfig" );
225         return NULL;
226     }
227
228     /* Decoder FIFO */
229     if( (p_config->p_decoder_fifo =
230             (decoder_fifo_t *)malloc( sizeof(decoder_fifo_t) )) == NULL )
231     {
232         intf_ErrMsg( "Out of memory" );
233         free( p_config );
234         return NULL;
235     }
236
237     /* Select a new ES */
238     p_input->stream.i_selected_es_number++;
239     p_input->stream.pp_selected_es = realloc(
240                                        p_input->stream.pp_selected_es,
241                                        p_input->stream.i_selected_es_number
242                                         * sizeof(es_descriptor_t *) );
243     if( p_input->stream.pp_selected_es == NULL )
244     {
245         intf_ErrMsg( "Unable to realloc memory" );
246         free( p_config->p_decoder_fifo );
247         free( p_config );
248         return NULL;
249     }
250     p_input->stream.pp_selected_es[p_input->stream.i_selected_es_number - 1]
251             = p_es;
252
253     /* Initialize the p_config structure */
254     vlc_mutex_init(&p_config->p_decoder_fifo->data_lock);
255     vlc_cond_init(&p_config->p_decoder_fifo->data_wait);
256     p_es->p_decoder_fifo = p_config->p_decoder_fifo;
257
258     p_config->pf_init_bit_stream = p_input->pf_init_bit_stream;
259
260     p_config->i_id = p_es->i_id;
261     p_config->i_type = p_es->i_type;
262     p_config->p_stream_ctrl = &p_input->stream.control;
263
264     p_config->p_decoder_fifo->i_start = p_config->p_decoder_fifo->i_end = 0;
265     p_config->p_decoder_fifo->b_die = p_config->p_decoder_fifo->b_error = 0;
266     p_config->p_decoder_fifo->p_packets_mgt = p_input->p_method_data;
267     p_config->p_decoder_fifo->pf_delete_pes = p_input->pf_delete_pes;
268
269     return p_config;
270 }
271
272 /*****************************************************************************
273  * DeleteDecoderConfig: create a decoder_config_t
274  *****************************************************************************/
275 static void DeleteDecoderConfig( decoder_config_t * p_config )
276 {
277     /* Free all packets still in the decoder fifo. */
278     while( !DECODER_FIFO_ISEMPTY( *p_config->p_decoder_fifo ) )
279     {
280         p_config->p_decoder_fifo->pf_delete_pes(
281                             p_config->p_decoder_fifo->p_packets_mgt,
282                             DECODER_FIFO_START( *p_config->p_decoder_fifo ) );
283         DECODER_FIFO_INCSTART( *p_config->p_decoder_fifo );
284     }
285
286     /* Destroy the lock and cond */
287     vlc_cond_destroy( &p_config->p_decoder_fifo->data_wait );
288     vlc_mutex_destroy( &p_config->p_decoder_fifo->data_lock );
289
290     free( p_config->p_decoder_fifo );
291
292     free( p_config );
293 }
294