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.116 2003/07/30 21:09:06 gbazin Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <string.h> /* memcpy(), memset() */
32 #include "stream_control.h"
33 #include "input_ext-intf.h"
34 #include "input_ext-dec.h"
35 #include "input_ext-plugins.h"
38 * NOTICE : all of these functions expect you to have taken the lock on
39 * p_input->stream.lock
42 /* 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.pp_programs = NULL;
71 p_input->stream.p_selected_program = NULL;
72 p_input->stream.p_new_program = NULL;
76 if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
78 msg_Err( p_input, "out of memory" );
81 memset( p_input->stream.p_demux_data, 0, i_data_len );
85 p_input->stream.p_demux_data = NULL;
88 var_Create( p_input, "intf-change", VLC_VAR_BOOL );
89 val.b_bool = VLC_TRUE;
90 var_Set( p_input, "intf-change", val );
92 /* Create a few object variables used for navigation in the interfaces */
93 var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
94 text.psz_string = _("Program");
95 var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
97 var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
98 text.psz_string = _("Title");
99 var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
101 var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
102 text.psz_string = _("Chapter");
103 var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
105 var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
106 text.psz_string = _("Navigation");
107 var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
109 var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
110 text.psz_string = _("Video track");
111 var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
112 var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
113 text.psz_string = _("Audio track");
114 var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
115 var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
116 text.psz_string = _("Subtitles track");
117 var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
119 var_AddCallback( p_input, "program", ProgramCallback, NULL );
120 var_AddCallback( p_input, "title", TitleCallback, NULL );
121 var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
122 var_AddCallback( p_input, "video-es", ESCallback, NULL );
123 var_AddCallback( p_input, "audio-es", ESCallback, NULL );
124 var_AddCallback( p_input, "spu-es", ESCallback, NULL );
129 /*****************************************************************************
130 * input_EndStream: free all stream descriptors
131 *****************************************************************************/
132 void input_EndStream( input_thread_t * p_input )
134 /* Free all programs and associated ES, and associated decoders. */
135 while( p_input->stream.i_pgrm_number )
137 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
140 /* Free standalone ES */
141 while( p_input->stream.i_es_number )
143 input_DelES( p_input, p_input->stream.pp_es[0] );
147 while( p_input->stream.i_area_nb )
149 input_DelArea( p_input, p_input->stream.pp_areas[0] );
152 /* Free selected ES */
153 if( p_input->stream.pp_selected_es != NULL )
155 free( p_input->stream.pp_selected_es );
158 if( p_input->stream.p_demux_data != NULL )
160 free( p_input->stream.p_demux_data );
163 /* Free navigation variables */
164 var_Destroy( p_input, "program" );
165 var_Destroy( p_input, "title" );
166 var_Destroy( p_input, "chapter" );
167 var_Destroy( p_input, "video-es" );
168 var_Destroy( p_input, "audio-es" );
169 var_Destroy( p_input, "spu-es" );
170 var_Destroy( p_input, "intf-change" );
173 /*****************************************************************************
174 * input_FindProgram: returns a pointer to a program described by its ID
175 *****************************************************************************/
176 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
181 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
183 if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
185 return p_input->stream.pp_programs[i];
192 /*****************************************************************************
193 * input_AddProgram: add and init a program descriptor
194 *****************************************************************************
195 * This program descriptor will be referenced in the given stream descriptor
196 *****************************************************************************/
197 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
198 u16 i_pgrm_id, size_t i_data_len )
200 /* Where to add the pgrm */
201 pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
206 msg_Err( p_input, "out of memory" );
210 /* Init this entry */
211 p_pgrm->i_number = i_pgrm_id;
213 p_pgrm->i_version = 0;
215 p_pgrm->i_es_number = 0;
216 p_pgrm->pp_es = NULL;
218 input_ClockInit( p_pgrm );
220 p_pgrm->i_synchro_state = SYNCHRO_START;
224 p_pgrm->p_demux_data = malloc( i_data_len );
225 if( p_pgrm->p_demux_data == NULL )
227 msg_Err( p_input, "out of memory" );
230 memset( p_pgrm->p_demux_data, 0, i_data_len );
234 p_pgrm->p_demux_data = NULL;
237 /* Add an entry to the list of program associated with the stream */
238 INSERT_ELEM( p_input->stream.pp_programs,
239 p_input->stream.i_pgrm_number,
240 p_input->stream.i_pgrm_number,
243 val.i_int = i_pgrm_id;
244 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
249 /*****************************************************************************
250 * input_DelProgram: destroy a program descriptor
251 *****************************************************************************
252 * All ES descriptions referenced in the descriptor will be deleted.
253 *****************************************************************************/
254 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
256 unsigned int i_pgrm_index;
259 /* Find the program in the programs table */
260 for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
263 if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
267 /* If the program wasn't found, do nothing */
268 if( i_pgrm_index == p_input->stream.i_pgrm_number )
270 msg_Err( p_input, "program does not belong to this input" );
274 val.i_int = i_pgrm_index;
275 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
277 /* Free the structures that describe the es that belongs to that program */
278 while( p_pgrm->i_es_number )
280 input_DelES( p_input, p_pgrm->pp_es[0] );
283 /* Free the demux data */
284 if( p_pgrm->p_demux_data != NULL )
286 free( p_pgrm->p_demux_data );
289 /* Remove this program from the stream's list of programs */
290 REMOVE_ELEM( p_input->stream.pp_programs,
291 p_input->stream.i_pgrm_number,
294 /* Free the description of this program */
298 /*****************************************************************************
299 * input_AddArea: add and init an area descriptor
300 *****************************************************************************
301 * This area descriptor will be referenced in the given stream descriptor
302 *****************************************************************************/
303 input_area_t * input_AddArea( input_thread_t * p_input,
304 uint16_t i_area_id, uint16_t i_part_nb )
306 /* Where to add the pgrm */
307 input_area_t * p_area = malloc( sizeof(input_area_t) );
313 msg_Err( p_input, "out of memory" );
317 /* Init this entry */
318 p_area->i_id = i_area_id;
319 p_area->i_part_nb = i_part_nb;
324 p_area->i_seek = NO_SEEK;
326 /* Add an entry to the list of program associated with the stream */
327 INSERT_ELEM( p_input->stream.pp_areas,
328 p_input->stream.i_area_nb,
329 p_input->stream.i_area_nb,
332 /* Don't add empty areas */
336 /* Take care of the navigation variables */
337 val.i_int = i_area_id;
338 var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
340 val.psz_string = malloc( sizeof("title ") + 5 );
343 vlc_value_t val2, text, text2;
345 sprintf( val.psz_string, "title %2i", i_area_id );
346 var_Destroy( p_input, val.psz_string );
347 var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
348 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
349 var_AddCallback( p_input, val.psz_string, NavigationCallback,
350 (void *)(int)i_area_id );
352 text.psz_string = malloc( strlen( _("Title %i") ) + 20 );
353 if( text.psz_string )
354 sprintf( text.psz_string, _("Title %i"), i_area_id );
356 var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, &text );
358 if( text.psz_string ) free( text.psz_string );
360 text2.psz_string = malloc( strlen( _("Chapter %i") ) + 20 );
362 for( i = 1; i <= i_part_nb; i++ )
366 if( text2.psz_string )
367 sprintf( text2.psz_string, _("Chapter %i"), i );
369 var_Change( p_input, val.psz_string,
370 VLC_VAR_ADDCHOICE, &val2, &text2 );
373 if( text2.psz_string ) free( text2.psz_string );
376 if( p_input->stream.i_area_nb == 2 )
380 /* Add another bunch of navigation object variables */
381 var_Create( p_input, "next-title", VLC_VAR_VOID );
382 text.psz_string = _("Next title");
383 var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
384 var_Create( p_input, "prev-title", VLC_VAR_VOID );
385 text.psz_string = _("Previous title");
386 var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
387 var_AddCallback( p_input, "next-title", TitleCallback, NULL );
388 var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
390 var_Create( p_input, "next-chapter", VLC_VAR_VOID );
391 text.psz_string = _("Next Chapter");
392 var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
393 var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
394 text.psz_string = _("Previous Chapter");
395 var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
396 var_AddCallback( p_input, "next-chapter", ChapterCallback, NULL );
397 var_AddCallback( p_input, "prev-chapter", ChapterCallback, NULL );
403 /*****************************************************************************
404 * input_SetProgram: changes the current program
405 *****************************************************************************/
406 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
408 unsigned int i_es_index;
409 int i_required_audio_es;
410 int i_required_spu_es;
415 if ( p_input->stream.p_selected_program )
417 for ( i_es_index = 1 ; /* 0 should be the PMT */
418 i_es_index < p_input->stream.p_selected_program->
422 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
423 if ( p_es->p_decoder_fifo ) /* if the ES was selected */
425 input_UnselectES( p_input , p_es );
431 /* Get the number of the required audio stream */
432 var_Get( p_input, "audio", &val );
435 /* Default is the first one */
436 var_Get( p_input, "audio-channel", &val );
437 i_required_audio_es = val.i_int;
438 if( i_required_audio_es < 0 )
440 i_required_audio_es = 1;
445 i_required_audio_es = 0;
448 /* Same thing for subtitles */
449 var_Get( p_input, "video", &val );
452 /* for spu, default is none */
453 var_Get( p_input, "spu-channel", &val );
454 i_required_spu_es = val.i_int;
455 if( i_required_spu_es < 0 )
457 i_required_spu_es = 0;
462 i_required_spu_es = 0;
465 for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
467 switch( p_new_prg->pp_es[i_es_index]->i_cat )
470 msg_Dbg( p_input, "selecting ES %x",
471 p_new_prg->pp_es[i_es_index]->i_id );
472 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
476 if( i_audio_es <= i_required_audio_es )
478 msg_Dbg( p_input, "selecting ES %x",
479 p_new_prg->pp_es[i_es_index]->i_id );
480 input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
483 /* Not sure this one is fully specification-compliant */
486 if( i_spu_es <= i_required_spu_es )
488 msg_Dbg( p_input, "selecting 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] );
494 msg_Dbg( p_input, "ES %x has unknown type",
495 p_new_prg->pp_es[i_es_index]->i_id );
502 p_input->stream.p_selected_program = p_new_prg;
504 /* Update the navigation variables without triggering a callback */
505 val.i_int = p_new_prg->i_number;
506 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
511 /*****************************************************************************
512 * input_DelArea: destroy a area descriptor
513 *****************************************************************************
514 * All ES descriptions referenced in the descriptor will be deleted.
515 *****************************************************************************/
516 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
518 unsigned int i_area_index;
521 /* Find the area in the areas table */
522 for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
525 if( p_input->stream.pp_areas[i_area_index] == p_area )
529 /* If the area wasn't found, do nothing */
530 if( i_area_index == p_input->stream.i_area_nb )
532 msg_Err( p_input, "area does not belong to this input" );
536 /* Take care of the navigation variables */
537 val.psz_string = malloc( sizeof("title ") + 5 );
540 sprintf( val.psz_string, "title %i", p_area->i_id );
541 var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
542 var_Destroy( p_input, val.psz_string );
545 /* Remove this area from the stream's list of areas */
546 REMOVE_ELEM( p_input->stream.pp_areas,
547 p_input->stream.i_area_nb,
550 /* Free the description of this area */
553 if( p_input->stream.i_area_nb == 1 )
555 /* Del unneeded navigation object variables */
556 var_Destroy( p_input, "next-title" );
557 var_Destroy( p_input, "prev-title" );
558 var_Destroy( p_input, "next-chapter" );
559 var_Destroy( p_input, "prev-chapter" );
564 /*****************************************************************************
565 * input_FindES: returns a pointer to an ES described by its ID
566 *****************************************************************************/
567 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
571 for( i = 0; i < p_input->stream.i_es_number; i++ )
573 if( p_input->stream.pp_es[i]->i_id == i_es_id )
575 return p_input->stream.pp_es[i];
582 /*****************************************************************************
584 *****************************************************************************
585 * Reserve a slot in the table of ES descriptors for the ES and add it to the
586 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
588 *****************************************************************************/
589 es_descriptor_t * input_AddES( input_thread_t * p_input,
590 pgrm_descriptor_t * p_pgrm, u16 i_es_id,
591 int i_category, char const *psz_desc,
594 es_descriptor_t * p_es;
595 vlc_value_t val, text;
596 char *psz_var = NULL;
598 p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
601 msg_Err( p_input, "out of memory" );
605 INSERT_ELEM( p_input->stream.pp_es,
606 p_input->stream.i_es_number,
607 p_input->stream.i_es_number,
610 /* Init its values */
611 p_es->i_id = i_es_id;
613 p_es->p_decoder_fifo = NULL;
614 p_es->i_cat = i_category;
615 p_es->i_demux_fd = 0;
617 p_es->c_invalid_packets = 0;
618 p_es->b_force_decoder = VLC_FALSE;
622 p_es->p_demux_data = malloc( i_data_len );
623 if( p_es->p_demux_data == NULL )
625 msg_Err( p_input, "out of memory" );
628 memset( p_es->p_demux_data, 0, i_data_len );
632 p_es->p_demux_data = NULL;
634 p_es->p_waveformatex = NULL;
635 p_es->p_bitmapinfoheader = NULL;
637 /* Add this ES to the program definition if one is given */
640 INSERT_ELEM( p_pgrm->pp_es,
644 p_es->p_pgrm = p_pgrm;
654 psz_var = "audio-es";
660 psz_var = "video-es";
666 /* Get the number of ES already added */
667 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
672 /* First one, we need to add the "Disable" choice */
673 val2.i_int = -1; text.psz_string = _("Disable");
674 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
678 /* Take care of the ES description */
679 if( psz_desc && *psz_desc )
681 p_es->psz_desc = strdup( psz_desc );
685 p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
687 sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
690 val.i_int = p_es->i_id;
691 text.psz_string = p_es->psz_desc;
692 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
694 else p_es->psz_desc = NULL;
699 /*****************************************************************************
701 *****************************************************************************/
702 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
704 unsigned int i_index, i_es_index;
705 pgrm_descriptor_t * p_pgrm;
706 char * psz_var = NULL;
709 /* Find the ES in the ES table */
710 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
713 if( p_input->stream.pp_es[i_es_index] == p_es )
717 /* If the ES wasn't found, do nothing */
718 if( i_es_index == p_input->stream.i_es_number )
720 msg_Err( p_input, "ES does not belong to this input" );
724 /* Remove es from its associated variable */
725 switch( p_es->i_cat )
728 psz_var = "audio-es";
734 psz_var = "video-es";
740 val.i_int = p_es->i_id;
741 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
743 /* Remove the "Disable" entry if needed */
744 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
748 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
752 /* Kill associated decoder, if any. */
753 if( p_es->p_decoder_fifo != NULL )
755 input_UnselectES( p_input, p_es );
758 /* Remove this ES from the description of the program if it is associated
760 p_pgrm = p_es->p_pgrm;
763 for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
765 if( p_pgrm->pp_es[i_index] == p_es )
767 REMOVE_ELEM( p_pgrm->pp_es,
775 /* Free the demux data */
776 if( p_es->p_demux_data != NULL )
778 free( p_es->p_demux_data );
780 if( p_es->p_waveformatex )
782 free( p_es->p_waveformatex );
784 if( p_es->p_bitmapinfoheader )
786 free( p_es->p_bitmapinfoheader );
789 /* Free the description string */
790 if( p_es->psz_desc != NULL )
792 free( p_es->psz_desc );
795 /* Find the ES in the ES table */
796 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
799 if( p_input->stream.pp_es[i_es_index] == p_es )
803 /* Remove this ES from the stream's list of ES */
804 REMOVE_ELEM( p_input->stream.pp_es,
805 p_input->stream.i_es_number,
812 /*****************************************************************************
813 * input_SelectES: selects an ES and spawns the associated decoder
814 *****************************************************************************
815 * Remember we are still supposed to have stream_lock when entering this
817 *****************************************************************************/
818 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
821 char *psz_var = NULL;
825 msg_Err( p_input, "nothing to do in input_SelectES" );
829 if( p_es->i_cat == VIDEO_ES || p_es->i_cat == SPU_ES )
831 var_Get( p_input, "video", &val );
834 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
840 if( p_es->i_cat == AUDIO_ES )
842 var_Get( p_input, "audio", &val );
845 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
851 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
853 if( p_es->p_decoder_fifo != NULL )
855 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
859 /* Release the lock, not to block the input thread during
860 * the creation of the thread. */
861 vlc_mutex_unlock( &p_input->stream.stream_lock );
862 p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
863 vlc_mutex_lock( &p_input->stream.stream_lock );
865 if( p_es->p_decoder_fifo == NULL )
870 /* Update the es variable without triggering a callback */
871 switch( p_es->i_cat )
874 psz_var = "audio-es";
880 psz_var = "video-es";
886 val.i_int = p_es->i_id;
887 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
893 /*****************************************************************************
894 * input_UnselectES: removes an ES from the list of selected ES
895 *****************************************************************************/
896 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
898 unsigned int i_index = 0;
900 char *psz_var = NULL;
904 msg_Err( p_input, "nothing to do in input_UnselectES" );
908 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
910 if( p_es->p_decoder_fifo == NULL )
912 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
916 /* Update the es variable without triggering a callback */
917 switch( p_es->i_cat )
920 psz_var = "audio-es";
926 psz_var = "video-es";
933 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
936 /* Actually unselect the ES */
937 input_EndDecoder( p_input, p_es );
940 if( ( p_es->p_decoder_fifo == NULL ) &&
941 ( p_input->stream.i_selected_es_number > 0 ) )
943 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
944 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
949 /* XXX: no need to memmove, we have unsorted data */
950 REMOVE_ELEM( p_input->stream.pp_selected_es,
951 p_input->stream.i_selected_es_number,
954 if( p_input->stream.i_selected_es_number == 0 )
956 msg_Dbg( p_input, "no more selected ES" );
964 /*****************************************************************************
965 * Navigation callback: a bunch of navigation variables are used as an
966 * alternative to the navigation API.
967 *****************************************************************************/
968 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
969 vlc_value_t oldval, vlc_value_t newval, void *p_data )
971 input_thread_t *p_input = (input_thread_t *)p_this;
974 if( oldval.i_int == newval.i_int )
977 vlc_mutex_lock( &p_input->stream.stream_lock );
978 if( ( newval.i_int > 0 ) )
980 vlc_mutex_unlock( &p_input->stream.stream_lock );
981 input_ChangeProgram( p_input, (uint16_t)newval.i_int );
982 input_SetStatus( p_input, INPUT_STATUS_PLAY );
983 vlc_mutex_lock( &p_input->stream.stream_lock );
985 vlc_mutex_unlock( &p_input->stream.stream_lock );
987 val.b_bool = VLC_TRUE;
988 var_Set( p_input, "intf-change", val );
993 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
994 vlc_value_t oldval, vlc_value_t newval, void *p_data )
996 input_thread_t *p_input = (input_thread_t *)p_this;
997 input_area_t *p_area;
998 vlc_value_t val, val_list;
1001 if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
1002 else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
1004 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1006 /* Sanity check should have already been done by var_Set(). */
1007 vlc_mutex_lock( &p_input->stream.stream_lock );
1011 var_Get( p_this, "title", &newval );
1012 var_Change( p_this, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
1013 for( i = 0; i < val_list.p_list->i_count; i++ )
1015 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1016 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1018 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1022 var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
1025 p_area = p_input->stream.pp_areas[newval.i_int];
1028 vlc_mutex_unlock( &p_input->stream.stream_lock );
1030 input_ChangeArea( p_input, p_area );
1031 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1033 val.b_bool = VLC_TRUE;
1034 var_Set( p_input, "intf-change", val );
1039 static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
1040 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1042 input_thread_t *p_input = (input_thread_t *)p_this;
1043 input_area_t *p_area;
1044 vlc_value_t val, val_list;
1047 if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
1048 else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
1050 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1052 /* Sanity check should have already been done by var_Set(). */
1053 vlc_mutex_lock( &p_input->stream.stream_lock );
1057 var_Get( p_this, "chapter", &newval );
1058 var_Change( p_this, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
1059 for( i = 0; i < val_list.p_list->i_count; i++ )
1061 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1062 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1064 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1068 var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
1071 p_area = p_input->stream.p_selected_area;
1072 p_input->stream.p_selected_area->i_part = newval.i_int;
1073 vlc_mutex_unlock( &p_input->stream.stream_lock );
1075 input_ChangeArea( p_input, p_area );
1076 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1078 val.b_bool = VLC_TRUE;
1079 var_Set( p_input, "intf-change", val );
1084 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
1085 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1087 input_thread_t *p_input = (input_thread_t *)p_this;
1088 uint16_t i_area_id = (int)p_data;
1091 vlc_mutex_lock( &p_input->stream.stream_lock );
1093 if( p_input->stream.p_selected_area->i_id == i_area_id &&
1094 oldval.i_int == newval.i_int )
1097 vlc_mutex_unlock( &p_input->stream.stream_lock );
1101 if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
1102 ( (uint16_t)newval.i_int <=
1103 p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
1105 input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
1106 p_area->i_part = newval.i_int;
1107 vlc_mutex_unlock( &p_input->stream.stream_lock );
1108 input_ChangeArea( p_input, p_area );
1109 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1110 vlc_mutex_lock( &p_input->stream.stream_lock );
1112 vlc_mutex_unlock( &p_input->stream.stream_lock );
1114 val.b_bool = VLC_TRUE;
1115 var_Set( p_input, "intf-change", val );
1120 static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
1121 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1123 input_thread_t *p_input = (input_thread_t *)p_this;
1127 vlc_mutex_lock( &p_input->stream.stream_lock );
1129 /* Unselect old ES */
1130 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1132 if( p_input->stream.pp_es[i]->i_id == oldval.i_int &&
1133 p_input->stream.pp_es[i]->p_decoder_fifo != NULL )
1135 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1140 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1142 if( p_input->stream.pp_es[i]->i_id == newval.i_int &&
1143 p_input->stream.pp_es[i]->p_decoder_fifo == NULL )
1145 input_SelectES( p_input, p_input->stream.pp_es[i] );
1149 vlc_mutex_unlock( &p_input->stream.stream_lock );
1151 val.b_bool = VLC_TRUE;
1152 var_Set( p_input, "intf-change", val );