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.95 2002/10/29 13:22:48 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() */
29 #include <sys/types.h> /* off_t */
33 #include "stream_control.h"
34 #include "input_ext-intf.h"
35 #include "input_ext-dec.h"
36 #include "input_ext-plugins.h"
39 * NOTICE : all of these functions expect you to have taken the lock on
40 * p_input->stream.lock
43 /*****************************************************************************
44 * input_InitStream: init the stream descriptor of the given input
45 *****************************************************************************/
46 int input_InitStream( input_thread_t * p_input, size_t i_data_len )
49 p_input->stream.i_stream_id = 0;
51 /* initialized to 0 since we don't give the signal to the interface
52 * before the end of input initialization */
53 p_input->stream.b_changed = 0;
54 p_input->stream.pp_es = NULL;
55 p_input->stream.pp_selected_es = NULL;
56 p_input->stream.p_removed_es = NULL;
57 p_input->stream.p_newly_selected_es = NULL;
58 p_input->stream.pp_programs = NULL;
59 p_input->stream.p_selected_program = NULL;
60 p_input->stream.p_new_program = NULL;
64 if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
66 msg_Err( p_input, "out of memory" );
69 memset( p_input->stream.p_demux_data, 0, i_data_len );
73 p_input->stream.p_demux_data = NULL;
79 /*****************************************************************************
80 * input_EndStream: free all stream descriptors
81 *****************************************************************************/
82 void input_EndStream( input_thread_t * p_input )
84 /* Free all programs and associated ES, and associated decoders. */
85 while( p_input->stream.i_pgrm_number )
87 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
90 /* Free standalone ES */
91 while( p_input->stream.i_es_number )
93 input_DelES( p_input, p_input->stream.pp_es[0] );
97 while( p_input->stream.i_area_nb )
99 input_DelArea( p_input, p_input->stream.pp_areas[0] );
102 /* Free selected ES */
103 if( p_input->stream.pp_selected_es != NULL )
105 free( p_input->stream.pp_selected_es );
108 if( p_input->stream.p_demux_data != NULL )
110 free( p_input->stream.p_demux_data );
114 /*****************************************************************************
115 * input_FindProgram: returns a pointer to a program described by its ID
116 *****************************************************************************/
117 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input, u16 i_pgrm_id )
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 )
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 )
270 int i_required_audio_es;
271 int i_required_spu_es;
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 )
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, u16 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 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 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
568 if( p_es->p_decoder_fifo != NULL )
570 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
574 /* Release the lock, not to block the input thread during
575 * the creation of the thread. */
576 vlc_mutex_unlock( &p_input->stream.stream_lock );
577 p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
578 vlc_mutex_lock( &p_input->stream.stream_lock );
580 if( p_es->p_decoder_fifo == NULL )
588 /*****************************************************************************
589 * input_UnselectES: removes an ES from the list of selected ES
590 *****************************************************************************/
591 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
598 msg_Err( p_input, "nothing to do in input_UnselectES" );
602 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
604 if( p_es->p_decoder_fifo == NULL )
606 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
610 input_EndDecoder( p_input, p_es );
613 if( ( p_es->p_decoder_fifo == NULL ) &&
614 ( p_input->stream.i_selected_es_number > 0 ) )
616 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
617 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
622 /* XXX: no need to memmove, we have unordered data */
623 REMOVE_ELEM( p_input->stream.pp_selected_es,
624 p_input->stream.i_selected_es_number,
627 if( p_input->stream.i_selected_es_number == 0 )
629 msg_Dbg( p_input, "no more selected ES" );