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 | VLC_VAR_DOINHERIT );
96 text.psz_string = _("Program");
97 var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
99 var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
100 text.psz_string = _("Title");
101 var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
103 var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
104 text.psz_string = _("Chapter");
105 var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
107 var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
108 text.psz_string = _("Navigation");
109 var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
111 var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
112 text.psz_string = _("Video Track");
113 var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
114 var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
115 text.psz_string = _("Audio Track");
116 var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
117 var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
118 text.psz_string = _("Subtitles Track");
119 var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
121 var_AddCallback( p_input, "program", ProgramCallback, NULL );
122 var_AddCallback( p_input, "title", TitleCallback, NULL );
123 var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
124 var_AddCallback( p_input, "video-es", ESCallback, NULL );
125 var_AddCallback( p_input, "audio-es", ESCallback, NULL );
126 var_AddCallback( p_input, "spu-es", ESCallback, NULL );
131 /*****************************************************************************
132 * input_EndStream: free all stream descriptors
133 *****************************************************************************/
134 void input_EndStream( input_thread_t * p_input )
136 vlc_mutex_lock( &p_input->stream.stream_lock );
138 /* Free all programs and associated ES, and associated decoders. */
139 while( p_input->stream.i_pgrm_number )
141 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
144 /* Free standalone ES */
145 while( p_input->stream.i_es_number )
147 input_DelES( p_input, p_input->stream.pp_es[0] );
151 while( p_input->stream.i_area_nb )
153 input_DelArea( p_input, p_input->stream.pp_areas[0] );
156 /* Free selected ES */
157 if( p_input->stream.pp_selected_es != NULL )
159 free( p_input->stream.pp_selected_es );
162 if( p_input->stream.p_demux_data != NULL )
164 free( p_input->stream.p_demux_data );
167 vlc_mutex_unlock( &p_input->stream.stream_lock );
169 /* Free navigation variables */
170 var_Destroy( p_input, "program" );
171 var_Destroy( p_input, "title" );
172 var_Destroy( p_input, "chapter" );
173 var_Destroy( p_input, "video-es" );
174 var_Destroy( p_input, "audio-es" );
175 var_Destroy( p_input, "spu-es" );
176 var_Destroy( p_input, "intf-change" );
179 /*****************************************************************************
180 * input_FindProgram: returns a pointer to a program described by its ID
181 *****************************************************************************/
182 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
187 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
189 if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
191 return p_input->stream.pp_programs[i];
198 /*****************************************************************************
199 * input_AddProgram: add and init a program descriptor
200 *****************************************************************************
201 * This program descriptor will be referenced in the given stream descriptor
202 *****************************************************************************/
203 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
204 uint16_t i_pgrm_id, size_t i_data_len )
206 /* Where to add the pgrm */
207 pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
212 msg_Err( p_input, "out of memory" );
216 /* Init this entry */
217 p_pgrm->i_number = i_pgrm_id;
219 p_pgrm->i_version = 0;
221 p_pgrm->i_es_number = 0;
222 p_pgrm->pp_es = NULL;
224 input_ClockInit( p_pgrm );
226 p_pgrm->i_synchro_state = SYNCHRO_START;
230 p_pgrm->p_demux_data = malloc( i_data_len );
231 if( p_pgrm->p_demux_data == NULL )
233 msg_Err( p_input, "out of memory" );
236 memset( p_pgrm->p_demux_data, 0, i_data_len );
240 p_pgrm->p_demux_data = NULL;
243 /* Add an entry to the list of program associated with the stream */
244 INSERT_ELEM( p_input->stream.pp_programs,
245 p_input->stream.i_pgrm_number,
246 p_input->stream.i_pgrm_number,
249 val.i_int = i_pgrm_id;
250 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
255 /*****************************************************************************
256 * input_DelProgram: destroy a program descriptor
257 *****************************************************************************
258 * All ES descriptions referenced in the descriptor will be deleted.
259 *****************************************************************************/
260 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
262 unsigned int i_pgrm_index;
265 /* Find the program in the programs table */
266 for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
269 if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
273 /* If the program wasn't found, do nothing */
274 if( i_pgrm_index == p_input->stream.i_pgrm_number )
276 msg_Err( p_input, "program does not belong to this input" );
280 val.i_int = p_input->stream.pp_programs[i_pgrm_index]->i_number;
281 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
283 /* Free the structures that describe the es that belongs to that program */
284 while( p_pgrm->i_es_number )
286 input_DelES( p_input, p_pgrm->pp_es[0] );
289 /* Free the demux data */
290 if( p_pgrm->p_demux_data != NULL )
292 free( p_pgrm->p_demux_data );
295 /* Remove this program from the stream's list of programs */
296 REMOVE_ELEM( p_input->stream.pp_programs,
297 p_input->stream.i_pgrm_number,
300 if( p_pgrm == p_input->stream.p_selected_program )
301 p_input->stream.p_selected_program = NULL;
303 /* Free the description of this program */
307 /*****************************************************************************
308 * input_AddArea: add and init an area descriptor
309 *****************************************************************************
310 * This area descriptor will be referenced in the given stream descriptor
311 *****************************************************************************/
312 input_area_t * input_AddArea( input_thread_t * p_input,
313 uint16_t i_area_id, uint16_t i_part_nb )
315 /* Where to add the pgrm */
316 input_area_t * p_area = malloc( sizeof(input_area_t) );
322 msg_Err( p_input, "out of memory" );
326 /* Init this entry */
327 p_area->i_id = i_area_id;
328 p_area->i_part_nb = i_part_nb;
333 p_area->i_seek = NO_SEEK;
335 /* Add an entry to the list of program associated with the stream */
336 INSERT_ELEM( p_input->stream.pp_areas,
337 p_input->stream.i_area_nb,
338 p_input->stream.i_area_nb,
341 /* Don't add empty areas */
345 /* Take care of the navigation variables */
346 val.i_int = i_area_id;
347 var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
349 val.psz_string = malloc( sizeof("title ") + 5 );
352 vlc_value_t val2, text, text2;
354 sprintf( val.psz_string, "title %2i", i_area_id );
355 var_Destroy( p_input, val.psz_string );
356 var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
357 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
358 var_AddCallback( p_input, val.psz_string, NavigationCallback,
359 (void *)(int)i_area_id );
361 text.psz_string = malloc( strlen( _("Title %i") ) + 20 );
362 if( text.psz_string )
363 sprintf( text.psz_string, _("Title %i"), i_area_id );
365 var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, &text );
367 if( text.psz_string ) free( text.psz_string );
369 text2.psz_string = malloc( strlen( _("Chapter %i") ) + 20 );
371 for( i = 1; i <= i_part_nb; i++ )
375 if( text2.psz_string )
376 sprintf( text2.psz_string, _("Chapter %i"), i );
378 var_Change( p_input, val.psz_string,
379 VLC_VAR_ADDCHOICE, &val2, &text2 );
382 if( text2.psz_string ) free( text2.psz_string );
383 free( val.psz_string );
386 if( p_input->stream.i_area_nb == 2 )
390 /* Add another bunch of navigation object variables */
391 var_Create( p_input, "next-title", VLC_VAR_VOID );
392 text.psz_string = _("Next title");
393 var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
394 var_Create( p_input, "prev-title", VLC_VAR_VOID );
395 text.psz_string = _("Previous title");
396 var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
397 var_AddCallback( p_input, "next-title", TitleCallback, NULL );
398 var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
400 var_Create( p_input, "next-chapter", VLC_VAR_VOID );
401 text.psz_string = _("Next chapter");
402 var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
403 var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
404 text.psz_string = _("Previous chapter");
405 var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
406 var_AddCallback( p_input, "next-chapter", ChapterCallback, NULL );
407 var_AddCallback( p_input, "prev-chapter", ChapterCallback, NULL );
413 /*****************************************************************************
414 * input_SetProgram: changes the current program
415 *****************************************************************************/
416 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
418 unsigned int i_es_index;
419 int i_required_audio_es;
420 int i_required_spu_es;
425 if ( p_input->stream.p_selected_program )
427 for ( i_es_index = 1 ; /* 0 should be the PMT */
428 i_es_index < p_input->stream.p_selected_program->
432 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
433 if ( p_es->p_dec ) /* if the ES was selected */
435 input_UnselectES( p_input , p_es );
441 /* Get the number of the required audio stream */
442 var_Get( p_input, "audio", &val );
445 /* Default is the first one */
446 var_Get( p_input, "audio-channel", &val );
447 i_required_audio_es = val.i_int;
448 if( i_required_audio_es < 0 )
450 i_required_audio_es = 1;
455 i_required_audio_es = 0;
458 /* Same thing for subtitles */
459 var_Get( p_input, "video", &val );
462 /* for spu, default is none */
463 var_Get( p_input, "spu-channel", &val );
464 i_required_spu_es = val.i_int;
465 if( i_required_spu_es < 0 )
467 i_required_spu_es = 0;
472 i_required_spu_es = 0;
475 for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
477 switch( p_new_prg->pp_es[i_es_index]->i_cat )
480 msg_Dbg( p_input, "selecting video ES %x",
481 p_new_prg->pp_es[i_es_index]->i_id );
482 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
486 if( i_audio_es <= i_required_audio_es )
488 msg_Dbg( p_input, "selecting audio ES %x",
489 p_new_prg->pp_es[i_es_index]->i_id );
490 input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
493 /* Not sure this one is fully specification-compliant */
496 if( i_spu_es <= i_required_spu_es )
498 msg_Dbg( p_input, "selecting spu ES %x",
499 p_new_prg->pp_es[i_es_index]->i_id );
500 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
504 msg_Dbg( p_input, "ES %x has unknown type",
505 p_new_prg->pp_es[i_es_index]->i_id );
511 p_input->stream.p_selected_program = p_new_prg;
513 /* Update the navigation variables without triggering a callback */
514 val.i_int = p_new_prg->i_number;
515 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
520 /*****************************************************************************
521 * input_DelArea: destroy a area descriptor
522 *****************************************************************************
523 * All ES descriptions referenced in the descriptor will be deleted.
524 *****************************************************************************/
525 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
527 unsigned int i_area_index;
530 /* Find the area in the areas table */
531 for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
534 if( p_input->stream.pp_areas[i_area_index] == p_area )
538 /* If the area wasn't found, do nothing */
539 if( i_area_index == p_input->stream.i_area_nb )
541 msg_Err( p_input, "area does not belong to this input" );
545 /* Take care of the navigation variables */
546 val.psz_string = malloc( sizeof("title ") + 5 );
549 sprintf( val.psz_string, "title %i", p_area->i_id );
550 var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
551 var_Destroy( p_input, val.psz_string );
553 free( val.psz_string );
556 /* Remove this area from the stream's list of areas */
557 REMOVE_ELEM( p_input->stream.pp_areas,
558 p_input->stream.i_area_nb,
561 /* Free the description of this area */
564 if( p_input->stream.i_area_nb == 1 )
566 /* Del unneeded navigation object variables */
567 var_Destroy( p_input, "next-title" );
568 var_Destroy( p_input, "prev-title" );
569 var_Destroy( p_input, "next-chapter" );
570 var_Destroy( p_input, "prev-chapter" );
575 /*****************************************************************************
576 * input_FindES: returns a pointer to an ES described by its ID
577 *****************************************************************************/
578 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
582 for( i = 0; i < p_input->stream.i_es_number; i++ )
584 if( p_input->stream.pp_es[i]->i_id == i_es_id )
586 return p_input->stream.pp_es[i];
593 /*****************************************************************************
595 *****************************************************************************
596 * Reserve a slot in the table of ES descriptors for the ES and add it to the
597 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
599 *****************************************************************************/
600 es_descriptor_t * input_AddES( input_thread_t * p_input,
601 pgrm_descriptor_t * p_pgrm, uint16_t i_es_id,
602 int i_category, char const *psz_desc,
605 es_descriptor_t * p_es;
606 vlc_value_t val, text;
607 char *psz_var = NULL;
609 p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
612 msg_Err( p_input, "out of memory" );
616 INSERT_ELEM( p_input->stream.pp_es,
617 p_input->stream.i_es_number,
618 p_input->stream.i_es_number,
621 /* Init its values */
622 p_es->i_id = i_es_id;
623 p_es->i_stream_id = 0;
626 p_es->i_cat = i_category;
627 p_es->i_demux_fd = 0;
629 p_es->c_invalid_packets = 0;
630 p_es->b_force_decoder = VLC_FALSE;
631 es_format_Init( &p_es->fmt, UNKNOWN_ES, 0 );
632 p_es->fmt.b_packetized = VLC_FALSE; /* Only there for old mpeg demuxers */
636 p_es->p_demux_data = malloc( i_data_len );
637 if( p_es->p_demux_data == NULL )
639 msg_Err( p_input, "out of memory" );
642 memset( p_es->p_demux_data, 0, i_data_len );
646 p_es->p_demux_data = NULL;
648 p_es->p_waveformatex = NULL;
649 p_es->p_bitmapinfoheader = NULL;
650 p_es->p_spuinfo = NULL;
652 /* Add this ES to the program definition if one is given */
655 INSERT_ELEM( p_pgrm->pp_es,
659 p_es->p_pgrm = p_pgrm;
669 psz_var = "audio-es";
675 psz_var = "video-es";
681 /* Get the number of ES already added */
682 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
687 /* First one, we need to add the "Disable" choice */
688 val2.i_int = -1; text.psz_string = _("Disable");
689 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
693 /* Take care of the ES description */
694 if( psz_desc && *psz_desc )
696 p_es->psz_desc = strdup( psz_desc );
700 p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
702 sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
705 val.i_int = p_es->i_id;
706 text.psz_string = p_es->psz_desc;
707 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
709 else p_es->psz_desc = NULL;
714 /*****************************************************************************
716 *****************************************************************************/
717 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
719 unsigned int i_index, i_es_index;
720 pgrm_descriptor_t * p_pgrm;
721 char * psz_var = NULL;
724 /* Find the ES in the ES table */
725 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
728 if( p_input->stream.pp_es[i_es_index] == p_es )
732 /* If the ES wasn't found, do nothing */
733 if( i_es_index == p_input->stream.i_es_number )
735 msg_Err( p_input, "ES does not belong to this input" );
739 /* Remove es from its associated variable */
740 switch( p_es->i_cat )
743 psz_var = "audio-es";
749 psz_var = "video-es";
755 val.i_int = p_es->i_id;
756 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
758 /* Remove the "Disable" entry if needed */
759 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
763 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
767 /* Kill associated decoder, if any. */
768 if( p_es->p_dec != NULL )
770 input_UnselectES( p_input, p_es );
773 /* Remove this ES from the description of the program if it is associated
775 p_pgrm = p_es->p_pgrm;
778 for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
780 if( p_pgrm->pp_es[i_index] == p_es )
782 REMOVE_ELEM( p_pgrm->pp_es,
790 /* Free the demux data */
791 if( p_es->p_demux_data != NULL )
793 free( p_es->p_demux_data );
795 if( p_es->p_waveformatex )
797 free( p_es->p_waveformatex );
799 if( p_es->p_bitmapinfoheader )
801 free( p_es->p_bitmapinfoheader );
803 if( p_es->p_spuinfo )
805 free( p_es->p_spuinfo );
808 /* Free the description string */
809 if( p_es->psz_desc != NULL )
811 free( p_es->psz_desc );
814 /* Clean the es format */
815 es_format_Clean( &p_es->fmt );
817 /* Find the ES in the ES table */
818 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
821 if( p_input->stream.pp_es[i_es_index] == p_es )
825 /* Remove this ES from the stream's list of ES */
826 REMOVE_ELEM( p_input->stream.pp_es,
827 p_input->stream.i_es_number,
834 /*****************************************************************************
835 * input_SelectES: selects an ES and spawns the associated decoder
836 *****************************************************************************
837 * Remember we are still supposed to have stream_lock when entering this
839 *****************************************************************************/
840 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
843 char *psz_var = NULL;
847 msg_Err( p_input, "nothing to do in input_SelectES" );
851 if( p_es->i_cat == VIDEO_ES || p_es->i_cat == SPU_ES )
853 var_Get( p_input, "video", &val );
854 if( val.b_bool && p_input->stream.p_sout )
856 var_Get( p_input, "sout-video", &val );
860 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
866 if( p_es->i_cat == AUDIO_ES )
868 var_Get( p_input, "audio", &val );
869 if( val.b_bool && p_input->stream.p_sout )
871 var_Get( p_input, "sout-audio", &val );
875 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
881 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
883 if( p_es->p_dec != NULL )
885 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
889 /* Release the lock, not to block the input thread during
890 * the creation of the thread. */
891 vlc_mutex_unlock( &p_input->stream.stream_lock );
892 p_es->p_dec = input_RunDecoder( p_input, p_es );
893 vlc_mutex_lock( &p_input->stream.stream_lock );
895 if( p_es->p_dec == NULL )
900 /* Update the es variable without triggering a callback */
901 switch( p_es->i_cat )
904 psz_var = "audio-es";
910 psz_var = "video-es";
916 val.i_int = p_es->i_id;
917 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
923 /*****************************************************************************
924 * input_UnselectES: removes an ES from the list of selected ES
925 *****************************************************************************/
926 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
928 unsigned int i_index = 0;
930 char *psz_var = NULL;
934 msg_Err( p_input, "nothing to do in input_UnselectES" );
938 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
940 if( p_es->p_dec == NULL )
942 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
946 /* Update the es variable without triggering a callback */
947 switch( p_es->i_cat )
950 psz_var = "audio-es";
956 psz_var = "video-es";
963 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
966 /* FIXME: input_UnselectES() shouldn't actually be entered with the
967 * input lock, the locking should be done here and only where necessary. */
968 vlc_mutex_unlock( &p_input->stream.stream_lock );
969 /* Actually unselect the ES */
970 input_EndDecoder( p_input, p_es );
971 vlc_mutex_lock( &p_input->stream.stream_lock );
975 if( ( p_es->p_dec == NULL ) &&
976 ( p_input->stream.i_selected_es_number > 0 ) )
978 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
979 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
984 /* XXX: no need to memmove, we have unsorted data */
985 REMOVE_ELEM( p_input->stream.pp_selected_es,
986 p_input->stream.i_selected_es_number,
989 if( p_input->stream.i_selected_es_number == 0 )
991 msg_Dbg( p_input, "no more selected ES" );
999 /*****************************************************************************
1000 * Navigation callback: a bunch of navigation variables are used as an
1001 * alternative to the navigation API.
1002 *****************************************************************************/
1003 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
1004 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1006 input_thread_t *p_input = (input_thread_t *)p_this;
1009 if( oldval.i_int == newval.i_int )
1012 vlc_mutex_lock( &p_input->stream.stream_lock );
1013 if( ( newval.i_int > 0 ) )
1015 vlc_mutex_unlock( &p_input->stream.stream_lock );
1016 input_ChangeProgram( p_input, (uint16_t)newval.i_int );
1017 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1018 vlc_mutex_lock( &p_input->stream.stream_lock );
1020 vlc_mutex_unlock( &p_input->stream.stream_lock );
1022 val.b_bool = VLC_TRUE;
1023 var_Set( p_input, "intf-change", val );
1028 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
1029 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1031 input_thread_t *p_input = (input_thread_t *)p_this;
1032 input_area_t *p_area;
1033 vlc_value_t val, val_list;
1036 if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
1037 else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
1039 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1041 /* Sanity check should have already been done by var_Set(). */
1042 vlc_mutex_lock( &p_input->stream.stream_lock );
1046 var_Get( p_this, "title", &newval );
1047 var_Change( p_this, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
1048 for( i = 0; i < val_list.p_list->i_count; i++ )
1050 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1051 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1053 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1057 var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
1060 p_area = p_input->stream.pp_areas[newval.i_int];
1063 vlc_mutex_unlock( &p_input->stream.stream_lock );
1065 input_ChangeArea( p_input, p_area );
1066 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1068 val.b_bool = VLC_TRUE;
1069 var_Set( p_input, "intf-change", val );
1074 static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
1075 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1077 input_thread_t *p_input = (input_thread_t *)p_this;
1078 input_area_t *p_area;
1079 vlc_value_t val, val_list;
1082 if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
1083 else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
1085 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1087 /* Sanity check should have already been done by var_Set(). */
1088 vlc_mutex_lock( &p_input->stream.stream_lock );
1092 var_Get( p_this, "chapter", &newval );
1093 var_Change( p_this, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
1094 for( i = 0; i < val_list.p_list->i_count; i++ )
1096 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1097 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1099 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1103 var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
1106 p_area = p_input->stream.p_selected_area;
1107 p_input->stream.p_selected_area->i_part = newval.i_int;
1108 vlc_mutex_unlock( &p_input->stream.stream_lock );
1110 input_ChangeArea( p_input, p_area );
1111 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1113 val.b_bool = VLC_TRUE;
1114 var_Set( p_input, "intf-change", val );
1119 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
1120 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1122 input_thread_t *p_input = (input_thread_t *)p_this;
1123 uint16_t i_area_id = (int)p_data;
1126 vlc_mutex_lock( &p_input->stream.stream_lock );
1128 if( p_input->stream.p_selected_area->i_id == i_area_id &&
1129 oldval.i_int == newval.i_int )
1132 vlc_mutex_unlock( &p_input->stream.stream_lock );
1136 if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
1137 ( (uint16_t)newval.i_int <=
1138 p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
1140 input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
1141 p_area->i_part = newval.i_int;
1142 vlc_mutex_unlock( &p_input->stream.stream_lock );
1143 input_ChangeArea( p_input, p_area );
1144 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1145 vlc_mutex_lock( &p_input->stream.stream_lock );
1147 vlc_mutex_unlock( &p_input->stream.stream_lock );
1149 val.b_bool = VLC_TRUE;
1150 var_Set( p_input, "intf-change", val );
1155 static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
1156 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1158 input_thread_t *p_input = (input_thread_t *)p_this;
1161 unsigned int i_cat = UNKNOWN_ES;
1162 es_descriptor_t *p_es = NULL;
1164 vlc_mutex_lock( &p_input->stream.stream_lock );
1166 /* First search old es type */
1167 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1169 if( p_input->stream.pp_es[i]->i_id == oldval.i_int )
1171 i_cat = p_input->stream.pp_es[i]->i_cat;
1175 /* Unselect all old ES */
1176 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1178 if( p_input->stream.pp_es[i]->i_cat == i_cat &&
1179 p_input->stream.pp_es[i]->i_id != newval.i_int &&
1180 p_input->stream.pp_es[i]->p_dec != NULL )
1182 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1187 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1189 if( p_input->stream.pp_es[i]->i_id == newval.i_int )
1191 p_es = p_input->stream.pp_es[i];
1192 if( p_es->p_dec == NULL )
1194 input_SelectES( p_input, p_es );
1201 /* Fix value (mainly for multiple selected ES */
1202 val.i_int = p_es->i_id;
1203 switch( p_es->i_cat )
1206 var_Change( p_input, "audio-es", VLC_VAR_SETVALUE, &val, NULL );
1209 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1212 var_Change( p_input, "video-es", VLC_VAR_SETVALUE, &val, NULL );
1217 vlc_mutex_unlock( &p_input->stream.stream_lock );
1219 val.b_bool = VLC_TRUE;
1220 var_Set( p_input, "intf-change", val );