1 /*****************************************************************************
2 * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
3 *****************************************************************************
4 * Copyright (C) 1999-2002 VideoLAN
5 * $Id: input_programs.c,v 1.99 2002/12/06 16:34:08 sam Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <string.h> /* memcpy(), memset() */
32 #include "stream_control.h"
33 #include "input_ext-intf.h"
34 #include "input_ext-dec.h"
35 #include "input_ext-plugins.h"
38 * NOTICE : all of these functions expect you to have taken the lock on
39 * p_input->stream.lock
42 /*****************************************************************************
43 * input_InitStream: init the stream descriptor of the given input
44 *****************************************************************************/
45 int input_InitStream( input_thread_t * p_input, size_t i_data_len )
48 p_input->stream.i_stream_id = 0;
50 /* initialized to 0 since we don't give the signal to the interface
51 * before the end of input initialization */
52 p_input->stream.b_changed = 0;
53 p_input->stream.pp_es = NULL;
54 p_input->stream.pp_selected_es = NULL;
55 p_input->stream.p_removed_es = NULL;
56 p_input->stream.p_newly_selected_es = NULL;
57 p_input->stream.pp_programs = NULL;
58 p_input->stream.p_selected_program = NULL;
59 p_input->stream.p_new_program = NULL;
63 if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
65 msg_Err( p_input, "out of memory" );
68 memset( p_input->stream.p_demux_data, 0, i_data_len );
72 p_input->stream.p_demux_data = NULL;
78 /*****************************************************************************
79 * input_EndStream: free all stream descriptors
80 *****************************************************************************/
81 void input_EndStream( input_thread_t * p_input )
83 /* Free all programs and associated ES, and associated decoders. */
84 while( p_input->stream.i_pgrm_number )
86 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
89 /* Free standalone ES */
90 while( p_input->stream.i_es_number )
92 input_DelES( p_input, p_input->stream.pp_es[0] );
96 while( p_input->stream.i_area_nb )
98 input_DelArea( p_input, p_input->stream.pp_areas[0] );
101 /* Free selected ES */
102 if( p_input->stream.pp_selected_es != NULL )
104 free( p_input->stream.pp_selected_es );
107 if( p_input->stream.p_demux_data != NULL )
109 free( p_input->stream.p_demux_data );
113 /*****************************************************************************
114 * input_FindProgram: returns a pointer to a program described by its ID
115 *****************************************************************************/
116 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
121 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
123 if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
125 return p_input->stream.pp_programs[i];
132 /*****************************************************************************
133 * input_AddProgram: add and init a program descriptor
134 *****************************************************************************
135 * This program descriptor will be referenced in the given stream descriptor
136 *****************************************************************************/
137 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
138 u16 i_pgrm_id, size_t i_data_len )
140 /* Where to add the pgrm */
141 pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
145 msg_Err( p_input, "out of memory" );
149 /* Init this entry */
150 p_pgrm->i_number = i_pgrm_id;
152 p_pgrm->i_version = 0;
154 p_pgrm->i_es_number = 0;
155 p_pgrm->pp_es = NULL;
157 input_ClockInit( p_pgrm );
159 p_pgrm->i_synchro_state = SYNCHRO_START;
163 p_pgrm->p_demux_data = malloc( i_data_len );
164 if( p_pgrm->p_demux_data == NULL )
166 msg_Err( p_input, "out of memory" );
169 memset( p_pgrm->p_demux_data, 0, i_data_len );
173 p_pgrm->p_demux_data = NULL;
176 /* Add an entry to the list of program associated with the stream */
177 INSERT_ELEM( p_input->stream.pp_programs,
178 p_input->stream.i_pgrm_number,
179 p_input->stream.i_pgrm_number,
185 /*****************************************************************************
186 * input_DelProgram: destroy a program descriptor
187 *****************************************************************************
188 * All ES descriptions referenced in the descriptor will be deleted.
189 *****************************************************************************/
190 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
192 unsigned int i_pgrm_index;
194 /* Find the program in the programs table */
195 for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
198 if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
202 /* If the program wasn't found, do nothing */
203 if( i_pgrm_index == p_input->stream.i_pgrm_number )
205 msg_Err( p_input, "program does not belong to this input" );
209 /* Free the structures that describe the es that belongs to that program */
210 while( p_pgrm->i_es_number )
212 input_DelES( p_input, p_pgrm->pp_es[0] );
215 /* Free the demux data */
216 if( p_pgrm->p_demux_data != NULL )
218 free( p_pgrm->p_demux_data );
221 /* Remove this program from the stream's list of programs */
222 REMOVE_ELEM( p_input->stream.pp_programs,
223 p_input->stream.i_pgrm_number,
226 /* Free the description of this program */
230 /*****************************************************************************
231 * input_AddArea: add and init an area descriptor
232 *****************************************************************************
233 * This area descriptor will be referenced in the given stream descriptor
234 *****************************************************************************/
235 input_area_t * input_AddArea( input_thread_t * p_input )
237 /* Where to add the pgrm */
238 input_area_t * p_area = malloc( sizeof(input_area_t) );
242 msg_Err( p_input, "out of memory" );
246 /* Init this entry */
251 p_area->i_seek = NO_SEEK;
252 p_area->i_part_nb = 1;
255 /* Add an entry to the list of program associated with the stream */
256 INSERT_ELEM( p_input->stream.pp_areas,
257 p_input->stream.i_area_nb,
258 p_input->stream.i_area_nb,
264 /*****************************************************************************
265 * input_SetProgram: changes the current program
266 *****************************************************************************/
267 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
269 unsigned int i_es_index;
270 unsigned int i_required_audio_es;
271 unsigned int i_required_spu_es;
272 unsigned int i_audio_es = 0;
273 unsigned int i_spu_es = 0;
275 if ( p_input->stream.p_selected_program )
277 for ( i_es_index = 1 ; /* 0 should be the PMT */
278 i_es_index < p_input->stream.p_selected_program->
282 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
283 if ( p_es->p_decoder_fifo ) /* if the ES was selected */
285 input_UnselectES( p_input , p_es );
290 /* Get the number of the required audio stream */
291 if( config_GetInt( p_input, "audio" ) )
293 /* Default is the first one */
294 i_required_audio_es = config_GetInt( p_input, "audio-channel" );
295 if( i_required_audio_es < 0 )
297 i_required_audio_es = 1;
302 i_required_audio_es = 0;
305 /* Same thing for subtitles */
306 if( config_GetInt( p_input, "video" ) )
308 /* for spu, default is none */
309 i_required_spu_es = config_GetInt( p_input, "spu-channel" );
310 if( i_required_spu_es < 0 )
312 i_required_spu_es = 0;
317 i_required_spu_es = 0;
320 for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
322 switch( p_new_prg->pp_es[i_es_index]->i_cat )
325 msg_Dbg( p_input, "selecting ES %x",
326 p_new_prg->pp_es[i_es_index]->i_id );
327 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
331 if( i_audio_es <= i_required_audio_es )
333 msg_Dbg( p_input, "selecting ES %x",
334 p_new_prg->pp_es[i_es_index]->i_id );
335 input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
338 /* Not sure this one is fully specification-compliant */
341 if( i_spu_es <= i_required_spu_es )
343 msg_Dbg( p_input, "selecting ES %x",
344 p_new_prg->pp_es[i_es_index]->i_id );
345 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
349 msg_Dbg( p_input, "ES %x has unknown type",
350 p_new_prg->pp_es[i_es_index]->i_id );
357 p_input->stream.p_selected_program = p_new_prg;
363 /*****************************************************************************
364 * input_DelArea: destroy a area descriptor
365 *****************************************************************************
366 * All ES descriptions referenced in the descriptor will be deleted.
367 *****************************************************************************/
368 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
370 unsigned int i_area_index;
372 /* Find the area in the areas table */
373 for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
376 if( p_input->stream.pp_areas[i_area_index] == p_area )
380 /* If the area wasn't found, do nothing */
381 if( i_area_index == p_input->stream.i_area_nb )
383 msg_Err( p_input, "area does not belong to this input" );
387 /* Remove this area from the stream's list of areas */
388 REMOVE_ELEM( p_input->stream.pp_areas,
389 p_input->stream.i_area_nb,
392 /* Free the description of this area */
397 /*****************************************************************************
398 * input_FindES: returns a pointer to an ES described by its ID
399 *****************************************************************************/
400 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
404 for( i = 0; i < p_input->stream.i_es_number; i++ )
406 if( p_input->stream.pp_es[i]->i_id == i_es_id )
408 return p_input->stream.pp_es[i];
415 /*****************************************************************************
417 *****************************************************************************
418 * Reserve a slot in the table of ES descriptors for the ES and add it to the
419 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
421 *****************************************************************************/
422 es_descriptor_t * input_AddES( input_thread_t * p_input,
423 pgrm_descriptor_t * p_pgrm, u16 i_es_id,
426 es_descriptor_t * p_es;
428 p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
431 msg_Err( p_input, "out of memory" );
435 INSERT_ELEM( p_input->stream.pp_es,
436 p_input->stream.i_es_number,
437 p_input->stream.i_es_number,
440 /* Init its values */
441 p_es->i_id = i_es_id;
442 p_es->psz_desc[0] = '\0';
444 p_es->p_decoder_fifo = NULL;
445 p_es->i_cat = UNKNOWN_ES;
446 p_es->i_demux_fd = 0;
448 p_es->c_invalid_packets = 0;
452 p_es->p_demux_data = malloc( i_data_len );
453 if( p_es->p_demux_data == NULL )
455 msg_Err( p_input, "out of memory" );
458 memset( p_es->p_demux_data, 0, i_data_len );
462 p_es->p_demux_data = NULL;
465 /* Add this ES to the program definition if one is given */
468 INSERT_ELEM( p_pgrm->pp_es,
472 p_es->p_pgrm = p_pgrm;
482 /*****************************************************************************
484 *****************************************************************************/
485 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
487 unsigned int i_index, i_es_index;
488 pgrm_descriptor_t * p_pgrm;
490 /* Find the ES in the ES table */
491 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
494 if( p_input->stream.pp_es[i_es_index] == p_es )
498 /* If the ES wasn't found, do nothing */
499 if( i_es_index == p_input->stream.i_es_number )
501 msg_Err( p_input, "ES does not belong to this input" );
505 p_pgrm = p_es->p_pgrm;
507 /* Kill associated decoder, if any. */
508 if( p_es->p_decoder_fifo != NULL )
510 input_EndDecoder( p_input, p_es );
513 /* Remove this ES from the description of the program if it is associated to
517 for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
519 if( p_pgrm->pp_es[i_index] == p_es )
521 REMOVE_ELEM( p_pgrm->pp_es,
529 /* Free the demux data */
530 if( p_es->p_demux_data != NULL )
532 free( p_es->p_demux_data );
535 /* Find the ES in the ES table */
536 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
539 if( p_input->stream.pp_es[i_es_index] == p_es )
543 /* Remove this ES from the stream's list of ES */
544 REMOVE_ELEM( p_input->stream.pp_es,
545 p_input->stream.i_es_number,
552 /*****************************************************************************
553 * input_SelectES: selects an ES and spawns the associated decoder
554 *****************************************************************************
555 * Remember we are still supposed to have stream_lock when entering this
557 *****************************************************************************/
558 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
562 msg_Err( p_input, "nothing to do in input_SelectES" );
566 if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
567 && !config_GetInt( p_input, "video" ) )
570 "video is disabled, not selecting ES 0x%x", p_es->i_id );
574 if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
577 "audio is disabled, not selecting ES 0x%x", p_es->i_id );
581 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
583 if( p_es->p_decoder_fifo != NULL )
585 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
589 /* Release the lock, not to block the input thread during
590 * the creation of the thread. */
591 vlc_mutex_unlock( &p_input->stream.stream_lock );
592 p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
593 vlc_mutex_lock( &p_input->stream.stream_lock );
595 if( p_es->p_decoder_fifo == NULL )
603 /*****************************************************************************
604 * input_UnselectES: removes an ES from the list of selected ES
605 *****************************************************************************/
606 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
609 unsigned int i_index = 0;
613 msg_Err( p_input, "nothing to do in input_UnselectES" );
617 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
619 if( p_es->p_decoder_fifo == NULL )
621 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
625 input_EndDecoder( p_input, p_es );
628 if( ( p_es->p_decoder_fifo == NULL ) &&
629 ( p_input->stream.i_selected_es_number > 0 ) )
631 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
632 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
637 /* XXX: no need to memmove, we have unsorted data */
638 REMOVE_ELEM( p_input->stream.pp_selected_es,
639 p_input->stream.i_selected_es_number,
642 if( p_input->stream.i_selected_es_number == 0 )
644 msg_Dbg( p_input, "no more selected ES" );