1 /*****************************************************************************
2 * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
3 *****************************************************************************
4 * Copyright (C) 1999-2004 VideoLAN
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 /* Navigation callbacks */
43 static int ProgramCallback( vlc_object_t *, char const *,
44 vlc_value_t, vlc_value_t, void * );
45 static int TitleCallback( vlc_object_t *, char const *,
46 vlc_value_t, vlc_value_t, void * );
47 static int ChapterCallback( vlc_object_t *, char const *,
48 vlc_value_t, vlc_value_t, void * );
49 static int NavigationCallback( vlc_object_t *, char const *,
50 vlc_value_t, vlc_value_t, void * );
51 static int ESCallback( vlc_object_t *, char const *,
52 vlc_value_t, vlc_value_t, void * );
54 /*****************************************************************************
55 * input_InitStream: init the stream descriptor of the given input
56 *****************************************************************************/
57 int input_InitStream( input_thread_t * p_input, size_t i_data_len )
61 p_input->stream.i_stream_id = 0;
63 /* initialized to 0 since we don't give the signal to the interface
64 * before the end of input initialization */
65 p_input->stream.b_changed = 0;
66 p_input->stream.pp_es = NULL;
67 p_input->stream.pp_selected_es = NULL;
68 p_input->stream.p_removed_es = NULL;
69 p_input->stream.p_newly_selected_es = NULL;
70 p_input->stream.i_pgrm_number = 0;
71 p_input->stream.pp_programs = NULL;
72 p_input->stream.p_selected_program = NULL;
73 p_input->stream.p_new_program = NULL;
77 if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
79 msg_Err( p_input, "out of memory" );
82 memset( p_input->stream.p_demux_data, 0, i_data_len );
86 p_input->stream.p_demux_data = NULL;
89 var_Create( p_input, "intf-change", VLC_VAR_BOOL );
90 val.b_bool = VLC_TRUE;
91 var_Set( p_input, "intf-change", val );
93 /* Create a few object variables used for navigation in the interfaces */
94 var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
95 text.psz_string = _("Program");
96 var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
98 var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
99 text.psz_string = _("Title");
100 var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
102 var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
103 text.psz_string = _("Chapter");
104 var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
106 var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
107 text.psz_string = _("Navigation");
108 var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
110 var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
111 text.psz_string = _("Video Track");
112 var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
113 var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
114 text.psz_string = _("Audio Track");
115 var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
116 var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
117 text.psz_string = _("Subtitles Track");
118 var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
120 var_AddCallback( p_input, "program", ProgramCallback, NULL );
121 var_AddCallback( p_input, "title", TitleCallback, NULL );
122 var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
123 var_AddCallback( p_input, "video-es", ESCallback, NULL );
124 var_AddCallback( p_input, "audio-es", ESCallback, NULL );
125 var_AddCallback( p_input, "spu-es", ESCallback, NULL );
130 /*****************************************************************************
131 * input_EndStream: free all stream descriptors
132 *****************************************************************************/
133 void input_EndStream( input_thread_t * p_input )
135 /* Free all programs and associated ES, and associated decoders. */
136 while( p_input->stream.i_pgrm_number )
138 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
141 /* Free standalone ES */
142 while( p_input->stream.i_es_number )
144 input_DelES( p_input, p_input->stream.pp_es[0] );
148 while( p_input->stream.i_area_nb )
150 input_DelArea( p_input, p_input->stream.pp_areas[0] );
153 /* Free selected ES */
154 if( p_input->stream.pp_selected_es != NULL )
156 free( p_input->stream.pp_selected_es );
159 if( p_input->stream.p_demux_data != NULL )
161 free( p_input->stream.p_demux_data );
164 /* Free navigation variables */
165 var_Destroy( p_input, "program" );
166 var_Destroy( p_input, "title" );
167 var_Destroy( p_input, "chapter" );
168 var_Destroy( p_input, "video-es" );
169 var_Destroy( p_input, "audio-es" );
170 var_Destroy( p_input, "spu-es" );
171 var_Destroy( p_input, "intf-change" );
174 /*****************************************************************************
175 * input_FindProgram: returns a pointer to a program described by its ID
176 *****************************************************************************/
177 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
182 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
184 if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
186 return p_input->stream.pp_programs[i];
193 /*****************************************************************************
194 * input_AddProgram: add and init a program descriptor
195 *****************************************************************************
196 * This program descriptor will be referenced in the given stream descriptor
197 *****************************************************************************/
198 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
199 uint16_t i_pgrm_id, size_t i_data_len )
201 /* Where to add the pgrm */
202 pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
207 msg_Err( p_input, "out of memory" );
211 /* Init this entry */
212 p_pgrm->i_number = i_pgrm_id;
214 p_pgrm->i_version = 0;
216 p_pgrm->i_es_number = 0;
217 p_pgrm->pp_es = NULL;
219 input_ClockInit( p_pgrm );
221 p_pgrm->i_synchro_state = SYNCHRO_START;
225 p_pgrm->p_demux_data = malloc( i_data_len );
226 if( p_pgrm->p_demux_data == NULL )
228 msg_Err( p_input, "out of memory" );
231 memset( p_pgrm->p_demux_data, 0, i_data_len );
235 p_pgrm->p_demux_data = NULL;
238 /* Add an entry to the list of program associated with the stream */
239 INSERT_ELEM( p_input->stream.pp_programs,
240 p_input->stream.i_pgrm_number,
241 p_input->stream.i_pgrm_number,
244 val.i_int = i_pgrm_id;
245 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
250 /*****************************************************************************
251 * input_DelProgram: destroy a program descriptor
252 *****************************************************************************
253 * All ES descriptions referenced in the descriptor will be deleted.
254 *****************************************************************************/
255 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
257 unsigned int i_pgrm_index;
260 /* Find the program in the programs table */
261 for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
264 if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
268 /* If the program wasn't found, do nothing */
269 if( i_pgrm_index == p_input->stream.i_pgrm_number )
271 msg_Err( p_input, "program does not belong to this input" );
275 val.i_int = p_input->stream.pp_programs[i_pgrm_index]->i_number;
276 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
278 /* Free the structures that describe the es that belongs to that program */
279 while( p_pgrm->i_es_number )
281 input_DelES( p_input, p_pgrm->pp_es[0] );
284 /* Free the demux data */
285 if( p_pgrm->p_demux_data != NULL )
287 free( p_pgrm->p_demux_data );
290 /* Remove this program from the stream's list of programs */
291 REMOVE_ELEM( p_input->stream.pp_programs,
292 p_input->stream.i_pgrm_number,
295 if( p_pgrm == p_input->stream.p_selected_program )
296 p_input->stream.p_selected_program = NULL;
298 /* Free the description of this program */
302 /*****************************************************************************
303 * input_AddArea: add and init an area descriptor
304 *****************************************************************************
305 * This area descriptor will be referenced in the given stream descriptor
306 *****************************************************************************/
307 input_area_t * input_AddArea( input_thread_t * p_input,
308 uint16_t i_area_id, uint16_t i_part_nb )
310 /* Where to add the pgrm */
311 input_area_t * p_area = malloc( sizeof(input_area_t) );
317 msg_Err( p_input, "out of memory" );
321 /* Init this entry */
322 p_area->i_id = i_area_id;
323 p_area->i_part_nb = i_part_nb;
328 p_area->i_seek = NO_SEEK;
330 /* Add an entry to the list of program associated with the stream */
331 INSERT_ELEM( p_input->stream.pp_areas,
332 p_input->stream.i_area_nb,
333 p_input->stream.i_area_nb,
336 /* Don't add empty areas */
340 /* Take care of the navigation variables */
341 val.i_int = i_area_id;
342 var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
344 val.psz_string = malloc( sizeof("title ") + 5 );
347 vlc_value_t val2, text, text2;
349 sprintf( val.psz_string, "title %2i", i_area_id );
350 var_Destroy( p_input, val.psz_string );
351 var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
352 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
353 var_AddCallback( p_input, val.psz_string, NavigationCallback,
354 (void *)(int)i_area_id );
356 text.psz_string = malloc( strlen( _("Title %i") ) + 20 );
357 if( text.psz_string )
358 sprintf( text.psz_string, _("Title %i"), i_area_id );
360 var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, &text );
362 if( text.psz_string ) free( text.psz_string );
364 text2.psz_string = malloc( strlen( _("Chapter %i") ) + 20 );
366 for( i = 1; i <= i_part_nb; i++ )
370 if( text2.psz_string )
371 sprintf( text2.psz_string, _("Chapter %i"), i );
373 var_Change( p_input, val.psz_string,
374 VLC_VAR_ADDCHOICE, &val2, &text2 );
377 if( text2.psz_string ) free( text2.psz_string );
378 free( val.psz_string );
381 if( p_input->stream.i_area_nb == 2 )
385 /* Add another bunch of navigation object variables */
386 var_Create( p_input, "next-title", VLC_VAR_VOID );
387 text.psz_string = _("Next title");
388 var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
389 var_Create( p_input, "prev-title", VLC_VAR_VOID );
390 text.psz_string = _("Previous title");
391 var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
392 var_AddCallback( p_input, "next-title", TitleCallback, NULL );
393 var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
395 var_Create( p_input, "next-chapter", VLC_VAR_VOID );
396 text.psz_string = _("Next chapter");
397 var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
398 var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
399 text.psz_string = _("Previous chapter");
400 var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
401 var_AddCallback( p_input, "next-chapter", ChapterCallback, NULL );
402 var_AddCallback( p_input, "prev-chapter", ChapterCallback, NULL );
408 /*****************************************************************************
409 * input_SetProgram: changes the current program
410 *****************************************************************************/
411 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
413 unsigned int i_es_index;
414 int i_required_audio_es;
415 int i_required_spu_es;
420 if ( p_input->stream.p_selected_program )
422 for ( i_es_index = 1 ; /* 0 should be the PMT */
423 i_es_index < p_input->stream.p_selected_program->
427 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
428 if ( p_es->p_dec ) /* if the ES was selected */
430 input_UnselectES( p_input , p_es );
436 /* Get the number of the required audio stream */
437 var_Get( p_input, "audio", &val );
440 /* Default is the first one */
441 var_Get( p_input, "audio-channel", &val );
442 i_required_audio_es = val.i_int;
443 if( i_required_audio_es < 0 )
445 i_required_audio_es = 1;
450 i_required_audio_es = 0;
453 /* Same thing for subtitles */
454 var_Get( p_input, "video", &val );
457 /* for spu, default is none */
458 var_Get( p_input, "spu-channel", &val );
459 i_required_spu_es = val.i_int;
460 if( i_required_spu_es < 0 )
462 i_required_spu_es = 0;
467 i_required_spu_es = 0;
470 for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
472 switch( p_new_prg->pp_es[i_es_index]->i_cat )
475 msg_Dbg( p_input, "selecting video ES %x",
476 p_new_prg->pp_es[i_es_index]->i_id );
477 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
481 if( i_audio_es <= i_required_audio_es )
483 msg_Dbg( p_input, "selecting audio ES %x",
484 p_new_prg->pp_es[i_es_index]->i_id );
485 input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
488 /* Not sure this one is fully specification-compliant */
491 if( i_spu_es <= i_required_spu_es )
493 msg_Dbg( p_input, "selecting spu ES %x",
494 p_new_prg->pp_es[i_es_index]->i_id );
495 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
499 msg_Dbg( p_input, "ES %x has unknown type",
500 p_new_prg->pp_es[i_es_index]->i_id );
506 p_input->stream.p_selected_program = p_new_prg;
508 /* Update the navigation variables without triggering a callback */
509 val.i_int = p_new_prg->i_number;
510 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
515 /*****************************************************************************
516 * input_DelArea: destroy a area descriptor
517 *****************************************************************************
518 * All ES descriptions referenced in the descriptor will be deleted.
519 *****************************************************************************/
520 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
522 unsigned int i_area_index;
525 /* Find the area in the areas table */
526 for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
529 if( p_input->stream.pp_areas[i_area_index] == p_area )
533 /* If the area wasn't found, do nothing */
534 if( i_area_index == p_input->stream.i_area_nb )
536 msg_Err( p_input, "area does not belong to this input" );
540 /* Take care of the navigation variables */
541 val.psz_string = malloc( sizeof("title ") + 5 );
544 sprintf( val.psz_string, "title %i", p_area->i_id );
545 var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
546 var_Destroy( p_input, val.psz_string );
548 free( val.psz_string );
551 /* Remove this area from the stream's list of areas */
552 REMOVE_ELEM( p_input->stream.pp_areas,
553 p_input->stream.i_area_nb,
556 /* Free the description of this area */
559 if( p_input->stream.i_area_nb == 1 )
561 /* Del unneeded navigation object variables */
562 var_Destroy( p_input, "next-title" );
563 var_Destroy( p_input, "prev-title" );
564 var_Destroy( p_input, "next-chapter" );
565 var_Destroy( p_input, "prev-chapter" );
570 /*****************************************************************************
571 * input_FindES: returns a pointer to an ES described by its ID
572 *****************************************************************************/
573 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
577 for( i = 0; i < p_input->stream.i_es_number; i++ )
579 if( p_input->stream.pp_es[i]->i_id == i_es_id )
581 return p_input->stream.pp_es[i];
588 /*****************************************************************************
590 *****************************************************************************
591 * Reserve a slot in the table of ES descriptors for the ES and add it to the
592 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
594 *****************************************************************************/
595 es_descriptor_t * input_AddES( input_thread_t * p_input,
596 pgrm_descriptor_t * p_pgrm, uint16_t i_es_id,
597 int i_category, char const *psz_desc,
600 es_descriptor_t * p_es;
601 vlc_value_t val, text;
602 char *psz_var = NULL;
603 char *psz_type = NULL;
605 p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
608 msg_Err( p_input, "out of memory" );
612 INSERT_ELEM( p_input->stream.pp_es,
613 p_input->stream.i_es_number,
614 p_input->stream.i_es_number,
617 /* Init its values */
618 p_es->i_id = i_es_id;
619 p_es->i_stream_id = 0;
622 p_es->i_cat = i_category;
623 p_es->i_demux_fd = 0;
625 p_es->c_invalid_packets = 0;
626 p_es->b_force_decoder = VLC_FALSE;
627 es_format_Init( &p_es->fmt, UNKNOWN_ES, 0 );
628 p_es->fmt.b_packetized = VLC_FALSE; /* Only there for old mpeg demuxers */
632 p_es->p_demux_data = malloc( i_data_len );
633 if( p_es->p_demux_data == NULL )
635 msg_Err( p_input, "out of memory" );
638 memset( p_es->p_demux_data, 0, i_data_len );
642 p_es->p_demux_data = NULL;
644 p_es->p_waveformatex = NULL;
645 p_es->p_bitmapinfoheader = NULL;
646 p_es->p_spuinfo = NULL;
648 /* Add this ES to the program definition if one is given */
651 INSERT_ELEM( p_pgrm->pp_es,
655 p_es->p_pgrm = p_pgrm;
665 psz_var = "audio-es";
666 psz_type = _("audio");
670 psz_type = _("subtitle");
673 psz_var = "video-es";
674 psz_type = _("video");
677 psz_type = _("navigation");
680 psz_type = _("unknown");
683 psz_type = _("error");
687 /* Add stream info. */
689 input_info_category_t *p_cat;
690 char psz_streamid[TITLE_MAX];
692 snprintf(psz_streamid, TITLE_MAX, "%s%04x", _("Stream "), i_es_id);
693 p_cat = input_InfoCategory( p_input, psz_streamid );
694 input_AddInfo( p_cat, _("Type"), "%s", psz_type );
695 if ( psz_desc && *psz_desc )
696 input_AddInfo( p_cat, _("Description"), "%s", psz_desc );
701 /* Get the number of ES already added */
702 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
707 /* First one, we need to add the "Disable" choice */
708 val2.i_int = -1; text.psz_string = _("Disable");
709 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
713 /* Take care of the ES description */
714 if( psz_desc && *psz_desc )
716 p_es->psz_desc = strdup( psz_desc );
720 p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
722 sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
725 val.i_int = p_es->i_id;
726 text.psz_string = p_es->psz_desc;
727 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
729 else p_es->psz_desc = NULL;
734 /*****************************************************************************
736 *****************************************************************************/
737 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
739 unsigned int i_index, i_es_index;
740 pgrm_descriptor_t * p_pgrm;
741 char * psz_var = NULL;
744 /* Find the ES in the ES table */
745 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
748 if( p_input->stream.pp_es[i_es_index] == p_es )
752 /* If the ES wasn't found, do nothing */
753 if( i_es_index == p_input->stream.i_es_number )
755 msg_Err( p_input, "ES does not belong to this input" );
759 /* Remove es from its associated variable */
760 switch( p_es->i_cat )
763 psz_var = "audio-es";
769 psz_var = "video-es";
775 val.i_int = p_es->i_id;
776 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
778 /* Remove the "Disable" entry if needed */
779 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
783 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
787 /* Kill associated decoder, if any. */
788 if( p_es->p_dec != NULL )
790 input_UnselectES( p_input, p_es );
793 /* Remove this ES from the description of the program if it is associated
795 p_pgrm = p_es->p_pgrm;
798 for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
800 if( p_pgrm->pp_es[i_index] == p_es )
802 REMOVE_ELEM( p_pgrm->pp_es,
810 /* Free the demux data */
811 if( p_es->p_demux_data != NULL )
813 free( p_es->p_demux_data );
815 if( p_es->p_waveformatex )
817 free( p_es->p_waveformatex );
819 if( p_es->p_bitmapinfoheader )
821 free( p_es->p_bitmapinfoheader );
823 if( p_es->p_spuinfo )
825 free( p_es->p_spuinfo );
828 /* Free the description string */
829 if( p_es->psz_desc != NULL )
831 free( p_es->psz_desc );
834 /* Clean the es format */
835 es_format_Clean( &p_es->fmt );
837 /* Find the ES in the ES table */
838 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
841 if( p_input->stream.pp_es[i_es_index] == p_es )
845 /* Remove this ES from the stream's list of ES */
846 REMOVE_ELEM( p_input->stream.pp_es,
847 p_input->stream.i_es_number,
854 /*****************************************************************************
855 * input_SelectES: selects an ES and spawns the associated decoder
856 *****************************************************************************
857 * Remember we are still supposed to have stream_lock when entering this
859 *****************************************************************************/
860 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
863 char *psz_var = NULL;
867 msg_Err( p_input, "nothing to do in input_SelectES" );
871 if( p_es->i_cat == VIDEO_ES || p_es->i_cat == SPU_ES )
873 var_Get( p_input, "video", &val );
874 if( val.b_bool && p_input->stream.p_sout )
876 var_Get( p_input, "sout-video", &val );
880 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
886 if( p_es->i_cat == AUDIO_ES )
888 var_Get( p_input, "audio", &val );
889 if( val.b_bool && p_input->stream.p_sout )
891 var_Get( p_input, "sout-audio", &val );
895 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
901 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
903 if( p_es->p_dec != NULL )
905 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
909 /* Release the lock, not to block the input thread during
910 * the creation of the thread. */
911 vlc_mutex_unlock( &p_input->stream.stream_lock );
912 p_es->p_dec = input_RunDecoder( p_input, p_es );
913 vlc_mutex_lock( &p_input->stream.stream_lock );
915 if( p_es->p_dec == NULL )
920 /* Update the es variable without triggering a callback */
921 switch( p_es->i_cat )
924 psz_var = "audio-es";
930 psz_var = "video-es";
936 val.i_int = p_es->i_id;
937 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
943 /*****************************************************************************
944 * input_UnselectES: removes an ES from the list of selected ES
945 *****************************************************************************/
946 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
948 unsigned int i_index = 0;
950 char *psz_var = NULL;
954 msg_Err( p_input, "nothing to do in input_UnselectES" );
958 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
960 if( p_es->p_dec == NULL )
962 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
966 /* Update the es variable without triggering a callback */
967 switch( p_es->i_cat )
970 psz_var = "audio-es";
976 psz_var = "video-es";
983 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
986 /* Actually unselect the ES */
987 input_EndDecoder( p_input, p_es );
990 if( ( p_es->p_dec == NULL ) &&
991 ( p_input->stream.i_selected_es_number > 0 ) )
993 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
994 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
999 /* XXX: no need to memmove, we have unsorted data */
1000 REMOVE_ELEM( p_input->stream.pp_selected_es,
1001 p_input->stream.i_selected_es_number,
1004 if( p_input->stream.i_selected_es_number == 0 )
1006 msg_Dbg( p_input, "no more selected ES" );
1014 /*****************************************************************************
1015 * Navigation callback: a bunch of navigation variables are used as an
1016 * alternative to the navigation API.
1017 *****************************************************************************/
1018 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
1019 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1021 input_thread_t *p_input = (input_thread_t *)p_this;
1024 if( oldval.i_int == newval.i_int )
1027 vlc_mutex_lock( &p_input->stream.stream_lock );
1028 if( ( newval.i_int > 0 ) )
1030 vlc_mutex_unlock( &p_input->stream.stream_lock );
1031 input_ChangeProgram( p_input, (uint16_t)newval.i_int );
1032 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1033 vlc_mutex_lock( &p_input->stream.stream_lock );
1035 vlc_mutex_unlock( &p_input->stream.stream_lock );
1037 val.b_bool = VLC_TRUE;
1038 var_Set( p_input, "intf-change", val );
1043 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
1044 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1046 input_thread_t *p_input = (input_thread_t *)p_this;
1047 input_area_t *p_area;
1048 vlc_value_t val, val_list;
1051 if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
1052 else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
1054 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1056 /* Sanity check should have already been done by var_Set(). */
1057 vlc_mutex_lock( &p_input->stream.stream_lock );
1061 var_Get( p_this, "title", &newval );
1062 var_Change( p_this, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
1063 for( i = 0; i < val_list.p_list->i_count; i++ )
1065 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1066 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1068 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1072 var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
1075 p_area = p_input->stream.pp_areas[newval.i_int];
1078 vlc_mutex_unlock( &p_input->stream.stream_lock );
1080 input_ChangeArea( p_input, p_area );
1081 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1083 val.b_bool = VLC_TRUE;
1084 var_Set( p_input, "intf-change", val );
1089 static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
1090 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1092 input_thread_t *p_input = (input_thread_t *)p_this;
1093 input_area_t *p_area;
1094 vlc_value_t val, val_list;
1097 if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
1098 else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
1100 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1102 /* Sanity check should have already been done by var_Set(). */
1103 vlc_mutex_lock( &p_input->stream.stream_lock );
1107 var_Get( p_this, "chapter", &newval );
1108 var_Change( p_this, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
1109 for( i = 0; i < val_list.p_list->i_count; i++ )
1111 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1112 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1114 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1118 var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
1121 p_area = p_input->stream.p_selected_area;
1122 p_input->stream.p_selected_area->i_part = newval.i_int;
1123 vlc_mutex_unlock( &p_input->stream.stream_lock );
1125 input_ChangeArea( p_input, p_area );
1126 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1128 val.b_bool = VLC_TRUE;
1129 var_Set( p_input, "intf-change", val );
1134 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
1135 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1137 input_thread_t *p_input = (input_thread_t *)p_this;
1138 uint16_t i_area_id = (int)p_data;
1141 vlc_mutex_lock( &p_input->stream.stream_lock );
1143 if( p_input->stream.p_selected_area->i_id == i_area_id &&
1144 oldval.i_int == newval.i_int )
1147 vlc_mutex_unlock( &p_input->stream.stream_lock );
1151 if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
1152 ( (uint16_t)newval.i_int <=
1153 p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
1155 input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
1156 p_area->i_part = newval.i_int;
1157 vlc_mutex_unlock( &p_input->stream.stream_lock );
1158 input_ChangeArea( p_input, p_area );
1159 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1160 vlc_mutex_lock( &p_input->stream.stream_lock );
1162 vlc_mutex_unlock( &p_input->stream.stream_lock );
1164 val.b_bool = VLC_TRUE;
1165 var_Set( p_input, "intf-change", val );
1170 static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
1171 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1173 input_thread_t *p_input = (input_thread_t *)p_this;
1176 unsigned int i_cat = UNKNOWN_ES;
1177 es_descriptor_t *p_es = NULL;
1179 vlc_mutex_lock( &p_input->stream.stream_lock );
1181 /* First search old es type */
1182 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1184 if( p_input->stream.pp_es[i]->i_id == oldval.i_int )
1186 i_cat = p_input->stream.pp_es[i]->i_cat;
1190 /* Unselect all old ES */
1191 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1193 if( p_input->stream.pp_es[i]->i_cat == i_cat &&
1194 p_input->stream.pp_es[i]->i_id != newval.i_int &&
1195 p_input->stream.pp_es[i]->p_dec != NULL )
1197 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1202 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1204 if( p_input->stream.pp_es[i]->i_id == newval.i_int )
1206 p_es = p_input->stream.pp_es[i];
1207 if( p_es->p_dec == NULL )
1209 input_SelectES( p_input, p_es );
1216 /* Fix value (mainly for multiple selected ES */
1217 val.i_int = p_es->i_id;
1218 switch( p_es->i_cat )
1221 var_Change( p_input, "audio-es", VLC_VAR_SETVALUE, &val, NULL );
1224 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1227 var_Change( p_input, "video-es", VLC_VAR_SETVALUE, &val, NULL );
1232 vlc_mutex_unlock( &p_input->stream.stream_lock );
1234 val.b_bool = VLC_TRUE;
1235 var_Set( p_input, "intf-change", val );