]> git.sesse.net Git - vlc/blob - src/input/input_programs.c
* src/input/input_programs.c: Added a 'intf-changed' variable as vout, aout
[vlc] / 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.109 2003/05/11 18:40:11 hartman 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     var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
97     text.psz_string = _("Title");
98     var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
99     var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
100     text.psz_string = _("Chapter");
101     var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
102     var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
103     text.psz_string = _("Navigation");
104     var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
105     var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
106     text.psz_string = _("Video track");
107     var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
108     var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
109     text.psz_string = _("Audio track");
110     var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
111     var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
112     text.psz_string = _("Subtitle track");
113     var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
114
115     var_AddCallback( p_input, "program", ProgramCallback, NULL );
116     var_AddCallback( p_input, "title", TitleCallback, NULL );
117     var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
118     var_AddCallback( p_input, "video-es", ESCallback, NULL );
119     var_AddCallback( p_input, "audio-es", ESCallback, NULL );
120     var_AddCallback( p_input, "spu-es", ESCallback, NULL );
121
122     return 0;
123 }
124
125 /*****************************************************************************
126  * input_EndStream: free all stream descriptors
127  *****************************************************************************/
128 void input_EndStream( input_thread_t * p_input )
129 {
130     /* Free all programs and associated ES, and associated decoders. */
131     while( p_input->stream.i_pgrm_number )
132     {
133         input_DelProgram( p_input, p_input->stream.pp_programs[0] );
134     }
135
136     /* Free standalone ES */
137     while( p_input->stream.i_es_number )
138     {
139         input_DelES( p_input, p_input->stream.pp_es[0] );
140     }
141
142     /* Free all areas */
143     while( p_input->stream.i_area_nb )
144     {
145         input_DelArea( p_input, p_input->stream.pp_areas[0] );
146     }
147
148     /* Free selected ES */
149     if( p_input->stream.pp_selected_es != NULL )
150     {
151         free( p_input->stream.pp_selected_es );
152     }
153
154     if( p_input->stream.p_demux_data != NULL )
155     {
156         free( p_input->stream.p_demux_data );
157     }
158
159     /* Free navigation variables */
160     var_Destroy( p_input, "program" );
161     var_Destroy( p_input, "title" );
162     var_Destroy( p_input, "chapter" );
163     var_Destroy( p_input, "video-es" );
164     var_Destroy( p_input, "audio-es" );
165     var_Destroy( p_input, "spu-es" );
166     var_Destroy( p_input, "intf-change" );
167 }
168
169 /*****************************************************************************
170  * input_FindProgram: returns a pointer to a program described by its ID
171  *****************************************************************************/
172 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
173                                        uint16_t i_pgrm_id )
174 {
175     unsigned int i;
176
177     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
178     {
179         if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
180         {
181             return p_input->stream.pp_programs[i];
182         }
183     }
184
185     return NULL;
186 }
187
188 /*****************************************************************************
189  * input_AddProgram: add and init a program descriptor
190  *****************************************************************************
191  * This program descriptor will be referenced in the given stream descriptor
192  *****************************************************************************/
193 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
194                                       u16 i_pgrm_id, size_t i_data_len )
195 {
196     /* Where to add the pgrm */
197     pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
198     vlc_value_t val;
199
200     if( p_pgrm == NULL )
201     {
202         msg_Err( p_input, "out of memory" );
203         return NULL;
204     }
205
206     /* Init this entry */
207     p_pgrm->i_number = i_pgrm_id;
208     p_pgrm->b_is_ok = 0;
209     p_pgrm->i_version = 0;
210
211     p_pgrm->i_es_number = 0;
212     p_pgrm->pp_es = NULL;
213
214     input_ClockInit( p_pgrm );
215
216     p_pgrm->i_synchro_state = SYNCHRO_START;
217
218     if( i_data_len )
219     {
220         p_pgrm->p_demux_data = malloc( i_data_len );
221         if( p_pgrm->p_demux_data == NULL )
222         {
223             msg_Err( p_input, "out of memory" );
224             return NULL;
225         }
226         memset( p_pgrm->p_demux_data, 0, i_data_len );
227     }
228     else
229     {
230         p_pgrm->p_demux_data = NULL;
231     }
232
233     /* Add an entry to the list of program associated with the stream */
234     INSERT_ELEM( p_input->stream.pp_programs,
235                  p_input->stream.i_pgrm_number,
236                  p_input->stream.i_pgrm_number,
237                  p_pgrm );
238
239     val.i_int = i_pgrm_id;
240     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
241
242     return p_pgrm;
243 }
244
245 /*****************************************************************************
246  * input_DelProgram: destroy a program descriptor
247  *****************************************************************************
248  * All ES descriptions referenced in the descriptor will be deleted.
249  *****************************************************************************/
250 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
251 {
252     unsigned int i_pgrm_index;
253     vlc_value_t val;
254
255     /* Find the program in the programs table */
256     for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
257          i_pgrm_index++ )
258     {
259         if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
260             break;
261     }
262
263     /* If the program wasn't found, do nothing */
264     if( i_pgrm_index == p_input->stream.i_pgrm_number )
265     {
266         msg_Err( p_input, "program does not belong to this input" );
267         return;
268     }
269
270     val.i_int = i_pgrm_index;
271     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
272
273     /* Free the structures that describe the es that belongs to that program */
274     while( p_pgrm->i_es_number )
275     {
276         input_DelES( p_input, p_pgrm->pp_es[0] );
277     }
278
279     /* Free the demux data */
280     if( p_pgrm->p_demux_data != NULL )
281     {
282         free( p_pgrm->p_demux_data );
283     }
284
285     /* Remove this program from the stream's list of programs */
286     REMOVE_ELEM( p_input->stream.pp_programs,
287                  p_input->stream.i_pgrm_number,
288                  i_pgrm_index );
289
290     /* Free the description of this program */
291     free( p_pgrm );
292 }
293
294 /*****************************************************************************
295  * input_AddArea: add and init an area descriptor
296  *****************************************************************************
297  * This area descriptor will be referenced in the given stream descriptor
298  *****************************************************************************/
299 input_area_t * input_AddArea( input_thread_t * p_input,
300                               uint16_t i_area_id, uint16_t i_part_nb )
301 {
302     /* Where to add the pgrm */
303     input_area_t * p_area = malloc( sizeof(input_area_t) );
304     vlc_value_t val;
305     int i;
306
307     if( p_area == NULL )
308     {
309         msg_Err( p_input, "out of memory" );
310         return NULL;
311     }
312
313     /* Init this entry */
314     p_area->i_id = i_area_id;
315     p_area->i_part_nb = i_part_nb;
316     p_area->i_part= 0;
317     p_area->i_start = 0;
318     p_area->i_size = 0;
319     p_area->i_tell = 0;
320     p_area->i_seek = NO_SEEK;
321
322     /* Add an entry to the list of program associated with the stream */
323     INSERT_ELEM( p_input->stream.pp_areas,
324                  p_input->stream.i_area_nb,
325                  p_input->stream.i_area_nb,
326                  p_area );
327
328     /* Don't add empty areas */
329     if( i_part_nb == 0 )
330         return NULL;
331
332     /* Take care of the navigation variables */
333     val.i_int = i_area_id;
334     var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
335
336     val.psz_string = malloc( sizeof("title ") + 5 );
337     if( val.psz_string )
338     {
339         vlc_value_t val2;
340
341         sprintf( val.psz_string, "title %2i", i_area_id );
342         var_Destroy( p_input, val.psz_string );
343         var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
344                     VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
345         var_AddCallback( p_input, val.psz_string, NavigationCallback,
346                          (void *)(int)i_area_id );
347
348         var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, NULL );
349
350         for( i = 1; i <= i_part_nb; i++ )
351         {
352             val2.i_int = i;
353             var_Change( p_input, val.psz_string,
354                         VLC_VAR_ADDCHOICE, &val2, NULL );
355         }
356     }
357
358     return p_area;
359 }
360
361 /*****************************************************************************
362  * input_SetProgram: changes the current program
363  *****************************************************************************/
364 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
365 {
366     unsigned int i_es_index;
367     int i_required_audio_es;
368     int i_required_spu_es;
369     int i_audio_es = 0;
370     int i_spu_es = 0;
371     vlc_value_t val;
372
373     if ( p_input->stream.p_selected_program )
374     {
375         for ( i_es_index = 1 ; /* 0 should be the PMT */
376                 i_es_index < p_input->stream.p_selected_program->
377                 i_es_number ;
378                 i_es_index ++ )
379         {
380 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
381             if ( p_es->p_decoder_fifo ) /* if the ES was selected */
382             {
383                 input_UnselectES( p_input , p_es );
384             }
385 #undef p_es
386         }
387     }
388     /* Get the number of the required audio stream */
389     if( config_GetInt( p_input, "audio" ) )
390     {
391         /* Default is the first one */
392         i_required_audio_es = config_GetInt( p_input, "audio-channel" );
393         if( i_required_audio_es < 0 )
394         {
395             i_required_audio_es = 1;
396         }
397     }
398     else
399     {
400         i_required_audio_es = 0;
401     }
402
403     /* Same thing for subtitles */
404     if( config_GetInt( p_input, "video" ) )
405     {
406         /* for spu, default is none */
407         i_required_spu_es = config_GetInt( p_input, "spu-channel" );
408         if( i_required_spu_es < 0 )
409         {
410             i_required_spu_es = 0;
411         }
412     }
413     else
414     {
415         i_required_spu_es = 0;
416     }
417
418     for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
419     {
420         switch( p_new_prg->pp_es[i_es_index]->i_cat )
421         {
422             case VIDEO_ES:
423                 msg_Dbg( p_input, "selecting ES %x",
424                          p_new_prg->pp_es[i_es_index]->i_id );
425                 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
426                 break;
427             case AUDIO_ES:
428                 i_audio_es += 1;
429                 if( i_audio_es <= i_required_audio_es )
430                 {
431                     msg_Dbg( p_input, "selecting ES %x",
432                              p_new_prg->pp_es[i_es_index]->i_id );
433                     input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
434                 }
435                 break;
436             /* Not sure this one is fully specification-compliant */
437             case SPU_ES :
438                 i_spu_es += 1;
439                 if( i_spu_es <= i_required_spu_es )
440                 {
441                     msg_Dbg( p_input, "selecting ES %x",
442                              p_new_prg->pp_es[i_es_index]->i_id );
443                     input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
444                 }
445             break;
446             default :
447                 msg_Dbg( p_input, "ES %x has unknown type",
448                          p_new_prg->pp_es[i_es_index]->i_id );
449                 break;
450         }
451
452     }
453
454
455     p_input->stream.p_selected_program = p_new_prg;
456
457     /* Update the navigation variables without triggering a callback */
458     val.i_int = p_new_prg->i_number;
459     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
460
461     return( 0 );
462 }
463
464 /*****************************************************************************
465  * input_DelArea: destroy a area descriptor
466  *****************************************************************************
467  * All ES descriptions referenced in the descriptor will be deleted.
468  *****************************************************************************/
469 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
470 {
471     unsigned int i_area_index;
472     vlc_value_t val;
473
474     /* Find the area in the areas table */
475     for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
476          i_area_index++ )
477     {
478         if( p_input->stream.pp_areas[i_area_index] == p_area )
479             break;
480     }
481
482     /* If the area wasn't found, do nothing */
483     if( i_area_index == p_input->stream.i_area_nb )
484     {
485         msg_Err( p_input, "area does not belong to this input" );
486         return;
487     }
488
489     /* Take care of the navigation variables */
490     val.psz_string = malloc( sizeof("title ") + 5 );
491     if( val.psz_string )
492     {
493         sprintf( val.psz_string, "title %i", p_area->i_id );
494         var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
495         var_Destroy( p_input, val.psz_string );
496     }
497
498     /* Remove this area from the stream's list of areas */
499     REMOVE_ELEM( p_input->stream.pp_areas,
500                  p_input->stream.i_area_nb,
501                  i_area_index );
502
503     /* Free the description of this area */
504     free( p_area );
505 }
506
507
508 /*****************************************************************************
509  * input_FindES: returns a pointer to an ES described by its ID
510  *****************************************************************************/
511 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
512 {
513     unsigned int i;
514
515     for( i = 0; i < p_input->stream.i_es_number; i++ )
516     {
517         if( p_input->stream.pp_es[i]->i_id == i_es_id )
518         {
519             return p_input->stream.pp_es[i];
520         }
521     }
522
523     return NULL;
524 }
525
526 /*****************************************************************************
527  * input_AddES:
528  *****************************************************************************
529  * Reserve a slot in the table of ES descriptors for the ES and add it to the
530  * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
531  * alone (PSI ?)
532  *****************************************************************************/
533 es_descriptor_t * input_AddES( input_thread_t * p_input,
534                                pgrm_descriptor_t * p_pgrm, u16 i_es_id,
535                                int i_category, char const *psz_desc,
536                                size_t i_data_len )
537 {
538     es_descriptor_t * p_es;
539     vlc_value_t val, text;
540     char *psz_var = NULL;
541
542     p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
543     if( p_es == NULL )
544     {
545         msg_Err( p_input, "out of memory" );
546         return( NULL);
547     }
548
549     INSERT_ELEM( p_input->stream.pp_es,
550                  p_input->stream.i_es_number,
551                  p_input->stream.i_es_number,
552                  p_es );
553
554     /* Init its values */
555     p_es->i_id = i_es_id;
556     p_es->p_pes = NULL;
557     p_es->p_decoder_fifo = NULL;
558     p_es->i_cat = i_category;
559     p_es->i_demux_fd = 0;
560     p_es->c_packets = 0;
561     p_es->c_invalid_packets = 0;
562     p_es->b_force_decoder = VLC_FALSE;
563
564     if( i_data_len )
565     {
566         p_es->p_demux_data = malloc( i_data_len );
567         if( p_es->p_demux_data == NULL )
568         {
569             msg_Err( p_input, "out of memory" );
570             return( NULL );
571         }
572         memset( p_es->p_demux_data, 0, i_data_len );
573     }
574     else
575     {
576         p_es->p_demux_data = NULL;
577     }
578     p_es->p_waveformatex     = NULL;
579     p_es->p_bitmapinfoheader = NULL;
580
581     /* Add this ES to the program definition if one is given */
582     if( p_pgrm )
583     {
584         INSERT_ELEM( p_pgrm->pp_es,
585                      p_pgrm->i_es_number,
586                      p_pgrm->i_es_number,
587                      p_es );
588         p_es->p_pgrm = p_pgrm;
589     }
590     else
591     {
592         p_es->p_pgrm = NULL;
593     }
594
595     switch( i_category )
596     {
597     case AUDIO_ES:
598         psz_var = "audio-es";
599         break;
600     case SPU_ES:
601         psz_var = "spu-es";
602         break;
603     case VIDEO_ES:
604         psz_var = "video-es";
605         break;
606     }
607
608     if( psz_var )
609     {
610         /* Get the number of ES already added */
611         var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
612         if( val.i_int == 0 )
613         {
614             vlc_value_t val2;
615
616             /* First one, we need to add the "Disable" choice */
617             val2.i_int = -1; text.psz_string = _("Disable");
618             var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
619             val.i_int++;
620         }
621
622         /* Take care of the ES description */
623         if( psz_desc )
624         {
625             p_es->psz_desc = strdup( psz_desc );
626         }
627         else
628         {
629             p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
630             if( p_es->psz_desc )
631                 sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
632         }
633
634         val.i_int = p_es->i_id;
635         text.psz_string = p_es->psz_desc;
636         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
637     }
638
639     return p_es;
640 }
641
642 /*****************************************************************************
643  * input_DelES:
644  *****************************************************************************/
645 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
646 {
647     unsigned int            i_index, i_es_index;
648     pgrm_descriptor_t *     p_pgrm;
649     char *                  psz_var = NULL;
650     vlc_value_t             val;
651
652     /* Find the ES in the ES table */
653     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
654          i_es_index++ )
655     {
656         if( p_input->stream.pp_es[i_es_index] == p_es )
657             break;
658     }
659
660     /* If the ES wasn't found, do nothing */
661     if( i_es_index == p_input->stream.i_es_number )
662     {
663         msg_Err( p_input, "ES does not belong to this input" );
664         return;
665     }
666
667     /* Remove es from its associated variable */
668     switch( p_es->i_cat )
669     {
670     case AUDIO_ES:
671         psz_var = "audio-es";
672         break;
673     case SPU_ES:
674         psz_var = "spu-es";
675         break;
676     case VIDEO_ES:
677         psz_var = "video-es";
678         break;
679     }
680
681     if( psz_var )
682     {
683         val.i_int = p_es->i_id;
684         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
685
686         /* Remove the "Disable" entry if needed */
687         var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
688         if( val.i_int == 1 )
689         {
690             val.i_int = -1;
691             var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
692         }
693     }
694
695     /* Kill associated decoder, if any. */
696     if( p_es->p_decoder_fifo != NULL )
697     {
698         input_EndDecoder( p_input, p_es );
699     }
700
701     /* Remove this ES from the description of the program if it is associated
702      * to one */
703     p_pgrm = p_es->p_pgrm;
704     if( p_pgrm )
705     {
706         for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
707         {
708             if( p_pgrm->pp_es[i_index] == p_es )
709             {
710                 REMOVE_ELEM( p_pgrm->pp_es,
711                              p_pgrm->i_es_number,
712                              i_index );
713                 break;
714             }
715         }
716     }
717
718     /* Free the demux data */
719     if( p_es->p_demux_data != NULL )
720     {
721         free( p_es->p_demux_data );
722     }
723     if( p_es->p_waveformatex )
724     {
725         free( p_es->p_waveformatex );
726     }
727     if( p_es->p_bitmapinfoheader )
728     {
729         free( p_es->p_bitmapinfoheader );
730     }
731
732     /* Free the description string */
733     if( p_es->psz_desc != NULL )
734     {
735         free( p_es->psz_desc );
736     }
737
738     /* Find the ES in the ES table */
739     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
740          i_es_index++ )
741     {
742         if( p_input->stream.pp_es[i_es_index] == p_es )
743             break;
744     }
745
746     /* Remove this ES from the stream's list of ES */
747     REMOVE_ELEM( p_input->stream.pp_es,
748                  p_input->stream.i_es_number,
749                  i_es_index );
750
751     /* Free the ES */
752     free( p_es );
753 }
754
755 /*****************************************************************************
756  * input_SelectES: selects an ES and spawns the associated decoder
757  *****************************************************************************
758  * Remember we are still supposed to have stream_lock when entering this
759  * function ?
760  *****************************************************************************/
761 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
762 {
763     vlc_value_t val;
764     char *psz_var = NULL;
765
766     if( p_es == NULL )
767     {
768         msg_Err( p_input, "nothing to do in input_SelectES" );
769         return -1;
770     }
771
772     if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
773         && !config_GetInt( p_input, "video" ) )
774     {
775         msg_Dbg( p_input,
776                  "video is disabled, not selecting ES 0x%x", p_es->i_id );
777         return -1;
778     }
779
780     if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
781     {
782         msg_Dbg( p_input,
783                  "audio is disabled, not selecting ES 0x%x", p_es->i_id );
784         return -1;
785     }
786
787     msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
788
789     if( p_es->p_decoder_fifo != NULL )
790     {
791         msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
792         return -1;
793     }
794
795     /* Release the lock, not to block the input thread during
796      * the creation of the thread. */
797     vlc_mutex_unlock( &p_input->stream.stream_lock );
798     p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
799     vlc_mutex_lock( &p_input->stream.stream_lock );
800
801     if( p_es->p_decoder_fifo == NULL )
802     {
803         return -1;
804     }
805
806     /* Update the es variable without triggering a callback */
807     switch( p_es->i_cat )
808     {
809     case AUDIO_ES:
810         psz_var = "audio-es";
811         break;
812     case SPU_ES:
813         psz_var = "spu-es";
814         break;
815     case VIDEO_ES:
816         psz_var = "video-es";
817         break;
818     }
819
820     if( psz_var )
821     {
822         val.i_int = p_es->i_id;
823         var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
824     }
825
826     return 0;
827 }
828
829 /*****************************************************************************
830  * input_UnselectES: removes an ES from the list of selected ES
831  *****************************************************************************/
832 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
833 {
834     unsigned int i_index = 0;
835     vlc_value_t val;
836     char *psz_var = NULL;
837
838     if( p_es == NULL )
839     {
840         msg_Err( p_input, "nothing to do in input_UnselectES" );
841         return -1;
842     }
843
844     msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
845
846     if( p_es->p_decoder_fifo == NULL )
847     {
848         msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
849         return( -1 );
850     }
851
852     /* Update the es variable without triggering a callback */
853     switch( p_es->i_cat )
854     {
855     case AUDIO_ES:
856         psz_var = "audio-es";
857         break;
858     case SPU_ES:
859         psz_var = "spu-es";
860         break;
861     case VIDEO_ES:
862         psz_var = "video-es";
863         break;
864     }
865
866     if( psz_var )
867     {
868         val.i_int = -1;
869         var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
870     }
871
872     /* Actually unselect the ES */
873     input_EndDecoder( p_input, p_es );
874     p_es->p_pes = NULL;
875
876     if( ( p_es->p_decoder_fifo == NULL ) &&
877         ( p_input->stream.i_selected_es_number > 0 ) )
878     {
879         while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
880                ( p_input->stream.pp_selected_es[i_index] != p_es ) )
881         {
882             i_index++;
883         }
884
885         /* XXX: no need to memmove, we have unsorted data */
886         REMOVE_ELEM( p_input->stream.pp_selected_es,
887                      p_input->stream.i_selected_es_number,
888                      i_index );
889
890         if( p_input->stream.i_selected_es_number == 0 )
891         {
892             msg_Dbg( p_input, "no more selected ES" );
893             return 1;
894         }
895     }
896
897     return 0;
898 }
899
900 /*****************************************************************************
901  * Navigation callback: a bunch of navigation variables are used as an
902  *  alternative to the navigation API.
903  *****************************************************************************/
904 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
905                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
906 {
907     input_thread_t *p_input = (input_thread_t *)p_this;
908     vlc_value_t val;
909
910     if( oldval.i_int == newval.i_int )
911        return VLC_SUCCESS;
912
913     vlc_mutex_lock( &p_input->stream.stream_lock );
914     if( ( newval.i_int > 0 ) )
915     {
916         vlc_mutex_unlock( &p_input->stream.stream_lock );
917         input_ChangeProgram( p_input, (uint16_t)newval.i_int );
918         input_SetStatus( p_input, INPUT_STATUS_PLAY );
919         vlc_mutex_lock( &p_input->stream.stream_lock );
920     }
921     vlc_mutex_unlock( &p_input->stream.stream_lock );
922
923     val.b_bool = VLC_TRUE;
924     var_Set( p_input, "intf-change", val );
925
926     return VLC_SUCCESS;
927 }
928
929 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
930                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
931 {
932     input_thread_t *p_input = (input_thread_t *)p_this;
933     input_area_t *p_area;
934     vlc_value_t val;
935
936     if( oldval.i_int == newval.i_int )
937        return VLC_SUCCESS;
938
939     /* Sanity check should have already be done by var_Set(). */
940     vlc_mutex_lock( &p_input->stream.stream_lock );
941     p_area = p_input->stream.pp_areas[newval.i_int];
942     p_area->i_part = 1;
943     vlc_mutex_unlock( &p_input->stream.stream_lock );
944     input_ChangeArea( p_input, p_area );
945     input_SetStatus( p_input, INPUT_STATUS_PLAY );
946
947     val.b_bool = VLC_TRUE;
948     var_Set( p_input, "intf-change", val );
949
950     return VLC_SUCCESS;
951 }
952
953 static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
954                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
955 {
956     input_thread_t *p_input = (input_thread_t *)p_this;
957     input_area_t *p_area;
958     vlc_value_t val;
959
960     if( oldval.i_int == newval.i_int )
961        return VLC_SUCCESS;
962
963     /* Sanity check will have already be done by var_Set(). */
964     vlc_mutex_lock( &p_input->stream.stream_lock );
965     p_area = p_input->stream.p_selected_area;
966     p_input->stream.p_selected_area->i_part = newval.i_int;
967     vlc_mutex_unlock( &p_input->stream.stream_lock );
968
969     input_ChangeArea( p_input, p_area );
970     input_SetStatus( p_input, INPUT_STATUS_PLAY );
971
972     val.b_bool = VLC_TRUE;
973     var_Set( p_input, "intf-change", val );
974
975     return VLC_SUCCESS;
976 }
977
978 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
979                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
980 {
981     input_thread_t *p_input = (input_thread_t *)p_this;
982     uint16_t i_area_id = (int)p_data;
983     vlc_value_t val;
984
985     vlc_mutex_lock( &p_input->stream.stream_lock );
986
987     if( p_input->stream.p_selected_area->i_id == i_area_id &&
988         oldval.i_int == newval.i_int )
989     {
990         /* Nothing to do */
991         vlc_mutex_unlock( &p_input->stream.stream_lock );
992         return VLC_SUCCESS;
993     }
994
995     if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
996         ( (uint16_t)newval.i_int <=
997           p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
998     {
999         input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
1000         p_input->stream.p_selected_area->i_part = newval.i_int;
1001         vlc_mutex_unlock( &p_input->stream.stream_lock );
1002         input_ChangeArea( p_input, p_area );
1003         input_SetStatus( p_input, INPUT_STATUS_PLAY );
1004         vlc_mutex_lock( &p_input->stream.stream_lock );
1005     }
1006     vlc_mutex_unlock( &p_input->stream.stream_lock );
1007
1008     val.b_bool = VLC_TRUE;
1009     var_Set( p_input, "intf-change", val );
1010
1011     return VLC_SUCCESS;
1012 }
1013
1014 static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
1015                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1016 {
1017     input_thread_t *p_input = (input_thread_t *)p_this;
1018     unsigned int i;
1019     vlc_value_t val;
1020
1021     vlc_mutex_lock( &p_input->stream.stream_lock );
1022
1023     /* Unselect old ES */
1024     for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1025     {
1026         if( p_input->stream.pp_es[i]->i_id == oldval.i_int &&
1027             p_input->stream.pp_es[i]->p_decoder_fifo != NULL )
1028         {
1029             input_UnselectES( p_input, p_input->stream.pp_es[i] );
1030         }
1031     }
1032
1033     /* Select new ES */
1034     for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1035     {
1036         if( p_input->stream.pp_es[i]->i_id == newval.i_int &&
1037             p_input->stream.pp_es[i]->p_decoder_fifo == NULL )
1038         {
1039             input_SelectES( p_input, p_input->stream.pp_es[i] );
1040         }
1041     }
1042
1043     vlc_mutex_unlock( &p_input->stream.stream_lock );
1044
1045     val.b_bool = VLC_TRUE;
1046     var_Set( p_input, "intf-change", val );
1047
1048     return VLC_SUCCESS;
1049 }