b9cad54cbe9d93430c46544af77855d4fb80f12b
[vlc.git] / src / input / input_programs.c
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 $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>                                    /* memcpy(), memset() */
29
30 #include <vlc/vlc.h>
31
32 #include "stream_control.h"
33 #include "input_ext-intf.h"
34 #include "input_ext-dec.h"
35 #include "input_ext-plugins.h"
36
37 /*
38  * NOTICE : all of these functions expect you to have taken the lock on
39  * p_input->stream.lock
40  */
41
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 * );
53
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 )
58 {
59     vlc_value_t text,val;
60
61     p_input->stream.i_stream_id = 0;
62
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;
73
74     if( i_data_len )
75     {
76         if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
77         {
78             msg_Err( p_input, "out of memory" );
79             return 1;
80         }
81         memset( p_input->stream.p_demux_data, 0, i_data_len );
82     }
83     else
84     {
85         p_input->stream.p_demux_data = NULL;
86     }
87     
88     var_Create( p_input, "intf-change", VLC_VAR_BOOL );
89     val.b_bool = VLC_TRUE;
90     var_Set( p_input, "intf-change", val );
91
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 );
96
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 );
106
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 );
116
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 );
120
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 );
130
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 );
141
142     return 0;
143 }
144
145 /*****************************************************************************
146  * input_EndStream: free all stream descriptors
147  *****************************************************************************/
148 void input_EndStream( input_thread_t * p_input )
149 {
150     /* Free all programs and associated ES, and associated decoders. */
151     while( p_input->stream.i_pgrm_number )
152     {
153         input_DelProgram( p_input, p_input->stream.pp_programs[0] );
154     }
155
156     /* Free standalone ES */
157     while( p_input->stream.i_es_number )
158     {
159         input_DelES( p_input, p_input->stream.pp_es[0] );
160     }
161
162     /* Free all areas */
163     while( p_input->stream.i_area_nb )
164     {
165         input_DelArea( p_input, p_input->stream.pp_areas[0] );
166     }
167
168     /* Free selected ES */
169     if( p_input->stream.pp_selected_es != NULL )
170     {
171         free( p_input->stream.pp_selected_es );
172     }
173
174     if( p_input->stream.p_demux_data != NULL )
175     {
176         free( p_input->stream.p_demux_data );
177     }
178
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" );
187 }
188
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,
193                                        uint16_t i_pgrm_id )
194 {
195     unsigned int i;
196
197     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
198     {
199         if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
200         {
201             return p_input->stream.pp_programs[i];
202         }
203     }
204
205     return NULL;
206 }
207
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 )
215 {
216     /* Where to add the pgrm */
217     pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
218     vlc_value_t val;
219
220     if( p_pgrm == NULL )
221     {
222         msg_Err( p_input, "out of memory" );
223         return NULL;
224     }
225
226     /* Init this entry */
227     p_pgrm->i_number = i_pgrm_id;
228     p_pgrm->b_is_ok = 0;
229     p_pgrm->i_version = 0;
230
231     p_pgrm->i_es_number = 0;
232     p_pgrm->pp_es = NULL;
233
234     input_ClockInit( p_pgrm );
235
236     p_pgrm->i_synchro_state = SYNCHRO_START;
237
238     if( i_data_len )
239     {
240         p_pgrm->p_demux_data = malloc( i_data_len );
241         if( p_pgrm->p_demux_data == NULL )
242         {
243             msg_Err( p_input, "out of memory" );
244             return NULL;
245         }
246         memset( p_pgrm->p_demux_data, 0, i_data_len );
247     }
248     else
249     {
250         p_pgrm->p_demux_data = NULL;
251     }
252
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,
257                  p_pgrm );
258
259     val.i_int = i_pgrm_id;
260     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
261
262     return p_pgrm;
263 }
264
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 )
271 {
272     unsigned int i_pgrm_index;
273     vlc_value_t val;
274
275     /* Find the program in the programs table */
276     for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
277          i_pgrm_index++ )
278     {
279         if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
280             break;
281     }
282
283     /* If the program wasn't found, do nothing */
284     if( i_pgrm_index == p_input->stream.i_pgrm_number )
285     {
286         msg_Err( p_input, "program does not belong to this input" );
287         return;
288     }
289
290     val.i_int = i_pgrm_index;
291     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
292
293     /* Free the structures that describe the es that belongs to that program */
294     while( p_pgrm->i_es_number )
295     {
296         input_DelES( p_input, p_pgrm->pp_es[0] );
297     }
298
299     /* Free the demux data */
300     if( p_pgrm->p_demux_data != NULL )
301     {
302         free( p_pgrm->p_demux_data );
303     }
304
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,
308                  i_pgrm_index );
309
310     /* Free the description of this program */
311     free( p_pgrm );
312 }
313
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 )
321 {
322     /* Where to add the pgrm */
323     input_area_t * p_area = malloc( sizeof(input_area_t) );
324     vlc_value_t val;
325     int i;
326
327     if( p_area == NULL )
328     {
329         msg_Err( p_input, "out of memory" );
330         return NULL;
331     }
332
333     /* Init this entry */
334     p_area->i_id = i_area_id;
335     p_area->i_part_nb = i_part_nb;
336     p_area->i_part= 0;
337     p_area->i_start = 0;
338     p_area->i_size = 0;
339     p_area->i_tell = 0;
340     p_area->i_seek = NO_SEEK;
341
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,
346                  p_area );
347
348     /* Don't add empty areas */
349     if( i_part_nb == 0 )
350         return NULL;
351
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 );
355
356     val.psz_string = malloc( sizeof("title ") + 5 );
357     if( val.psz_string )
358     {
359         vlc_value_t val2;
360
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 );
367
368         var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, NULL );
369
370         for( i = 1; i <= i_part_nb; i++ )
371         {
372             val2.i_int = i;
373             var_Change( p_input, val.psz_string,
374                         VLC_VAR_ADDCHOICE, &val2, NULL );
375         }
376     }
377
378     return p_area;
379 }
380
381 /*****************************************************************************
382  * input_SetProgram: changes the current program
383  *****************************************************************************/
384 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
385 {
386     unsigned int i_es_index;
387     int i_required_audio_es;
388     int i_required_spu_es;
389     int i_audio_es = 0;
390     int i_spu_es = 0;
391     vlc_value_t val;
392
393     if ( p_input->stream.p_selected_program )
394     {
395         for ( i_es_index = 1 ; /* 0 should be the PMT */
396                 i_es_index < p_input->stream.p_selected_program->
397                 i_es_number ;
398                 i_es_index ++ )
399         {
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 */
402             {
403                 input_UnselectES( p_input , p_es );
404             }
405 #undef p_es
406         }
407     }
408     /* Get the number of the required audio stream */
409     if( config_GetInt( p_input, "audio" ) )
410     {
411         /* Default is the first one */
412         i_required_audio_es = config_GetInt( p_input, "audio-channel" );
413         if( i_required_audio_es < 0 )
414         {
415             i_required_audio_es = 1;
416         }
417     }
418     else
419     {
420         i_required_audio_es = 0;
421     }
422
423     /* Same thing for subtitles */
424     if( config_GetInt( p_input, "video" ) )
425     {
426         /* for spu, default is none */
427         i_required_spu_es = config_GetInt( p_input, "spu-channel" );
428         if( i_required_spu_es < 0 )
429         {
430             i_required_spu_es = 0;
431         }
432     }
433     else
434     {
435         i_required_spu_es = 0;
436     }
437
438     for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
439     {
440         switch( p_new_prg->pp_es[i_es_index]->i_cat )
441         {
442             case VIDEO_ES:
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] );
446                 break;
447             case AUDIO_ES:
448                 i_audio_es += 1;
449                 if( i_audio_es <= i_required_audio_es )
450                 {
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]);
454                 }
455                 break;
456             /* Not sure this one is fully specification-compliant */
457             case SPU_ES :
458                 i_spu_es += 1;
459                 if( i_spu_es <= i_required_spu_es )
460                 {
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] );
464                 }
465             break;
466             default :
467                 msg_Dbg( p_input, "ES %x has unknown type",
468                          p_new_prg->pp_es[i_es_index]->i_id );
469                 break;
470         }
471
472     }
473
474
475     p_input->stream.p_selected_program = p_new_prg;
476
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 );
480
481     return( 0 );
482 }
483
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 )
490 {
491     unsigned int i_area_index;
492     vlc_value_t val;
493
494     /* Find the area in the areas table */
495     for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
496          i_area_index++ )
497     {
498         if( p_input->stream.pp_areas[i_area_index] == p_area )
499             break;
500     }
501
502     /* If the area wasn't found, do nothing */
503     if( i_area_index == p_input->stream.i_area_nb )
504     {
505         msg_Err( p_input, "area does not belong to this input" );
506         return;
507     }
508
509     /* Take care of the navigation variables */
510     val.psz_string = malloc( sizeof("title ") + 5 );
511     if( val.psz_string )
512     {
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 );
516     }
517
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,
521                  i_area_index );
522
523     /* Free the description of this area */
524     free( p_area );
525 }
526
527
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 )
532 {
533     unsigned int i;
534
535     for( i = 0; i < p_input->stream.i_es_number; i++ )
536     {
537         if( p_input->stream.pp_es[i]->i_id == i_es_id )
538         {
539             return p_input->stream.pp_es[i];
540         }
541     }
542
543     return NULL;
544 }
545
546 /*****************************************************************************
547  * input_AddES:
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
551  * alone (PSI ?)
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,
556                                size_t i_data_len )
557 {
558     es_descriptor_t * p_es;
559     vlc_value_t val, text;
560     char *psz_var = NULL;
561
562     p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
563     if( p_es == NULL )
564     {
565         msg_Err( p_input, "out of memory" );
566         return( NULL);
567     }
568
569     INSERT_ELEM( p_input->stream.pp_es,
570                  p_input->stream.i_es_number,
571                  p_input->stream.i_es_number,
572                  p_es );
573
574     /* Init its values */
575     p_es->i_id = i_es_id;
576     p_es->p_pes = NULL;
577     p_es->p_decoder_fifo = NULL;
578     p_es->i_cat = i_category;
579     p_es->i_demux_fd = 0;
580     p_es->c_packets = 0;
581     p_es->c_invalid_packets = 0;
582     p_es->b_force_decoder = VLC_FALSE;
583
584     if( i_data_len )
585     {
586         p_es->p_demux_data = malloc( i_data_len );
587         if( p_es->p_demux_data == NULL )
588         {
589             msg_Err( p_input, "out of memory" );
590             return( NULL );
591         }
592         memset( p_es->p_demux_data, 0, i_data_len );
593     }
594     else
595     {
596         p_es->p_demux_data = NULL;
597     }
598     p_es->p_waveformatex     = NULL;
599     p_es->p_bitmapinfoheader = NULL;
600
601     /* Add this ES to the program definition if one is given */
602     if( p_pgrm )
603     {
604         INSERT_ELEM( p_pgrm->pp_es,
605                      p_pgrm->i_es_number,
606                      p_pgrm->i_es_number,
607                      p_es );
608         p_es->p_pgrm = p_pgrm;
609     }
610     else
611     {
612         p_es->p_pgrm = NULL;
613     }
614
615     switch( i_category )
616     {
617     case AUDIO_ES:
618         psz_var = "audio-es";
619         break;
620     case SPU_ES:
621         psz_var = "spu-es";
622         break;
623     case VIDEO_ES:
624         psz_var = "video-es";
625         break;
626     }
627
628     if( psz_var )
629     {
630         /* Get the number of ES already added */
631         var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
632         if( val.i_int == 0 )
633         {
634             vlc_value_t val2;
635
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 );
639             val.i_int++;
640         }
641
642         /* Take care of the ES description */
643         if( psz_desc )
644         {
645             p_es->psz_desc = strdup( psz_desc );
646         }
647         else
648         {
649             p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
650             if( p_es->psz_desc )
651                 sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
652         }
653
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 );
657     }
658     else p_es->psz_desc = NULL;
659
660     return p_es;
661 }
662
663 /*****************************************************************************
664  * input_DelES:
665  *****************************************************************************/
666 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
667 {
668     unsigned int            i_index, i_es_index;
669     pgrm_descriptor_t *     p_pgrm;
670     char *                  psz_var = NULL;
671     vlc_value_t             val;
672
673     /* Find the ES in the ES table */
674     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
675          i_es_index++ )
676     {
677         if( p_input->stream.pp_es[i_es_index] == p_es )
678             break;
679     }
680
681     /* If the ES wasn't found, do nothing */
682     if( i_es_index == p_input->stream.i_es_number )
683     {
684         msg_Err( p_input, "ES does not belong to this input" );
685         return;
686     }
687
688     /* Remove es from its associated variable */
689     switch( p_es->i_cat )
690     {
691     case AUDIO_ES:
692         psz_var = "audio-es";
693         break;
694     case SPU_ES:
695         psz_var = "spu-es";
696         break;
697     case VIDEO_ES:
698         psz_var = "video-es";
699         break;
700     }
701
702     if( psz_var )
703     {
704         val.i_int = p_es->i_id;
705         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
706
707         /* Remove the "Disable" entry if needed */
708         var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
709         if( val.i_int == 1 )
710         {
711             val.i_int = -1;
712             var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
713         }
714     }
715
716     /* Kill associated decoder, if any. */
717     if( p_es->p_decoder_fifo != NULL )
718     {
719         input_EndDecoder( p_input, p_es );
720     }
721
722     /* Remove this ES from the description of the program if it is associated
723      * to one */
724     p_pgrm = p_es->p_pgrm;
725     if( p_pgrm )
726     {
727         for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
728         {
729             if( p_pgrm->pp_es[i_index] == p_es )
730             {
731                 REMOVE_ELEM( p_pgrm->pp_es,
732                              p_pgrm->i_es_number,
733                              i_index );
734                 break;
735             }
736         }
737     }
738
739     /* Free the demux data */
740     if( p_es->p_demux_data != NULL )
741     {
742         free( p_es->p_demux_data );
743     }
744     if( p_es->p_waveformatex )
745     {
746         free( p_es->p_waveformatex );
747     }
748     if( p_es->p_bitmapinfoheader )
749     {
750         free( p_es->p_bitmapinfoheader );
751     }
752
753     /* Free the description string */
754     if( p_es->psz_desc != NULL )
755     {
756         free( p_es->psz_desc );
757     }
758
759     /* Find the ES in the ES table */
760     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
761          i_es_index++ )
762     {
763         if( p_input->stream.pp_es[i_es_index] == p_es )
764             break;
765     }
766
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,
770                  i_es_index );
771
772     /* Free the ES */
773     free( p_es );
774 }
775
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
780  * function ?
781  *****************************************************************************/
782 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
783 {
784     vlc_value_t val;
785     char *psz_var = NULL;
786
787     if( p_es == NULL )
788     {
789         msg_Err( p_input, "nothing to do in input_SelectES" );
790         return -1;
791     }
792
793     if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
794         && !config_GetInt( p_input, "video" ) )
795     {
796         msg_Dbg( p_input,
797                  "video is disabled, not selecting ES 0x%x", p_es->i_id );
798         return -1;
799     }
800
801     if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
802     {
803         msg_Dbg( p_input,
804                  "audio is disabled, not selecting ES 0x%x", p_es->i_id );
805         return -1;
806     }
807
808     msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
809
810     if( p_es->p_decoder_fifo != NULL )
811     {
812         msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
813         return -1;
814     }
815
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 );
821
822     if( p_es->p_decoder_fifo == NULL )
823     {
824         return -1;
825     }
826
827     /* Update the es variable without triggering a callback */
828     switch( p_es->i_cat )
829     {
830     case AUDIO_ES:
831         psz_var = "audio-es";
832         break;
833     case SPU_ES:
834         psz_var = "spu-es";
835         break;
836     case VIDEO_ES:
837         psz_var = "video-es";
838         break;
839     }
840
841     if( psz_var )
842     {
843         val.i_int = p_es->i_id;
844         var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
845     }
846
847     return 0;
848 }
849
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 )
854 {
855     unsigned int i_index = 0;
856     vlc_value_t val;
857     char *psz_var = NULL;
858
859     if( p_es == NULL )
860     {
861         msg_Err( p_input, "nothing to do in input_UnselectES" );
862         return -1;
863     }
864
865     msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
866
867     if( p_es->p_decoder_fifo == NULL )
868     {
869         msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
870         return( -1 );
871     }
872
873     /* Update the es variable without triggering a callback */
874     switch( p_es->i_cat )
875     {
876     case AUDIO_ES:
877         psz_var = "audio-es";
878         break;
879     case SPU_ES:
880         psz_var = "spu-es";
881         break;
882     case VIDEO_ES:
883         psz_var = "video-es";
884         break;
885     }
886
887     if( psz_var )
888     {
889         val.i_int = -1;
890         var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
891     }
892
893     /* Actually unselect the ES */
894     input_EndDecoder( p_input, p_es );
895     p_es->p_pes = NULL;
896
897     if( ( p_es->p_decoder_fifo == NULL ) &&
898         ( p_input->stream.i_selected_es_number > 0 ) )
899     {
900         while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
901                ( p_input->stream.pp_selected_es[i_index] != p_es ) )
902         {
903             i_index++;
904         }
905
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,
909                      i_index );
910
911         if( p_input->stream.i_selected_es_number == 0 )
912         {
913             msg_Dbg( p_input, "no more selected ES" );
914             return 1;
915         }
916     }
917
918     return 0;
919 }
920
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 )
927 {
928     input_thread_t *p_input = (input_thread_t *)p_this;
929     vlc_value_t val;
930
931     if( oldval.i_int == newval.i_int )
932        return VLC_SUCCESS;
933
934     vlc_mutex_lock( &p_input->stream.stream_lock );
935     if( ( newval.i_int > 0 ) )
936     {
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 );
941     }
942     vlc_mutex_unlock( &p_input->stream.stream_lock );
943
944     val.b_bool = VLC_TRUE;
945     var_Set( p_input, "intf-change", val );
946
947     return VLC_SUCCESS;
948 }
949
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 )
952 {
953     input_thread_t *p_input = (input_thread_t *)p_this;
954     input_area_t *p_area;
955     vlc_value_t val, val_list;
956     int i, i_step = 0;
957
958     if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
959     else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
960
961     if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
962
963     /* Sanity check should have already been done by var_Set(). */
964     vlc_mutex_lock( &p_input->stream.stream_lock );
965
966     if( i_step )
967     {
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++ )
971         {
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 )
974             {
975                 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
976                 break;
977             }
978         }
979         var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
980     }
981
982     p_area = p_input->stream.pp_areas[newval.i_int];
983     p_area->i_part = 1;
984
985     vlc_mutex_unlock( &p_input->stream.stream_lock );
986
987     input_ChangeArea( p_input, p_area );
988     input_SetStatus( p_input, INPUT_STATUS_PLAY );
989
990     val.b_bool = VLC_TRUE;
991     var_Set( p_input, "intf-change", val );
992
993     return VLC_SUCCESS;
994 }
995
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 )
998 {
999     input_thread_t *p_input = (input_thread_t *)p_this;
1000     input_area_t *p_area;
1001     vlc_value_t val, val_list;
1002     int i, i_step = 0;
1003
1004     if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
1005     else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
1006
1007     if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
1008
1009     /* Sanity check should have already been done by var_Set(). */
1010     vlc_mutex_lock( &p_input->stream.stream_lock );
1011
1012     if( i_step )
1013     {
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++ )
1017         {
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 )
1020             {
1021                 newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
1022                 break;
1023             }
1024         }
1025         var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
1026     }
1027
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 );
1031
1032     input_ChangeArea( p_input, p_area );
1033     input_SetStatus( p_input, INPUT_STATUS_PLAY );
1034
1035     val.b_bool = VLC_TRUE;
1036     var_Set( p_input, "intf-change", val );
1037
1038     return VLC_SUCCESS;
1039 }
1040
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 )
1043 {
1044     input_thread_t *p_input = (input_thread_t *)p_this;
1045     uint16_t i_area_id = (int)p_data;
1046     vlc_value_t val;
1047
1048     vlc_mutex_lock( &p_input->stream.stream_lock );
1049
1050     if( p_input->stream.p_selected_area->i_id == i_area_id &&
1051         oldval.i_int == newval.i_int )
1052     {
1053         /* Nothing to do */
1054         vlc_mutex_unlock( &p_input->stream.stream_lock );
1055         return VLC_SUCCESS;
1056     }
1057
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 ) )
1061     {
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 );
1068     }
1069     vlc_mutex_unlock( &p_input->stream.stream_lock );
1070
1071     val.b_bool = VLC_TRUE;
1072     var_Set( p_input, "intf-change", val );
1073
1074     return VLC_SUCCESS;
1075 }
1076
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 )
1079 {
1080     input_thread_t *p_input = (input_thread_t *)p_this;
1081     unsigned int i;
1082     vlc_value_t val;
1083
1084     vlc_mutex_lock( &p_input->stream.stream_lock );
1085
1086     /* Unselect old ES */
1087     for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1088     {
1089         if( p_input->stream.pp_es[i]->i_id == oldval.i_int &&
1090             p_input->stream.pp_es[i]->p_decoder_fifo != NULL )
1091         {
1092             input_UnselectES( p_input, p_input->stream.pp_es[i] );
1093         }
1094     }
1095
1096     /* Select new ES */
1097     for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1098     {
1099         if( p_input->stream.pp_es[i]->i_id == newval.i_int &&
1100             p_input->stream.pp_es[i]->p_decoder_fifo == NULL )
1101         {
1102             input_SelectES( p_input, p_input->stream.pp_es[i] );
1103         }
1104     }
1105
1106     vlc_mutex_unlock( &p_input->stream.stream_lock );
1107
1108     val.b_bool = VLC_TRUE;
1109     var_Set( p_input, "intf-change", val );
1110
1111     return VLC_SUCCESS;
1112 }