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