]> git.sesse.net Git - vlc/blob - src/input/input_programs.c
- Hardware YUV overlay (SDL) with real colors ;p It may suck for non
[vlc] / src / input / input_programs.c
1 /*****************************************************************************
2  * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  *
6  * Authors:
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include "defs.h"
27
28 #include <stdlib.h>
29
30 #include "config.h"
31 #include "common.h"
32 #include "threads.h"
33 #include "mtime.h"
34 #include "debug.h"
35
36 #include "intf_msg.h"
37
38 #include "stream_control.h"
39 #include "input_ext-intf.h"
40 #include "input_ext-dec.h"
41 #include "input.h"
42
43 /*
44  * NOTICE : all of these functions expect you to have taken the lock on
45  * p_input->stream.lock
46  */
47
48 /*****************************************************************************
49  * input_InitStream: init the stream descriptor of the given input
50  *****************************************************************************/
51 void input_InitStream( input_thread_t * p_input, size_t i_data_len )
52 {
53     p_input->stream.i_pgrm_number = 0;
54     p_input->stream.pp_programs = NULL;
55
56     if( i_data_len )
57     {
58         p_input->stream.p_demux_data = malloc( i_data_len );
59         memset( p_input->stream.p_demux_data, 0, i_data_len );
60     }
61 }
62
63 /*****************************************************************************
64  * input_AddProgram: add and init a program descriptor
65  *****************************************************************************
66  * This program descriptor will be referenced in the given stream descriptor
67  *****************************************************************************/
68 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
69                                       u16 i_pgrm_id, size_t i_data_len )
70 {
71     /* Where to add the pgrm */
72     int i_pgrm_index = p_input->stream.i_pgrm_number;
73
74     intf_DbgMsg("Adding description for pgrm %d", i_pgrm_id);
75
76     /* Add an entry to the list of program associated with the stream */
77     p_input->stream.i_pgrm_number++;
78     p_input->stream.pp_programs = realloc( p_input->stream.pp_programs,
79                                            p_input->stream.i_pgrm_number
80                                             * sizeof(pgrm_descriptor_t *) );
81
82     /* Allocate the structure to store this description */
83     p_input->stream.pp_programs[i_pgrm_index] =
84                                         malloc( sizeof(pgrm_descriptor_t) );
85
86     /* Init this entry */
87     p_input->stream.pp_programs[i_pgrm_index]->i_number = i_pgrm_id;
88     p_input->stream.pp_programs[i_pgrm_index]->b_is_ok = 0;
89
90     p_input->stream.pp_programs[i_pgrm_index]->i_es_number = 0;
91     p_input->stream.pp_programs[i_pgrm_index]->pp_es = NULL;
92
93     p_input->stream.pp_programs[i_pgrm_index]->delta_cr = 0;
94     p_input->stream.pp_programs[i_pgrm_index]->delta_absolute = 0;
95     p_input->stream.pp_programs[i_pgrm_index]->last_cr = 0;
96     p_input->stream.pp_programs[i_pgrm_index]->c_average_count = 0;
97     p_input->stream.pp_programs[i_pgrm_index]->i_synchro_state
98                                                 = SYNCHRO_NOT_STARTED;
99     p_input->stream.pp_programs[i_pgrm_index]->b_discontinuity = 0;
100
101     p_input->stream.pp_programs[i_pgrm_index]->p_vout
102                                             = p_input->p_default_vout;
103     p_input->stream.pp_programs[i_pgrm_index]->p_aout
104                                             = p_input->p_default_aout;
105
106     if( i_data_len )
107     {
108         p_input->stream.pp_programs[i_pgrm_index]->p_demux_data =
109             malloc( i_data_len );
110         memset( p_input->stream.pp_programs[i_pgrm_index]->p_demux_data, 0,
111                 i_data_len );
112     }
113
114     return p_input->stream.pp_programs[i_pgrm_index];
115 }
116
117 /*****************************************************************************
118  * input_DelProgram: destroy a program descriptor
119  *****************************************************************************
120  * All ES descriptions referenced in the descriptor will be deleted.
121  *****************************************************************************/
122 void input_DelProgram( input_thread_t * p_input, u16 i_pgrm_id )
123 {
124     int i_index, i_pgrm_index = -1;
125     pgrm_descriptor_t * p_pgrm = NULL;
126
127     intf_DbgMsg("Deleting description for pgrm %d", i_pgrm_id);
128
129     /* Find where this program is described */
130     for( i_index = 0; i_index < p_input->stream.i_pgrm_number; i_index++ )
131     {
132         if( p_input->stream.pp_programs[i_index]->i_number == i_pgrm_id )
133         {
134             i_pgrm_index = i_index;
135             p_pgrm = p_input->stream.pp_programs[ i_pgrm_index ];
136             break;
137         }
138     }
139
140     /* Make sure that the pgrm exists */
141     ASSERT(i_pgrm_index >= 0);
142     ASSERT(p_pgrm);
143
144     /* Free the structures that describe the es that belongs to that program */
145     for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
146     {
147         input_DelES( p_input, p_pgrm->pp_es[i_index]->i_id );
148     }
149
150     /* Free the table of es descriptors */
151     free( p_pgrm->pp_es );
152
153     /* Free the demux data */
154     if( p_pgrm->p_demux_data != NULL )
155     {
156         free( p_pgrm->p_demux_data );
157     }
158
159     /* Free the description of this stream */
160     free( p_pgrm );
161
162     /* Remove this program from the stream's list of programs */
163     p_input->stream.i_pgrm_number--;
164     p_input->stream.pp_programs[i_pgrm_index] =
165         p_input->stream.pp_programs[p_input->stream.i_pgrm_number];
166     p_input->stream.pp_programs = realloc( p_input->stream.pp_programs,
167                                            p_input->stream.i_pgrm_number
168                                             * sizeof(pgrm_descriptor_t *) );
169 }
170
171 /*****************************************************************************
172  * input_AddES:
173  *****************************************************************************
174  * Reserve a slot in the table of ES descriptors for the ES and add it to the
175  * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
176  * alone (PSI ?)
177  *****************************************************************************/
178 es_descriptor_t * input_AddES( input_thread_t * p_input,
179                                pgrm_descriptor_t * p_pgrm, u16 i_es_id,
180                                size_t i_data_len )
181 {
182     int i_index;
183     es_descriptor_t * p_es = NULL;
184
185     intf_DbgMsg("Adding description for ES %d", i_es_id);
186
187     /* Find an empty slot to store the description of that es */
188     for( i_index = 0; i_index < INPUT_MAX_ES &&
189          p_input->p_es[i_index].i_id != EMPTY_ID; i_index++ );
190
191     if( i_index >= INPUT_MAX_ES )
192     {
193         /* No slot is empty */
194         intf_ErrMsg("Stream carries too many ES for our decoder");
195     }
196     else
197     {
198         /* Reserve the slot for that ES */
199         p_es = &p_input->p_es[i_index];
200         p_es->i_id = i_es_id;
201         intf_DbgMsg("Slot %d in p_es table assigned to ES %d",
202                     i_index, i_es_id);
203
204         /* Init its values */
205         p_es->b_discontinuity = 0;
206         p_es->p_pes = NULL;
207         p_es->p_decoder_fifo = NULL;
208
209         if( i_data_len )
210         {
211             p_es->p_demux_data = malloc( i_data_len );
212             memset( p_es->p_demux_data, 0, i_data_len );
213         }
214
215         /* Add this ES to the program definition if one is given */
216         if( p_pgrm )
217         {
218             p_pgrm->i_es_number++;
219             p_pgrm->pp_es = realloc( p_pgrm->pp_es,
220                                      p_pgrm->i_es_number
221                                       * sizeof(es_descriptor_t *) );
222             p_pgrm->pp_es[p_pgrm->i_es_number - 1] = p_es;
223             p_es->p_pgrm = p_pgrm;
224         }
225         else
226         {
227             p_es->p_pgrm = NULL;
228         }
229     }
230
231     return p_es;
232 }
233
234 /*****************************************************************************
235  * input_DelES:
236  *****************************************************************************/
237 void input_DelES( input_thread_t * p_input, u16 i_id )
238 {
239     int                     i_index;
240     pgrm_descriptor_t *     p_pgrm = NULL;
241     es_descriptor_t *       p_es = NULL;
242
243     /* Look for the description of the ES */
244     for( i_index = 0; i_index < INPUT_MAX_ES; i_index++ )
245     {
246         if( p_input->p_es[i_index].i_id == i_id )
247         {
248             p_es = &p_input->p_es[i_index];
249             p_pgrm = p_input->p_es[i_index].p_pgrm;
250             break;
251         }
252     }
253
254     ASSERT( p_es );
255
256     /* Remove this ES from the description of the program if it is associated to
257      * one */
258     if( p_pgrm )
259     {
260         for( i_index = 0; ; i_index++ )
261         {
262             if( p_pgrm->pp_es[i_index]->i_id == i_id )
263             {
264                 p_pgrm->i_es_number--;
265                 p_pgrm->pp_es[i_index] = p_pgrm->pp_es[p_pgrm->i_es_number];
266                 p_pgrm->pp_es = realloc( p_pgrm->pp_es,
267                                          p_pgrm->i_es_number
268                                           * sizeof(es_descriptor_t *));
269                 break;
270             }
271         }
272     }
273
274     /* The table of stream descriptors is static, so don't free memory
275      * but just mark the slot as unused */
276     p_es->i_id = EMPTY_ID;
277
278     /* Free the demux data */
279     if( p_es->p_demux_data != NULL )
280     {
281         free( p_es->p_demux_data );
282     }
283 }
284
285 /*****************************************************************************
286  * InitDecConfig: initializes a decoder_config_t
287  *****************************************************************************/
288 static int InitDecConfig( input_thread_t * p_input, es_descriptor_t * p_es,
289                           decoder_config_t * p_config )
290 {
291     p_config->i_stream_id = p_es->i_stream_id;
292     p_config->i_type = p_es->i_type;
293     p_config->p_stream_ctrl =
294         &p_input->stream.control;
295
296     /* Decoder FIFO */
297     if( (p_config->p_decoder_fifo =
298             (decoder_fifo_t *)malloc( sizeof(decoder_fifo_t) )) == NULL )
299     {
300         intf_ErrMsg( "Out of memory" );
301         return( -1 );
302     }
303
304     vlc_mutex_init(&p_config->p_decoder_fifo->data_lock);
305     vlc_cond_init(&p_config->p_decoder_fifo->data_wait);
306     p_config->p_decoder_fifo->i_start = p_config->p_decoder_fifo->i_end = 0;
307     p_config->p_decoder_fifo->b_die = 0;
308     p_config->p_decoder_fifo->p_packets_mgt = p_input->p_method_data;
309     p_config->p_decoder_fifo->pf_delete_pes =
310         p_input->p_plugin->pf_delete_pes;
311     p_es->p_decoder_fifo = p_config->p_decoder_fifo;
312
313     p_config->pf_init_bit_stream = InitBitstream;
314
315     return( 0 );
316 }
317
318 /*****************************************************************************
319  * GetVdecConfig: returns a valid vdec_config_t
320  *****************************************************************************/
321 static vdec_config_t * GetVdecConfig( input_thread_t * p_input,
322                                       es_descriptor_t * p_es )
323 {
324     vdec_config_t *     p_config;
325
326     p_config = (vdec_config_t *)malloc( sizeof(vdec_config_t) );
327     p_config->p_vout = p_input->p_default_vout;
328     if( InitDecConfig( p_input, p_es, &p_config->decoder_config ) == -1 )
329     {
330         free( p_config );
331         return NULL;
332     }
333
334     return( p_config );
335 }
336
337 /*****************************************************************************
338  * GetAdecConfig: returns a valid adec_config_t
339  *****************************************************************************/
340 static adec_config_t * GetAdecConfig( input_thread_t * p_input,
341                                       es_descriptor_t * p_es )
342 {
343     adec_config_t *     p_config;
344
345     p_config = (adec_config_t *)malloc( sizeof(adec_config_t) );
346     p_config->p_aout = p_input->p_default_aout;
347     if( InitDecConfig( p_input, p_es, &p_config->decoder_config ) == -1 )
348     {
349         free( p_config );
350         return NULL;
351     }
352
353     return( p_config );
354 }
355
356 /*****************************************************************************
357  * input_SelectES: selects an ES and spawns the associated decoder
358  *****************************************************************************/
359 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
360 {
361     int                 i;
362     es_descriptor_t **  p_spot = NULL;
363
364 #ifdef DEBUG_INPUT
365     intf_DbgMsg( "Selecting ES %d", p_es->i_id );
366 #endif
367
368     if( p_es->p_decoder_fifo != NULL )
369     {
370         intf_ErrMsg( "ES %d is already selected", p_es->i_id );
371         return( -1 );
372     }
373
374     /* Find a free spot in pp_selected_es. */
375     for( i = 0; i < INPUT_MAX_SELECTED_ES; i++ )
376     {
377         if( p_input->pp_selected_es[i] == NULL )
378         {
379             p_spot = &p_input->pp_selected_es[i];
380             break;
381         }
382     }
383
384     if( p_spot == NULL )
385     {
386         intf_ErrMsg( "Too many ES selected" );
387         return( -1 );
388     }
389
390     switch( p_es->i_type )
391     {
392         /* FIXME ! */
393     case AC3_AUDIO_ES:
394         p_es->thread_id = ac3dec_CreateThread( GetAdecConfig( p_input, p_es ) );
395         break;
396
397     case MPEG1_AUDIO_ES:
398     case MPEG2_AUDIO_ES:
399         p_es->thread_id = adec_CreateThread( GetAdecConfig( p_input, p_es ) );
400         break;
401
402     case MPEG1_VIDEO_ES:
403     case MPEG2_VIDEO_ES:
404         p_es->thread_id = vpar_CreateThread( GetVdecConfig( p_input, p_es ) );
405         break;
406
407     default:
408         intf_ErrMsg( "Unknown stream type %d", p_es->i_type );
409         return( -1 );
410         break;
411     }
412
413     *p_spot = p_es;
414     return( 0 );
415 }