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.111 2003/05/15 21:31:53 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 );
100 var_Create( p_input, "next-title", VLC_VAR_VOID );
101 text.psz_string = _("Next title");
102 var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
103 var_Create( p_input, "prev-title", VLC_VAR_VOID );
104 text.psz_string = _("Previous title");
105 var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
107 var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
108 text.psz_string = _("Chapter");
109 var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
110 var_Create( p_input, "next-chapter", VLC_VAR_VOID );
111 text.psz_string = _("Next Chapter");
112 var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
113 var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
114 text.psz_string = _("Previous Chapter");
115 var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
117 var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
118 text.psz_string = _("Navigation");
119 var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
121 var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
122 text.psz_string = _("Video track");
123 var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
124 var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
125 text.psz_string = _("Audio track");
126 var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
127 var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
128 text.psz_string = _("Subtitles track");
129 var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
131 var_AddCallback( p_input, "program", ProgramCallback, NULL );
132 var_AddCallback( p_input, "title", TitleCallback, NULL );
133 var_AddCallback( p_input, "next-title", TitleCallback, NULL );
134 var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
135 var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
136 var_AddCallback( p_input, "next-chapter", ChapterCallback, NULL );
137 var_AddCallback( p_input, "prev-chapter", ChapterCallback, NULL );
138 var_AddCallback( p_input, "video-es", ESCallback, NULL );
139 var_AddCallback( p_input, "audio-es", ESCallback, NULL );
140 var_AddCallback( p_input, "spu-es", ESCallback, NULL );
145 /*****************************************************************************
146 * input_EndStream: free all stream descriptors
147 *****************************************************************************/
148 void input_EndStream( input_thread_t * p_input )
150 /* Free all programs and associated ES, and associated decoders. */
151 while( p_input->stream.i_pgrm_number )
153 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
156 /* Free standalone ES */
157 while( p_input->stream.i_es_number )
159 input_DelES( p_input, p_input->stream.pp_es[0] );
163 while( p_input->stream.i_area_nb )
165 input_DelArea( p_input, p_input->stream.pp_areas[0] );
168 /* Free selected ES */
169 if( p_input->stream.pp_selected_es != NULL )
171 free( p_input->stream.pp_selected_es );
174 if( p_input->stream.p_demux_data != NULL )
176 free( p_input->stream.p_demux_data );
179 /* Free navigation variables */
180 var_Destroy( p_input, "program" );
181 var_Destroy( p_input, "title" );
182 var_Destroy( p_input, "chapter" );
183 var_Destroy( p_input, "video-es" );
184 var_Destroy( p_input, "audio-es" );
185 var_Destroy( p_input, "spu-es" );
186 var_Destroy( p_input, "intf-change" );
189 /*****************************************************************************
190 * input_FindProgram: returns a pointer to a program described by its ID
191 *****************************************************************************/
192 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
197 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
199 if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
201 return p_input->stream.pp_programs[i];
208 /*****************************************************************************
209 * input_AddProgram: add and init a program descriptor
210 *****************************************************************************
211 * This program descriptor will be referenced in the given stream descriptor
212 *****************************************************************************/
213 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
214 u16 i_pgrm_id, size_t i_data_len )
216 /* Where to add the pgrm */
217 pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
222 msg_Err( p_input, "out of memory" );
226 /* Init this entry */
227 p_pgrm->i_number = i_pgrm_id;
229 p_pgrm->i_version = 0;
231 p_pgrm->i_es_number = 0;
232 p_pgrm->pp_es = NULL;
234 input_ClockInit( p_pgrm );
236 p_pgrm->i_synchro_state = SYNCHRO_START;
240 p_pgrm->p_demux_data = malloc( i_data_len );
241 if( p_pgrm->p_demux_data == NULL )
243 msg_Err( p_input, "out of memory" );
246 memset( p_pgrm->p_demux_data, 0, i_data_len );
250 p_pgrm->p_demux_data = NULL;
253 /* Add an entry to the list of program associated with the stream */
254 INSERT_ELEM( p_input->stream.pp_programs,
255 p_input->stream.i_pgrm_number,
256 p_input->stream.i_pgrm_number,
259 val.i_int = i_pgrm_id;
260 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
265 /*****************************************************************************
266 * input_DelProgram: destroy a program descriptor
267 *****************************************************************************
268 * All ES descriptions referenced in the descriptor will be deleted.
269 *****************************************************************************/
270 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
272 unsigned int i_pgrm_index;
275 /* Find the program in the programs table */
276 for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
279 if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
283 /* If the program wasn't found, do nothing */
284 if( i_pgrm_index == p_input->stream.i_pgrm_number )
286 msg_Err( p_input, "program does not belong to this input" );
290 val.i_int = i_pgrm_index;
291 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
293 /* Free the structures that describe the es that belongs to that program */
294 while( p_pgrm->i_es_number )
296 input_DelES( p_input, p_pgrm->pp_es[0] );
299 /* Free the demux data */
300 if( p_pgrm->p_demux_data != NULL )
302 free( p_pgrm->p_demux_data );
305 /* Remove this program from the stream's list of programs */
306 REMOVE_ELEM( p_input->stream.pp_programs,
307 p_input->stream.i_pgrm_number,
310 /* Free the description of this program */
314 /*****************************************************************************
315 * input_AddArea: add and init an area descriptor
316 *****************************************************************************
317 * This area descriptor will be referenced in the given stream descriptor
318 *****************************************************************************/
319 input_area_t * input_AddArea( input_thread_t * p_input,
320 uint16_t i_area_id, uint16_t i_part_nb )
322 /* Where to add the pgrm */
323 input_area_t * p_area = malloc( sizeof(input_area_t) );
329 msg_Err( p_input, "out of memory" );
333 /* Init this entry */
334 p_area->i_id = i_area_id;
335 p_area->i_part_nb = i_part_nb;
340 p_area->i_seek = NO_SEEK;
342 /* Add an entry to the list of program associated with the stream */
343 INSERT_ELEM( p_input->stream.pp_areas,
344 p_input->stream.i_area_nb,
345 p_input->stream.i_area_nb,
348 /* Don't add empty areas */
352 /* Take care of the navigation variables */
353 val.i_int = i_area_id;
354 var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
356 val.psz_string = malloc( sizeof("title ") + 5 );
361 sprintf( val.psz_string, "title %2i", i_area_id );
362 var_Destroy( p_input, val.psz_string );
363 var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
364 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
365 var_AddCallback( p_input, val.psz_string, NavigationCallback,
366 (void *)(int)i_area_id );
368 var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, NULL );
370 for( i = 1; i <= i_part_nb; i++ )
373 var_Change( p_input, val.psz_string,
374 VLC_VAR_ADDCHOICE, &val2, NULL );
381 /*****************************************************************************
382 * input_SetProgram: changes the current program
383 *****************************************************************************/
384 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
386 unsigned int i_es_index;
387 int i_required_audio_es;
388 int i_required_spu_es;
393 if ( p_input->stream.p_selected_program )
395 for ( i_es_index = 1 ; /* 0 should be the PMT */
396 i_es_index < p_input->stream.p_selected_program->
400 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
401 if ( p_es->p_decoder_fifo ) /* if the ES was selected */
403 input_UnselectES( p_input , p_es );
408 /* Get the number of the required audio stream */
409 if( config_GetInt( p_input, "audio" ) )
411 /* Default is the first one */
412 i_required_audio_es = config_GetInt( p_input, "audio-channel" );
413 if( i_required_audio_es < 0 )
415 i_required_audio_es = 1;
420 i_required_audio_es = 0;
423 /* Same thing for subtitles */
424 if( config_GetInt( p_input, "video" ) )
426 /* for spu, default is none */
427 i_required_spu_es = config_GetInt( p_input, "spu-channel" );
428 if( i_required_spu_es < 0 )
430 i_required_spu_es = 0;
435 i_required_spu_es = 0;
438 for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
440 switch( p_new_prg->pp_es[i_es_index]->i_cat )
443 msg_Dbg( p_input, "selecting ES %x",
444 p_new_prg->pp_es[i_es_index]->i_id );
445 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
449 if( i_audio_es <= i_required_audio_es )
451 msg_Dbg( p_input, "selecting ES %x",
452 p_new_prg->pp_es[i_es_index]->i_id );
453 input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
456 /* Not sure this one is fully specification-compliant */
459 if( i_spu_es <= i_required_spu_es )
461 msg_Dbg( p_input, "selecting ES %x",
462 p_new_prg->pp_es[i_es_index]->i_id );
463 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
467 msg_Dbg( p_input, "ES %x has unknown type",
468 p_new_prg->pp_es[i_es_index]->i_id );
475 p_input->stream.p_selected_program = p_new_prg;
477 /* Update the navigation variables without triggering a callback */
478 val.i_int = p_new_prg->i_number;
479 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
484 /*****************************************************************************
485 * input_DelArea: destroy a area descriptor
486 *****************************************************************************
487 * All ES descriptions referenced in the descriptor will be deleted.
488 *****************************************************************************/
489 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
491 unsigned int i_area_index;
494 /* Find the area in the areas table */
495 for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
498 if( p_input->stream.pp_areas[i_area_index] == p_area )
502 /* If the area wasn't found, do nothing */
503 if( i_area_index == p_input->stream.i_area_nb )
505 msg_Err( p_input, "area does not belong to this input" );
509 /* Take care of the navigation variables */
510 val.psz_string = malloc( sizeof("title ") + 5 );
513 sprintf( val.psz_string, "title %i", p_area->i_id );
514 var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
515 var_Destroy( p_input, val.psz_string );
518 /* Remove this area from the stream's list of areas */
519 REMOVE_ELEM( p_input->stream.pp_areas,
520 p_input->stream.i_area_nb,
523 /* Free the description of this area */
528 /*****************************************************************************
529 * input_FindES: returns a pointer to an ES described by its ID
530 *****************************************************************************/
531 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
535 for( i = 0; i < p_input->stream.i_es_number; i++ )
537 if( p_input->stream.pp_es[i]->i_id == i_es_id )
539 return p_input->stream.pp_es[i];
546 /*****************************************************************************
548 *****************************************************************************
549 * Reserve a slot in the table of ES descriptors for the ES and add it to the
550 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
552 *****************************************************************************/
553 es_descriptor_t * input_AddES( input_thread_t * p_input,
554 pgrm_descriptor_t * p_pgrm, u16 i_es_id,
555 int i_category, char const *psz_desc,
558 es_descriptor_t * p_es;
559 vlc_value_t val, text;
560 char *psz_var = NULL;
562 p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
565 msg_Err( p_input, "out of memory" );
569 INSERT_ELEM( p_input->stream.pp_es,
570 p_input->stream.i_es_number,
571 p_input->stream.i_es_number,
574 /* Init its values */
575 p_es->i_id = i_es_id;
577 p_es->p_decoder_fifo = NULL;
578 p_es->i_cat = i_category;
579 p_es->i_demux_fd = 0;
581 p_es->c_invalid_packets = 0;
582 p_es->b_force_decoder = VLC_FALSE;
586 p_es->p_demux_data = malloc( i_data_len );
587 if( p_es->p_demux_data == NULL )
589 msg_Err( p_input, "out of memory" );
592 memset( p_es->p_demux_data, 0, i_data_len );
596 p_es->p_demux_data = NULL;
598 p_es->p_waveformatex = NULL;
599 p_es->p_bitmapinfoheader = NULL;
601 /* Add this ES to the program definition if one is given */
604 INSERT_ELEM( p_pgrm->pp_es,
608 p_es->p_pgrm = p_pgrm;
618 psz_var = "audio-es";
624 psz_var = "video-es";
630 /* Get the number of ES already added */
631 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
636 /* First one, we need to add the "Disable" choice */
637 val2.i_int = -1; text.psz_string = _("Disable");
638 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
642 /* Take care of the ES description */
645 p_es->psz_desc = strdup( psz_desc );
649 p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
651 sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
654 val.i_int = p_es->i_id;
655 text.psz_string = p_es->psz_desc;
656 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
658 else p_es->psz_desc = NULL;
663 /*****************************************************************************
665 *****************************************************************************/
666 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
668 unsigned int i_index, i_es_index;
669 pgrm_descriptor_t * p_pgrm;
670 char * psz_var = NULL;
673 /* Find the ES in the ES table */
674 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
677 if( p_input->stream.pp_es[i_es_index] == p_es )
681 /* If the ES wasn't found, do nothing */
682 if( i_es_index == p_input->stream.i_es_number )
684 msg_Err( p_input, "ES does not belong to this input" );
688 /* Remove es from its associated variable */
689 switch( p_es->i_cat )
692 psz_var = "audio-es";
698 psz_var = "video-es";
704 val.i_int = p_es->i_id;
705 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
707 /* Remove the "Disable" entry if needed */
708 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
712 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
716 /* Kill associated decoder, if any. */
717 if( p_es->p_decoder_fifo != NULL )
719 input_EndDecoder( p_input, p_es );
722 /* Remove this ES from the description of the program if it is associated
724 p_pgrm = p_es->p_pgrm;
727 for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
729 if( p_pgrm->pp_es[i_index] == p_es )
731 REMOVE_ELEM( p_pgrm->pp_es,
739 /* Free the demux data */
740 if( p_es->p_demux_data != NULL )
742 free( p_es->p_demux_data );
744 if( p_es->p_waveformatex )
746 free( p_es->p_waveformatex );
748 if( p_es->p_bitmapinfoheader )
750 free( p_es->p_bitmapinfoheader );
753 /* Free the description string */
754 if( p_es->psz_desc != NULL )
756 free( p_es->psz_desc );
759 /* Find the ES in the ES table */
760 for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
763 if( p_input->stream.pp_es[i_es_index] == p_es )
767 /* Remove this ES from the stream's list of ES */
768 REMOVE_ELEM( p_input->stream.pp_es,
769 p_input->stream.i_es_number,
776 /*****************************************************************************
777 * input_SelectES: selects an ES and spawns the associated decoder
778 *****************************************************************************
779 * Remember we are still supposed to have stream_lock when entering this
781 *****************************************************************************/
782 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
785 char *psz_var = NULL;
789 msg_Err( p_input, "nothing to do in input_SelectES" );
793 if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
794 && !config_GetInt( p_input, "video" ) )
797 "video is disabled, not selecting ES 0x%x", p_es->i_id );
801 if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
804 "audio is disabled, not selecting ES 0x%x", p_es->i_id );
808 msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
810 if( p_es->p_decoder_fifo != NULL )
812 msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
816 /* Release the lock, not to block the input thread during
817 * the creation of the thread. */
818 vlc_mutex_unlock( &p_input->stream.stream_lock );
819 p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
820 vlc_mutex_lock( &p_input->stream.stream_lock );
822 if( p_es->p_decoder_fifo == NULL )
827 /* Update the es variable without triggering a callback */
828 switch( p_es->i_cat )
831 psz_var = "audio-es";
837 psz_var = "video-es";
843 val.i_int = p_es->i_id;
844 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
850 /*****************************************************************************
851 * input_UnselectES: removes an ES from the list of selected ES
852 *****************************************************************************/
853 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
855 unsigned int i_index = 0;
857 char *psz_var = NULL;
861 msg_Err( p_input, "nothing to do in input_UnselectES" );
865 msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
867 if( p_es->p_decoder_fifo == NULL )
869 msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
873 /* Update the es variable without triggering a callback */
874 switch( p_es->i_cat )
877 psz_var = "audio-es";
883 psz_var = "video-es";
890 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
893 /* Actually unselect the ES */
894 input_EndDecoder( p_input, p_es );
897 if( ( p_es->p_decoder_fifo == NULL ) &&
898 ( p_input->stream.i_selected_es_number > 0 ) )
900 while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
901 ( p_input->stream.pp_selected_es[i_index] != p_es ) )
906 /* XXX: no need to memmove, we have unsorted data */
907 REMOVE_ELEM( p_input->stream.pp_selected_es,
908 p_input->stream.i_selected_es_number,
911 if( p_input->stream.i_selected_es_number == 0 )
913 msg_Dbg( p_input, "no more selected ES" );
921 /*****************************************************************************
922 * Navigation callback: a bunch of navigation variables are used as an
923 * alternative to the navigation API.
924 *****************************************************************************/
925 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
926 vlc_value_t oldval, vlc_value_t newval, void *p_data )
928 input_thread_t *p_input = (input_thread_t *)p_this;
931 if( oldval.i_int == newval.i_int )
934 vlc_mutex_lock( &p_input->stream.stream_lock );
935 if( ( newval.i_int > 0 ) )
937 vlc_mutex_unlock( &p_input->stream.stream_lock );
938 input_ChangeProgram( p_input, (uint16_t)newval.i_int );
939 input_SetStatus( p_input, INPUT_STATUS_PLAY );
940 vlc_mutex_lock( &p_input->stream.stream_lock );
942 vlc_mutex_unlock( &p_input->stream.stream_lock );
944 val.b_bool = VLC_TRUE;
945 var_Set( p_input, "intf-change", val );
950 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
951 vlc_value_t oldval, vlc_value_t newval, void *p_data )
953 input_thread_t *p_input = (input_thread_t *)p_this;
954 input_area_t *p_area;
955 vlc_value_t val, val_list;
958 if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
959 else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
961 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
963 /* Sanity check should have already been done by var_Set(). */
964 vlc_mutex_lock( &p_input->stream.stream_lock );
968 var_Get( p_this, "title", &newval );
969 var_Change( p_this, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
970 for( i = 0; i < val_list.p_list->i_count; i++ )
972 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
973 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
975 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
979 var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
982 p_area = p_input->stream.pp_areas[newval.i_int];
985 vlc_mutex_unlock( &p_input->stream.stream_lock );
987 input_ChangeArea( p_input, p_area );
988 input_SetStatus( p_input, INPUT_STATUS_PLAY );
990 val.b_bool = VLC_TRUE;
991 var_Set( p_input, "intf-change", val );
996 static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
997 vlc_value_t oldval, vlc_value_t newval, void *p_data )
999 input_thread_t *p_input = (input_thread_t *)p_this;
1000 input_area_t *p_area;
1001 vlc_value_t val, val_list;
1004 if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
1005 else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
1007 if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1009 /* Sanity check should have already been done by var_Set(). */
1010 vlc_mutex_lock( &p_input->stream.stream_lock );
1014 var_Get( p_this, "chapter", &newval );
1015 var_Change( p_this, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
1016 for( i = 0; i < val_list.p_list->i_count; i++ )
1018 if( val_list.p_list->p_values[i].i_int == newval.i_int &&
1019 i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
1021 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1025 var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
1028 p_area = p_input->stream.p_selected_area;
1029 p_input->stream.p_selected_area->i_part = newval.i_int;
1030 vlc_mutex_unlock( &p_input->stream.stream_lock );
1032 input_ChangeArea( p_input, p_area );
1033 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1035 val.b_bool = VLC_TRUE;
1036 var_Set( p_input, "intf-change", val );
1041 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
1042 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1044 input_thread_t *p_input = (input_thread_t *)p_this;
1045 uint16_t i_area_id = (int)p_data;
1048 vlc_mutex_lock( &p_input->stream.stream_lock );
1050 if( p_input->stream.p_selected_area->i_id == i_area_id &&
1051 oldval.i_int == newval.i_int )
1054 vlc_mutex_unlock( &p_input->stream.stream_lock );
1058 if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
1059 ( (uint16_t)newval.i_int <=
1060 p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
1062 input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
1063 p_input->stream.p_selected_area->i_part = newval.i_int;
1064 vlc_mutex_unlock( &p_input->stream.stream_lock );
1065 input_ChangeArea( p_input, p_area );
1066 input_SetStatus( p_input, INPUT_STATUS_PLAY );
1067 vlc_mutex_lock( &p_input->stream.stream_lock );
1069 vlc_mutex_unlock( &p_input->stream.stream_lock );
1071 val.b_bool = VLC_TRUE;
1072 var_Set( p_input, "intf-change", val );
1077 static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
1078 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1080 input_thread_t *p_input = (input_thread_t *)p_this;
1084 vlc_mutex_lock( &p_input->stream.stream_lock );
1086 /* Unselect old ES */
1087 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1089 if( p_input->stream.pp_es[i]->i_id == oldval.i_int &&
1090 p_input->stream.pp_es[i]->p_decoder_fifo != NULL )
1092 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1097 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1099 if( p_input->stream.pp_es[i]->i_id == newval.i_int &&
1100 p_input->stream.pp_es[i]->p_decoder_fifo == NULL )
1102 input_SelectES( p_input, p_input->stream.pp_es[i] );
1106 vlc_mutex_unlock( &p_input->stream.stream_lock );
1108 val.b_bool = VLC_TRUE;
1109 var_Set( p_input, "intf-change", val );