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