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.97 2002/11/10 18:04:23 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 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h> /* off_t */
36 #include "stream_control.h"
37 #include "input_ext-intf.h"
38 #include "input_ext-dec.h"
39 #include "input_ext-plugins.h"
42 * NOTICE : all of these functions expect you to have taken the lock on
43 * p_input->stream.lock
46 /*****************************************************************************
47 * input_InitStream: init the stream descriptor of the given input
48 *****************************************************************************/
49 int input_InitStream( input_thread_t * p_input, size_t i_data_len )
52 p_input->stream.i_stream_id = 0;
54 /* initialized to 0 since we don't give the signal to the interface
55 * before the end of input initialization */
56 p_input->stream.b_changed = 0;
57 p_input->stream.pp_es = NULL;
58 p_input->stream.pp_selected_es = NULL;
59 p_input->stream.p_removed_es = NULL;
60 p_input->stream.p_newly_selected_es = NULL;
61 p_input->stream.pp_programs = NULL;
62 p_input->stream.p_selected_program = NULL;
63 p_input->stream.p_new_program = NULL;
67 if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
69 msg_Err( p_input, "out of memory" );
72 memset( p_input->stream.p_demux_data, 0, i_data_len );
76 p_input->stream.p_demux_data = NULL;
82 /*****************************************************************************
83 * input_EndStream: free all stream descriptors
84 *****************************************************************************/
85 void input_EndStream( input_thread_t * p_input )
87 /* Free all programs and associated ES, and associated decoders. */
88 while( p_input->stream.i_pgrm_number )
90 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
93 /* Free standalone ES */
94 while( p_input->stream.i_es_number )
96 input_DelES( p_input, p_input->stream.pp_es[0] );
100 while( p_input->stream.i_area_nb )
102 input_DelArea( p_input, p_input->stream.pp_areas[0] );
105 /* Free selected ES */
106 if( p_input->stream.pp_selected_es != NULL )
108 free( p_input->stream.pp_selected_es );
111 if( p_input->stream.p_demux_data != NULL )
113 free( p_input->stream.p_demux_data );
117 /*****************************************************************************
118 * input_FindProgram: returns a pointer to a program described by its ID
119 *****************************************************************************/
120 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input, u16 i_pgrm_id )
124 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
126 if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
128 return p_input->stream.pp_programs[i];
135 /*****************************************************************************
136 * input_AddProgram: add and init a program descriptor
137 *****************************************************************************
138 * This program descriptor will be referenced in the given stream descriptor
139 *****************************************************************************/
140 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
141 u16 i_pgrm_id, size_t i_data_len )
143 /* Where to add the pgrm */
144 pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
148 msg_Err( p_input, "out of memory" );
152 /* Init this entry */
153 p_pgrm->i_number = i_pgrm_id;
155 p_pgrm->i_version = 0;
157 p_pgrm->i_es_number = 0;
158 p_pgrm->pp_es = NULL;
160 input_ClockInit( p_pgrm );
162 p_pgrm->i_synchro_state = SYNCHRO_START;
166 p_pgrm->p_demux_data = malloc( i_data_len );
167 if( p_pgrm->p_demux_data == NULL )
169 msg_Err( p_input, "out of memory" );
172 memset( p_pgrm->p_demux_data, 0, i_data_len );
176 p_pgrm->p_demux_data = NULL;
179 /* Add an entry to the list of program associated with the stream */
180 INSERT_ELEM( p_input->stream.pp_programs,
181 p_input->stream.i_pgrm_number,
182 p_input->stream.i_pgrm_number,
188 /*****************************************************************************
189 * input_DelProgram: destroy a program descriptor
190 *****************************************************************************
191 * All ES descriptions referenced in the descriptor will be deleted.
192 *****************************************************************************/
193 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
197 /* Find the program in the programs table */
198 for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
201 if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
205 /* If the program wasn't found, do nothing */
206 if( i_pgrm_index == p_input->stream.i_pgrm_number )
208 msg_Err( p_input, "program does not belong to this input" );
212 /* Free the structures that describe the es that belongs to that program */
213 while( p_pgrm->i_es_number )
215 input_DelES( p_input, p_pgrm->pp_es[0] );
218 /* Free the demux data */
219 if( p_pgrm->p_demux_data != NULL )
221 free( p_pgrm->p_demux_data );
224 /* Remove this program from the stream's list of programs */
225 REMOVE_ELEM( p_input->stream.pp_programs,
226 p_input->stream.i_pgrm_number,
229 /* Free the description of this program */
233 /*****************************************************************************
234 * input_AddArea: add and init an area descriptor
235 *****************************************************************************
236 * This area descriptor will be referenced in the given stream descriptor
237 *****************************************************************************/
238 input_area_t * input_AddArea( input_thread_t * p_input )
240 /* Where to add the pgrm */
241 input_area_t * p_area = malloc( sizeof(input_area_t) );
245 msg_Err( p_input, "out of memory" );
249 /* Init this entry */
254 p_area->i_seek = NO_SEEK;
255 p_area->i_part_nb = 1;
258 /* Add an entry to the list of program associated with the stream */
259 INSERT_ELEM( p_input->stream.pp_areas,
260 p_input->stream.i_area_nb,
261 p_input->stream.i_area_nb,
267 /*****************************************************************************
268 * input_SetProgram: changes the current program
269 *****************************************************************************/
270 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
273 int i_required_audio_es;
274 int i_required_spu_es;
278 if ( p_input->stream.p_selected_program )
280 for ( i_es_index = 1 ; /* 0 should be the PMT */
281 i_es_index < p_input->stream.p_selected_program->
285 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
286 if ( p_es->p_decoder_fifo ) /* if the ES was selected */
288 input_UnselectES( p_input , p_es );
293 /* Get the number of the required audio stream */
294 if( config_GetInt( p_input, "audio" ) )
296 /* Default is the first one */
297 i_required_audio_es = config_GetInt( p_input, "audio-channel" );
298 if( i_required_audio_es < 0 )
300 i_required_audio_es = 1;
305 i_required_audio_es = 0;
308 /* Same thing for subtitles */
309 if( config_GetInt( p_input, "video" ) )
311 /* for spu, default is none */
312 i_required_spu_es = config_GetInt( p_input, "spu-channel" );
313 if( i_required_spu_es < 0 )
315 i_required_spu_es = 0;
320 i_required_spu_es = 0;
323 for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
325 switch( p_new_prg->pp_es[i_es_index]->i_cat )
328 msg_Dbg( p_input, "selecting ES %x",
329 p_new_prg->pp_es[i_es_index]->i_id );
330 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
334 if( i_audio_es <= i_required_audio_es )
336 msg_Dbg( p_input, "selecting ES %x",
337 p_new_prg->pp_es[i_es_index]->i_id );
338 input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
341 /* Not sure this one is fully specification-compliant */
344 if( i_spu_es <= i_required_spu_es )
346 msg_Dbg( p_input, "selecting ES %x",
347 p_new_prg->pp_es[i_es_index]->i_id );
348 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
352 msg_Dbg( p_input, "ES %x has unknown type",
353 p_new_prg->pp_es[i_es_index]->i_id );
360 p_input->stream.p_selected_program = p_new_prg;
366 /*****************************************************************************
367 * input_DelArea: destroy a area descriptor
368 *****************************************************************************
369 * All ES descriptions referenced in the descriptor will be deleted.
370 *****************************************************************************/
371 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
375 /* Find the area in the areas table */
376 for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
379 if( p_input->stream.pp_areas[i_area_index] == p_area )
383 /* If the area wasn't found, do nothing */
384 if( i_area_index == p_input->stream.i_area_nb )
386 msg_Err( p_input, "area does not belong to this input" );
390 /* Remove this area from the stream's list of areas */
391 REMOVE_ELEM( p_input->stream.pp_areas,
392 p_input->stream.i_area_nb,
395 /* Free the description of this area */
400 /*****************************************************************************
401 * input_FindES: returns a pointer to an ES described by its ID
402 *****************************************************************************/
403 es_descriptor_t * input_FindES( input_thread_t * p_input, u16 i_es_id )
407 for( i = 0; i < p_input->stream.i_es_number; i++ )
409 if( p_input->stream.pp_es[i]->i_id == i_es_id )
411 return p_input->stream.pp_es[i];
418 /*****************************************************************************
420 *****************************************************************************
421 * Reserve a slot in the table of ES descriptors for the ES and add it to the
422 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
424 *****************************************************************************/
425 es_descriptor_t * input_AddES( input_thread_t * p_input,
426 pgrm_descriptor_t * p_pgrm, u16 i_es_id,
429 es_descriptor_t * p_es;
431 p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
434 msg_Err( p_input, "out of memory" );
438 INSERT_ELEM( p_input->stream.pp_es,
439 p_input->stream.i_es_number,
440 p_input->stream.i_es_number,
443 /* Init its values */
444 p_es->i_id = i_es_id;
445 p_es->psz_desc[0] = '\0';
447 p_es->p_decoder_fifo = NULL;
448 p_es->i_cat = UNKNOWN_ES;
449 p_es->i_demux_fd = 0;
451 p_es->c_invalid_packets = 0;
455 p_es->p_demux_data = malloc( i_data_len );
456 if( p_es->p_demux_data == NULL )
458 msg_Err( p_input, "out of memory" );
461 memset( p_es->p_demux_data, 0, i_data_len );
465 p_es->p_demux_data = NULL;
468 /* Add this ES to the program definition if one is given */
471 INSERT_ELEM( p_pgrm->pp_es,
475 p_es->p_pgrm = p_pgrm;
485 /*****************************************************************************
487 *****************************************************************************/
488 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
490 int i_index, i_es_index;
491 pgrm_descriptor_t * p_pgrm;
493 /* Find the ES in the ES table */
494 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
497 if( p_input->stream.pp_es[i_es_index] == p_es )
501 /* If the ES wasn't found, do nothing */
502 if( i_es_index == p_input->stream.i_es_number )
504 msg_Err( p_input, "ES does not belong to this input" );
508 p_pgrm = p_es->p_pgrm;
510 /* Kill associated decoder, if any. */
511 if( p_es->p_decoder_fifo != NULL )
513 input_EndDecoder( p_input, p_es );
516 /* Remove this ES from the description of the program if it is associated to
520 for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
522 if( p_pgrm->pp_es[i_index] == p_es )
524 REMOVE_ELEM( p_pgrm->pp_es,
532 /* Free the demux data */
533 if( p_es->p_demux_data != NULL )
535 free( p_es->p_demux_data );
538 /* Find the ES in the ES table */
539 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
542 if( p_input->stream.pp_es[i_es_index] == p_es )
546 /* Remove this ES from the stream's list of ES */
547 REMOVE_ELEM( p_input->stream.pp_es,
548 p_input->stream.i_es_number,
555 /*****************************************************************************
556 * input_SelectES: selects an ES and spawns the associated decoder
557 *****************************************************************************
558 * Remember we are still supposed to have stream_lock when entering this
560 *****************************************************************************/
561 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
565 msg_Err( p_input, "nothing to do in input_SelectES" );
569 if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
570 && !config_GetInt( p_input, "video" ) )
573 "video is disabled, not selecting ES 0x%x", p_es->i_id );
577 if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
580 "audio is disabled, not selecting ES 0x%x", p_es->i_id );
584 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
586 if( p_es->p_decoder_fifo != NULL )
588 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
592 /* Release the lock, not to block the input thread during
593 * the creation of the thread. */
594 vlc_mutex_unlock( &p_input->stream.stream_lock );
595 p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
596 vlc_mutex_lock( &p_input->stream.stream_lock );
598 if( p_es->p_decoder_fifo == NULL )
606 /*****************************************************************************
607 * input_UnselectES: removes an ES from the list of selected ES
608 *****************************************************************************/
609 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
616 msg_Err( p_input, "nothing to do in input_UnselectES" );
620 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
622 if( p_es->p_decoder_fifo == NULL )
624 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
628 input_EndDecoder( p_input, p_es );
631 if( ( p_es->p_decoder_fifo == NULL ) &&
632 ( p_input->stream.i_selected_es_number > 0 ) )
634 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
635 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
640 /* XXX: no need to memmove, we have unordered data */
641 REMOVE_ELEM( p_input->stream.pp_selected_es,
642 p_input->stream.i_selected_es_number,
645 if( p_input->stream.i_selected_es_number == 0 )
647 msg_Dbg( p_input, "no more selected ES" );