98f4fa0656cbdb227b1ad760e598c71b0ed3829c
[vlc.git] / src / input / es_out.c
1 /*****************************************************************************
2  * es_out.c: Es Out handler for input.
3  *****************************************************************************
4  * Copyright (C) 2003-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include <vlc_input.h>
34 #include <vlc_es_out.h>
35 #include <vlc_block.h>
36
37 #include "input_internal.h"
38
39 #include "vlc_playlist.h"
40 #include "iso_lang.h"
41 /* FIXME we should find a better way than including that */
42 #include "../text/iso-639_def.h"
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 typedef struct
48 {
49     /* Program ID */
50     int i_id;
51
52     /* Number of es for this pgrm */
53     int i_es;
54
55     vlc_bool_t b_selected;
56
57     /* Clock for this program */
58     input_clock_t clock;
59
60     char    *psz_now_playing;
61
62 } es_out_pgrm_t;
63
64 struct es_out_id_t
65 {
66     /* ES ID */
67     int       i_id;
68     es_out_pgrm_t *p_pgrm;
69
70     /* Signal a discontinuity in the timeline for every PID */
71     vlc_bool_t b_discontinuity;
72
73     /* Misc. */
74     int64_t i_preroll_end;
75
76     /* Channel in the track type */
77     int         i_channel;
78     es_format_t fmt;
79     char        *psz_language;
80     char        *psz_language_code;
81     decoder_t   *p_dec;
82 };
83
84 struct es_out_sys_t
85 {
86     input_thread_t *p_input;
87
88     /* all programs */
89     int           i_pgrm;
90     es_out_pgrm_t **pgrm;
91     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
92     es_out_pgrm_t *p_pgrm;  /* Master program */
93
94     /* all es */
95     int         i_id;
96     int         i_es;
97     es_out_id_t **es;
98
99     /* mode gestion */
100     vlc_bool_t  b_active;
101     int         i_mode;
102
103     /* es count */
104     int         i_audio;
105     int         i_video;
106     int         i_sub;
107
108     /* es to select */
109     int         i_audio_last, i_audio_id;
110     int         i_sub_last, i_sub_id;
111     char        **ppsz_audio_language;
112     char        **ppsz_sub_language;
113
114     /* current main es */
115     es_out_id_t *p_es_audio;
116     es_out_id_t *p_es_video;
117     es_out_id_t *p_es_sub;
118
119     /* delay */
120     int64_t i_audio_delay;
121     int64_t i_spu_delay;
122 };
123
124 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
125 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
126 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
127 static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
128 static int          EsOutControl( es_out_t *, int i_query, va_list );
129
130 static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
131
132 static void EsSelect( es_out_t *out, es_out_id_t *es );
133 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
134 static char *LanguageGetName( const char *psz_code );
135 static char *LanguageGetCode( const char *psz_lang );
136 static char **LanguageSplit( const char *psz_langs );
137 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
138
139 /*****************************************************************************
140  * input_EsOutNew:
141  *****************************************************************************/
142 es_out_t *input_EsOutNew( input_thread_t *p_input )
143 {
144     es_out_t     *out = malloc( sizeof( es_out_t ) );
145     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
146     vlc_value_t  val;
147     int i;
148
149     out->pf_add     = EsOutAdd;
150     out->pf_send    = EsOutSend;
151     out->pf_del     = EsOutDel;
152     out->pf_control = EsOutControl;
153     out->p_sys      = p_sys;
154     out->b_sout     = (p_input->p->p_sout != NULL ? VLC_TRUE : VLC_FALSE);
155
156     p_sys->p_input = p_input;
157
158     p_sys->b_active = VLC_FALSE;
159     p_sys->i_mode   = ES_OUT_MODE_AUTO;
160
161
162     p_sys->i_pgrm   = 0;
163     p_sys->pgrm     = NULL;
164     p_sys->p_pgrm   = NULL;
165
166     p_sys->i_id    = 0;
167     p_sys->i_es    = 0;
168     p_sys->es      = NULL;
169
170     p_sys->i_audio = 0;
171     p_sys->i_video = 0;
172     p_sys->i_sub   = 0;
173
174     /* */
175     var_Get( p_input, "audio-track", &val );
176     p_sys->i_audio_last = val.i_int;
177
178     var_Get( p_input, "sub-track", &val );
179     p_sys->i_sub_last = val.i_int;
180
181     if( !p_input->b_preparsing )
182     {
183         var_Get( p_input, "audio-language", &val );
184         p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
185         if( p_sys->ppsz_audio_language )
186         {
187             for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
188                 msg_Dbg( p_input, "selected audio language[%d] %s",
189                          i, p_sys->ppsz_audio_language[i] );
190         }
191         if( val.psz_string ) free( val.psz_string );
192
193         var_Get( p_input, "sub-language", &val );
194         p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
195         if( p_sys->ppsz_sub_language )
196         {
197             for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
198                 msg_Dbg( p_input, "selected subtitle language[%d] %s",
199                          i, p_sys->ppsz_sub_language[i] );
200         }
201         if( val.psz_string ) free( val.psz_string );
202     }
203     else
204     {
205         p_sys->ppsz_sub_language = NULL;
206         p_sys->ppsz_audio_language = NULL;
207     }
208
209     var_Get( p_input, "audio-track-id", &val );
210     p_sys->i_audio_id = val.i_int;
211
212     var_Get( p_input, "sub-track-id", &val );
213     p_sys->i_sub_id = val.i_int;
214
215     p_sys->p_es_audio = NULL;
216     p_sys->p_es_video = NULL;
217     p_sys->p_es_sub   = NULL;
218
219     p_sys->i_audio_delay= 0;
220     p_sys->i_spu_delay  = 0;
221
222     return out;
223 }
224
225 /*****************************************************************************
226  * input_EsOutDelete:
227  *****************************************************************************/
228 void input_EsOutDelete( es_out_t *out )
229 {
230     es_out_sys_t *p_sys = out->p_sys;
231     int i;
232
233     for( i = 0; i < p_sys->i_es; i++ )
234     {
235         if( p_sys->es[i]->p_dec )
236         {
237             input_DecoderDelete( p_sys->es[i]->p_dec );
238         }
239         if( p_sys->es[i]->psz_language )
240             free( p_sys->es[i]->psz_language );
241         if( p_sys->es[i]->psz_language_code )
242             free( p_sys->es[i]->psz_language_code );
243         es_format_Clean( &p_sys->es[i]->fmt );
244
245         free( p_sys->es[i] );
246     }
247     if( p_sys->ppsz_audio_language )
248     {
249         for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
250             free( p_sys->ppsz_audio_language[i] );
251         free( p_sys->ppsz_audio_language );
252     }
253     if( p_sys->ppsz_sub_language )
254     {
255         for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
256             free( p_sys->ppsz_sub_language[i] );
257         free( p_sys->ppsz_sub_language );
258     }
259
260     if( p_sys->es )
261         free( p_sys->es );
262
263     for( i = 0; i < p_sys->i_pgrm; i++ )
264     {
265         if( p_sys->pgrm[i]->psz_now_playing )
266             free( p_sys->pgrm[i]->psz_now_playing );
267         free( p_sys->pgrm[i] );
268     }
269     if( p_sys->pgrm )
270         free( p_sys->pgrm );
271
272     free( p_sys );
273     free( out );
274 }
275
276 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
277 {
278     int i;
279     if( i_id < 0 )
280     {
281         /* Special HACK, -i_id is tha cat of the stream */
282         return (es_out_id_t*)((uint8_t*)NULL-i_id);
283     }
284
285     for( i = 0; i < out->p_sys->i_es; i++ )
286     {
287         if( out->p_sys->es[i]->i_id == i_id )
288             return out->p_sys->es[i];
289     }
290     return NULL;
291 }
292
293 void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
294 {
295     es_out_sys_t      *p_sys = out->p_sys;
296     int i;
297
298     for( i = 0; i < p_sys->i_es; i++ )
299     {
300         es_out_id_t *es = p_sys->es[i];
301         es->b_discontinuity = VLC_TRUE; /* signal discontinuity */
302
303         /* Send a dummy block to let decoder know that
304          * there is a discontinuity */
305         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
306         {
307             input_DecoderDiscontinuity( es->p_dec );
308         }
309     }
310 }
311
312 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
313 {
314     es_out_sys_t *p_sys = out->p_sys;
315
316     if( i_cat == AUDIO_ES )
317         p_sys->i_audio_delay = i_delay;
318     else if( i_cat == SPU_ES )
319         p_sys->i_spu_delay = i_delay;
320 }
321
322 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
323 {
324     es_out_sys_t      *p_sys = out->p_sys;
325     int i;
326
327     for( i = 0; i < p_sys->i_es; i++ )
328     {
329         es_out_id_t *es = p_sys->es[i];
330
331         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
332             return VLC_FALSE;
333     }
334     return VLC_TRUE;
335 }
336
337 /*****************************************************************************
338  *
339  *****************************************************************************/
340 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
341                               vlc_bool_t b_delete )
342 {
343     es_out_sys_t      *p_sys = out->p_sys;
344     input_thread_t    *p_input = p_sys->p_input;
345     vlc_value_t       val, text;
346
347     const char *psz_var;
348
349     if( es->fmt.i_cat == AUDIO_ES )
350         psz_var = "audio-es";
351     else if( es->fmt.i_cat == VIDEO_ES )
352         psz_var = "video-es";
353     else if( es->fmt.i_cat == SPU_ES )
354         psz_var = "spu-es";
355     else
356         return;
357
358     if( b_delete )
359     {
360         val.i_int = es->i_id;
361         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
362         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
363         return;
364     }
365
366     /* Get the number of ES already added */
367     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
368     if( val.i_int == 0 )
369     {
370         vlc_value_t val2;
371
372         /* First one, we need to add the "Disable" choice */
373         val2.i_int = -1; text.psz_string = _("Disable");
374         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
375         val.i_int++;
376     }
377
378     /* Take care of the ES description */
379     if( es->fmt.psz_description && *es->fmt.psz_description )
380     {
381         if( es->psz_language && *es->psz_language )
382         {
383             text.psz_string = malloc( strlen( es->fmt.psz_description) +
384                                       strlen( es->psz_language ) + 10 );
385             sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description,
386                                                    es->psz_language );
387         }
388         else text.psz_string = strdup( es->fmt.psz_description );
389     }
390     else
391     {
392         if( es->psz_language && *es->psz_language )
393         {
394             char *temp;
395             text.psz_string = malloc( strlen( _("Track %i") )+
396                                       strlen( es->psz_language ) + 30 );
397             asprintf( &temp,  _("Track %i"), val.i_int );
398             sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
399             free( temp );
400         }
401         else
402         {
403             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
404             sprintf( text.psz_string, _("Track %i"), val.i_int );
405         }
406     }
407
408     val.i_int = es->i_id;
409     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
410
411     free( text.psz_string );
412
413     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
414 }
415
416 /* EsOutProgramSelect:
417  *  Select a program and update the object variable
418  */
419 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
420 {
421     es_out_sys_t      *p_sys = out->p_sys;
422     input_thread_t    *p_input = p_sys->p_input;
423     vlc_value_t       val;
424     int               i;
425
426     if( p_sys->p_pgrm == p_pgrm )
427         return; /* Nothing to do */
428
429     if( p_sys->p_pgrm )
430     {
431         es_out_pgrm_t *old = p_sys->p_pgrm;
432         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
433
434         for( i = 0; i < p_sys->i_es; i++ )
435         {
436             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
437                 p_sys->i_mode != ES_OUT_MODE_ALL )
438                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
439         }
440
441         p_sys->p_es_audio = NULL;
442         p_sys->p_es_sub = NULL;
443         p_sys->p_es_video = NULL;
444     }
445
446     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
447
448     /* Mark it selected */
449     p_pgrm->b_selected = VLC_TRUE;
450
451     /* Switch master stream */
452     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
453     {
454         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
455     }
456     p_pgrm->clock.b_master = VLC_TRUE;
457     p_sys->p_pgrm = p_pgrm;
458
459     /* Update "program" */
460     val.i_int = p_pgrm->i_id;
461     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
462
463     /* Update "es-*" */
464     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
465     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
466     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
467     for( i = 0; i < p_sys->i_es; i++ )
468     {
469         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
470             EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
471         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
472     }
473
474     /* Update now playing if defined per program */
475     if( p_pgrm->psz_now_playing )
476     {
477         char *psz_cat = malloc( strlen(_("Program")) + 10 );
478
479         sprintf( psz_cat, "%s %d", _("Program"), p_pgrm->i_id );
480         input_Control( p_input, INPUT_ADD_INFO, _(VLC_META_INFO_CAT),
481                        _(VLC_META_NOW_PLAYING), "%s", p_pgrm->psz_now_playing );
482         free( psz_cat );
483     }
484
485
486     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
487 }
488
489 /* EsOutAddProgram:
490  *  Add a program
491  */
492 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
493 {
494     es_out_sys_t      *p_sys = out->p_sys;
495     input_thread_t    *p_input = p_sys->p_input;
496     vlc_value_t       val;
497
498     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
499
500     /* Init */
501     p_pgrm->i_id = i_group;
502     p_pgrm->i_es = 0;
503     p_pgrm->b_selected = VLC_FALSE;
504     p_pgrm->psz_now_playing = NULL;
505     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average );
506
507     /* Append it */
508     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
509
510     /* Update "program" variable */
511     val.i_int = i_group;
512     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
513
514     if( i_group == var_GetInteger( p_input, "program" ) )
515     {
516         EsOutProgramSelect( out, p_pgrm );
517     }
518     else
519     {
520         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
521     }
522     return p_pgrm;
523 }
524
525 /* EsOutDelProgram:
526  *  Delete a program
527  */
528 static int EsOutProgramDel( es_out_t *out, int i_group )
529 {
530     es_out_sys_t      *p_sys = out->p_sys;
531     input_thread_t    *p_input = p_sys->p_input;
532     es_out_pgrm_t     *p_pgrm = NULL;
533     vlc_value_t       val;
534     int               i;
535
536     for( i = 0; i < p_sys->i_pgrm; i++ )
537     {
538         if( p_sys->pgrm[i]->i_id == i_group )
539         {
540             p_pgrm = p_sys->pgrm[i];
541             break;
542         }
543     }
544
545     if( p_pgrm == NULL )
546         return VLC_EGENERIC;
547
548     if( p_pgrm->i_es )
549     {
550         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
551                  i_group, p_pgrm->i_es );
552         return VLC_EGENERIC;
553     }
554
555     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
556
557     /* If program is selected we need to unselect it */
558     if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = 0;
559
560     if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
561     free( p_pgrm );
562
563     /* Update "program" variable */
564     val.i_int = i_group;
565     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
566
567     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
568
569     return VLC_SUCCESS;
570 }
571
572 /* EsOutProgramMeta:
573  */
574 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
575 {
576     es_out_sys_t      *p_sys = out->p_sys;
577     es_out_pgrm_t     *p_pgrm = NULL;
578     input_thread_t    *p_input = p_sys->p_input;
579     char              *psz_cat = malloc( strlen(_("Program")) + 10 );
580     char              *psz_title = NULL;
581     char              *psz_now_playing = NULL;
582     char              *psz_provider = NULL;
583     int i;
584
585     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
586     sprintf( psz_cat, "%s %d", _("Program"), i_group );
587
588     if( p_meta->psz_title ) psz_title = p_meta->psz_title;
589     if( p_meta->psz_publisher ) psz_provider = p_meta->psz_publisher;
590     if( p_meta->psz_nowplaying ) psz_now_playing = p_meta->psz_nowplaying;
591
592     if( !psz_title && !psz_now_playing )
593     {
594         free( psz_cat );
595         return;
596     }
597
598     for( i = 0; i < p_sys->i_pgrm; i++ )
599     {
600         if( p_sys->pgrm[i]->i_id == i_group )
601         {
602             p_pgrm = p_sys->pgrm[i];
603             break;
604         }
605     }
606
607     if( p_pgrm == NULL ) {
608         free( psz_cat );
609         msg_Dbg( p_input, "Trying to add meta for non-existing program" );
610         return;
611     }
612
613     /* Update the description text of the program */
614     if( psz_title && *psz_title )
615     {
616         vlc_value_t val;
617         vlc_value_t text;
618
619         /* ugly but it works */
620         val.i_int = i_group;
621         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
622
623         if( psz_provider && *psz_provider )
624         {
625             asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider );
626             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
627             free( text.psz_string );
628         }
629         else
630         {
631             text.psz_string = psz_title;
632             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
633         }
634     }
635     if( psz_now_playing )
636     {
637         if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
638         p_pgrm->psz_now_playing = strdup(psz_now_playing);
639
640         if( p_sys->p_pgrm == p_pgrm )
641         {
642             vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta,
643                                     psz_now_playing );
644         }
645     }
646     free( psz_cat );
647 }
648
649 /* EsOutAdd:
650  *  Add an es_out
651  */
652 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
653 {
654     es_out_sys_t      *p_sys = out->p_sys;
655     input_thread_t    *p_input = p_sys->p_input;
656
657     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
658     es_out_pgrm_t     *p_pgrm = NULL;
659     int i;
660
661     if( fmt->i_group < 0 )
662     {
663         msg_Err( p_input, "invalid group number" );
664         return NULL;
665     }
666
667     /* Search the program */
668     for( i = 0; i < p_sys->i_pgrm; i++ )
669     {
670         if( fmt->i_group == p_sys->pgrm[i]->i_id )
671         {
672             p_pgrm = p_sys->pgrm[i];
673             break;
674         }
675     }
676     if( p_pgrm == NULL )
677     {
678         /* Create a new one */
679         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
680     }
681
682     /* Increase ref count for program */
683     p_pgrm->i_es++;
684
685     /* Set up ES */
686     if( fmt->i_id < 0 )
687         fmt->i_id = out->p_sys->i_id;
688     es->i_id = fmt->i_id;
689     es->p_pgrm = p_pgrm;
690     es_format_Copy( &es->fmt, fmt );
691     es->i_preroll_end = -1;
692     es->b_discontinuity = VLC_FALSE;
693
694     switch( fmt->i_cat )
695     {
696     case AUDIO_ES:
697         es->i_channel = p_sys->i_audio;
698         break;
699
700     case VIDEO_ES:
701         es->i_channel = p_sys->i_video;
702         if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
703             vlc_ureduce( &es->fmt.video.i_frame_rate,
704                          &es->fmt.video.i_frame_rate_base,
705                          fmt->video.i_frame_rate,
706                          fmt->video.i_frame_rate_base, 0 );
707         break;
708
709     case SPU_ES:
710         es->i_channel = p_sys->i_sub;
711         break;
712
713     default:
714         es->i_channel = 0;
715         break;
716     }
717     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
718     es->psz_language_code = LanguageGetCode( fmt->psz_language );
719     es->p_dec = NULL;
720
721     if( es->p_pgrm == p_sys->p_pgrm )
722         EsOutESVarUpdate( out, es, VLC_FALSE );
723
724     /* Select it if needed */
725     EsOutSelect( out, es, VLC_FALSE );
726
727
728     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
729     p_sys->i_id++;  /* always incremented */
730     switch( fmt->i_cat )
731     {
732         case AUDIO_ES:
733             p_sys->i_audio++;
734             break;
735         case SPU_ES:
736             p_sys->i_sub++;
737             break;
738         case VIDEO_ES:
739             p_sys->i_video++;
740             break;
741     }
742
743     EsOutAddInfo( out, es );
744
745     return es;
746 }
747
748 static void EsSelect( es_out_t *out, es_out_id_t *es )
749 {
750     es_out_sys_t   *p_sys = out->p_sys;
751     input_thread_t *p_input = p_sys->p_input;
752     vlc_value_t    val;
753     const char     *psz_var;
754
755     if( es->p_dec )
756     {
757         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
758         return;
759     }
760
761     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
762     {
763         if( !var_GetBool( p_input, "video" ) ||
764             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
765         {
766             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
767                      es->i_id );
768             return;
769         }
770     }
771     else if( es->fmt.i_cat == AUDIO_ES )
772     {
773         var_Get( p_input, "audio", &val );
774         if( !var_GetBool( p_input, "audio" ) ||
775             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
776         {
777             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
778                      es->i_id );
779             return;
780         }
781     }
782     if( es->fmt.i_cat == SPU_ES )
783     {
784         var_Get( p_input, "spu", &val );
785         if( !var_GetBool( p_input, "spu" ) ||
786             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) )
787         {
788             msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
789                      es->i_id );
790             return;
791         }
792     }
793
794     es->i_preroll_end = -1;
795     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
796     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
797         return;
798
799     if( es->fmt.i_cat == VIDEO_ES )
800         psz_var = "video-es";
801     else if( es->fmt.i_cat == AUDIO_ES )
802         psz_var = "audio-es";
803     else if( es->fmt.i_cat == SPU_ES )
804         psz_var = "spu-es";
805     else
806         return;
807
808     /* Mark it as selected */
809     val.i_int = es->i_id;
810     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
811
812
813     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
814 }
815
816 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
817 {
818     es_out_sys_t   *p_sys = out->p_sys;
819     input_thread_t *p_input = p_sys->p_input;
820     vlc_value_t    val;
821     const char     *psz_var;
822
823     if( es->p_dec == NULL )
824     {
825         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
826         return;
827     }
828
829     input_DecoderDelete( es->p_dec );
830     es->p_dec = NULL;
831
832     if( !b_update )
833         return;
834
835     /* Update var */
836     if( es->p_dec == NULL )
837         return;
838     if( es->fmt.i_cat == VIDEO_ES )
839         psz_var = "video-es";
840     else if( es->fmt.i_cat == AUDIO_ES )
841         psz_var = "audio-es";
842     else if( es->fmt.i_cat == SPU_ES )
843         psz_var = "spu-es";
844     else
845         return;
846
847     /* Mark it as selected */
848     val.i_int = -1;
849     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
850
851     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
852 }
853
854 /**
855  * Select an ES given the current mode
856  * XXX: you need to take a the lock before (stream.stream_lock)
857  *
858  * \param out The es_out structure
859  * \param es es_out_id structure
860  * \param b_force ...
861  * \return nothing
862  */
863 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
864 {
865     es_out_sys_t      *p_sys = out->p_sys;
866
867     int i_cat = es->fmt.i_cat;
868
869     if( !p_sys->b_active ||
870         ( !b_force && es->fmt.i_priority < 0 ) )
871     {
872         return;
873     }
874
875     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
876     {
877         if( !es->p_dec )
878             EsSelect( out, es );
879     }
880     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
881     {
882         vlc_value_t val;
883         int i;
884         var_Get( p_sys->p_input, "programs", &val );
885         for ( i = 0; i < val.p_list->i_count; i++ )
886         {
887             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
888             {
889                 if( !es->p_dec )
890                     EsSelect( out, es );
891                 break;
892             }
893         }
894         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
895     }
896     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
897     {
898         int i_wanted  = -1;
899
900         if( es->p_pgrm != p_sys->p_pgrm )
901             return;
902
903         if( i_cat == AUDIO_ES )
904         {
905             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
906                                      es->psz_language_code );
907
908             if( p_sys->p_es_audio &&
909                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
910             {
911                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
912                                          p_sys->p_es_audio->psz_language_code );
913
914                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
915                     return;
916                 i_wanted = es->i_channel;
917             }
918             else
919             {
920                 /* Select audio if (no audio selected yet)
921                  * - no audio-language
922                  * - no audio code for the ES
923                  * - audio code in the requested list */
924                 if( idx1 >= 0 ||
925                     !strcmp( es->psz_language_code, "??" ) ||
926                     !p_sys->ppsz_audio_language )
927                     i_wanted = es->i_channel;
928             }
929
930             if( p_sys->i_audio_last >= 0 )
931                 i_wanted = p_sys->i_audio_last;
932
933             if( p_sys->i_audio_id >= 0 )
934             {
935                 if( es->i_id == p_sys->i_audio_id )
936                     i_wanted = es->i_channel;
937                 else
938                     return;
939             }
940         }
941         else if( i_cat == SPU_ES )
942         {
943             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
944                                      es->psz_language_code );
945
946             if( p_sys->p_es_sub &&
947                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
948             {
949                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
950                                          p_sys->p_es_sub->psz_language_code );
951
952                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
953                         idx1, es->psz_language_code, idx2,
954                         p_sys->p_es_sub->psz_language_code );
955
956                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
957                     return;
958                 /* We found a SPU that matches our language request */
959                 i_wanted  = es->i_channel;
960             }
961             else if( idx1 >= 0 )
962             {
963                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
964                         idx1, es->psz_language_code );
965
966                 i_wanted  = es->i_channel;
967             }
968             if( p_sys->i_sub_last >= 0 )
969                 i_wanted  = p_sys->i_sub_last;
970
971             if( p_sys->i_sub_id >= 0 )
972             {
973                 if( es->i_id == p_sys->i_sub_id )
974                     i_wanted = es->i_channel;
975                 else
976                     return;
977             }
978         }
979         else if( i_cat == VIDEO_ES )
980         {
981             i_wanted  = es->i_channel;
982         }
983
984         if( i_wanted == es->i_channel && es->p_dec == NULL )
985             EsSelect( out, es );
986     }
987
988     /* FIXME TODO handle priority here */
989     if( es->p_dec )
990     {
991         if( i_cat == AUDIO_ES )
992         {
993             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
994                 p_sys->p_es_audio &&
995                 p_sys->p_es_audio != es &&
996                 p_sys->p_es_audio->p_dec )
997             {
998                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
999             }
1000             p_sys->p_es_audio = es;
1001         }
1002         else if( i_cat == SPU_ES )
1003         {
1004             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1005                 p_sys->p_es_sub &&
1006                 p_sys->p_es_sub != es &&
1007                 p_sys->p_es_sub->p_dec )
1008             {
1009                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
1010             }
1011             p_sys->p_es_sub = es;
1012         }
1013         else if( i_cat == VIDEO_ES )
1014         {
1015             p_sys->p_es_video = es;
1016         }
1017     }
1018 }
1019
1020 /**
1021  * Send a block for the given es_out
1022  *
1023  * \param out the es_out to send from
1024  * \param es the es_out_id
1025  * \param p_block the data block to send
1026  */
1027 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1028 {
1029     es_out_sys_t *p_sys = out->p_sys;
1030     input_thread_t    *p_input = p_sys->p_input;
1031     es_out_pgrm_t *p_pgrm = es->p_pgrm;
1032     int64_t i_delay;
1033     int i_total=0;
1034
1035     if( es->fmt.i_cat == AUDIO_ES )
1036         i_delay = p_sys->i_audio_delay;
1037     else if( es->fmt.i_cat == SPU_ES )
1038         i_delay = p_sys->i_spu_delay;
1039     else
1040         i_delay = 0;
1041
1042     if( p_input->p_libvlc->b_stats )
1043     {
1044         vlc_mutex_lock( &p_input->p->counters.counters_lock );
1045         stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1046                              p_block->i_buffer, &i_total );
1047         stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1048                            (float)i_total, NULL );
1049         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1050     }
1051
1052     /* Mark preroll blocks */
1053     if( es->i_preroll_end >= 0 )
1054     {
1055         int64_t i_date = p_block->i_pts;
1056         if( i_date <= 0 )
1057             i_date = p_block->i_dts;
1058
1059         if( i_date < es->i_preroll_end )
1060             p_block->i_flags |= BLOCK_FLAG_PREROLL;
1061         else
1062             es->i_preroll_end = -1;
1063     }
1064
1065     /* +11 -> avoid null value with non null dts/pts */
1066     if( p_block->i_dts > 0 )
1067     {
1068         p_block->i_dts =
1069             input_ClockGetTS( p_input, &p_pgrm->clock,
1070                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
1071     }
1072     if( p_block->i_pts > 0 )
1073     {
1074         p_block->i_pts =
1075             input_ClockGetTS( p_input, &p_pgrm->clock,
1076                               ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
1077     }
1078     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1079     {
1080         mtime_t current_date = mdate();
1081         if( !p_block->i_pts
1082                || p_block->i_pts > current_date + 10000000
1083                || current_date > p_block->i_pts )
1084         {
1085             /* ETSI EN 300 472 Annex A : do not take into account the PTS
1086              * for teletext streams. */
1087             p_block->i_pts = current_date + 400000
1088                                + p_input->i_pts_delay + i_delay;
1089         }
1090     }
1091
1092     p_block->i_rate = p_input->p->i_rate;
1093
1094     /* TODO handle mute */
1095     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
1096         p_input->p->i_rate == INPUT_RATE_DEFAULT ) )
1097     {
1098         input_DecoderDecode( es->p_dec, p_block );
1099     }
1100     else
1101     {
1102         block_Release( p_block );
1103     }
1104
1105     return VLC_SUCCESS;
1106 }
1107
1108 /*****************************************************************************
1109  * EsOutDel:
1110  *****************************************************************************/
1111 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1112 {
1113     es_out_sys_t *p_sys = out->p_sys;
1114     vlc_bool_t b_reselect = VLC_FALSE;
1115     int i;
1116
1117     /* We don't try to reselect */
1118     if( es->p_dec )
1119         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1120
1121     if( es->p_pgrm == p_sys->p_pgrm )
1122         EsOutESVarUpdate( out, es, VLC_TRUE );
1123
1124     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1125
1126     es->p_pgrm->i_es--;
1127     if( es->p_pgrm->i_es == 0 )
1128     {
1129         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1130     }
1131
1132     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1133         p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
1134
1135     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1136     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1137     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
1138
1139     switch( es->fmt.i_cat )
1140     {
1141         case AUDIO_ES:
1142             p_sys->i_audio--;
1143             break;
1144         case SPU_ES:
1145             p_sys->i_sub--;
1146             break;
1147         case VIDEO_ES:
1148             p_sys->i_video--;
1149             break;
1150     }
1151
1152     /* Re-select another track when needed */
1153     if( b_reselect )
1154         for( i = 0; i < p_sys->i_es; i++ )
1155         {
1156             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1157                 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1158         }
1159
1160     if( es->psz_language )
1161         free( es->psz_language );
1162     if( es->psz_language_code )
1163         free( es->psz_language_code );
1164
1165     es_format_Clean( &es->fmt );
1166
1167     free( es );
1168 }
1169
1170 /**
1171  * Control query handler
1172  *
1173  * \param out the es_out to control
1174  * \param i_query A es_out query as defined in include/ninput.h
1175  * \param args a variable list of arguments for the query
1176  * \return VLC_SUCCESS or an error code
1177  */
1178 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1179 {
1180     es_out_sys_t *p_sys = out->p_sys;
1181     vlc_bool_t  b, *pb;
1182     int         i, *pi;
1183
1184     es_out_id_t *es;
1185
1186     switch( i_query )
1187     {
1188         case ES_OUT_SET_ES_STATE:
1189             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1190             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1191             if( b && es->p_dec == NULL )
1192             {
1193                 EsSelect( out, es );
1194                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
1195             }
1196             else if( !b && es->p_dec )
1197             {
1198                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1199                 return VLC_SUCCESS;
1200             }
1201             return VLC_SUCCESS;
1202
1203         case ES_OUT_GET_ES_STATE:
1204             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1205             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1206
1207             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
1208             return VLC_SUCCESS;
1209
1210         case ES_OUT_SET_ACTIVE:
1211         {
1212             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1213             p_sys->b_active = b;
1214             /* Needed ? */
1215             if( b )
1216                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1217             return VLC_SUCCESS;
1218         }
1219
1220         case ES_OUT_GET_ACTIVE:
1221             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1222             *pb = p_sys->b_active;
1223             return VLC_SUCCESS;
1224
1225         case ES_OUT_SET_MODE:
1226             i = (int) va_arg( args, int );
1227             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1228                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1229             {
1230                 p_sys->i_mode = i;
1231
1232                 /* Reapply policy mode */
1233                 for( i = 0; i < p_sys->i_es; i++ )
1234                 {
1235                     if( p_sys->es[i]->p_dec )
1236                     {
1237                         EsUnselect( out, p_sys->es[i],
1238                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1239                     }
1240                 }
1241                 for( i = 0; i < p_sys->i_es; i++ )
1242                 {
1243                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1244                 }
1245                 return VLC_SUCCESS;
1246             }
1247             return VLC_EGENERIC;
1248
1249         case ES_OUT_GET_MODE:
1250             pi = (int*) va_arg( args, int* );
1251             *pi = p_sys->i_mode;
1252             return VLC_SUCCESS;
1253
1254         case ES_OUT_SET_ES:
1255             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1256             /* Special case NULL, NULL+i_cat */
1257             if( es == NULL )
1258             {
1259                 for( i = 0; i < p_sys->i_es; i++ )
1260                 {
1261                     if( p_sys->es[i]->p_dec )
1262                         EsUnselect( out, p_sys->es[i],
1263                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1264                 }
1265             }
1266             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1267             {
1268                 for( i = 0; i < p_sys->i_es; i++ )
1269                 {
1270                     if( p_sys->es[i]->p_dec &&
1271                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
1272                         EsUnselect( out, p_sys->es[i],
1273                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1274                 }
1275             }
1276             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1277             {
1278                 for( i = 0; i < p_sys->i_es; i++ )
1279                 {
1280                     if( p_sys->es[i]->p_dec &&
1281                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
1282                         EsUnselect( out, p_sys->es[i],
1283                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1284                 }
1285             }
1286             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1287             {
1288                 for( i = 0; i < p_sys->i_es; i++ )
1289                 {
1290                     if( p_sys->es[i]->p_dec &&
1291                         p_sys->es[i]->fmt.i_cat == SPU_ES )
1292                         EsUnselect( out, p_sys->es[i],
1293                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1294                 }
1295             }
1296             else
1297             {
1298                 for( i = 0; i < p_sys->i_es; i++ )
1299                 {
1300                     if( es == p_sys->es[i] )
1301                     {
1302                         EsOutSelect( out, es, VLC_TRUE );
1303                         break;
1304                     }
1305                 }
1306             }
1307             {
1308                 playlist_t * p_playlist = pl_Yield( p_sys->p_input );
1309                 PL_LOCK;
1310                 p_playlist->gc_date = mdate();
1311                 vlc_cond_signal( &p_playlist->object_wait );
1312                 PL_UNLOCK;
1313                 pl_Release( p_playlist );
1314             }
1315             return VLC_SUCCESS;
1316
1317         case ES_OUT_SET_PCR:
1318         case ES_OUT_SET_GROUP_PCR:
1319         {
1320             es_out_pgrm_t *p_pgrm = NULL;
1321             int            i_group = 0;
1322             int64_t        i_pcr;
1323
1324             if( i_query == ES_OUT_SET_PCR )
1325             {
1326                 p_pgrm = p_sys->p_pgrm;
1327             }
1328             else
1329             {
1330                 int i;
1331                 i_group = (int)va_arg( args, int );
1332                 for( i = 0; i < p_sys->i_pgrm; i++ )
1333                 {
1334                     if( p_sys->pgrm[i]->i_id == i_group )
1335                     {
1336                         p_pgrm = p_sys->pgrm[i];
1337                         break;
1338                     }
1339                 }
1340             }
1341             if( p_pgrm == NULL )
1342                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1343
1344             i_pcr = (int64_t)va_arg( args, int64_t );
1345             /* search program */
1346             /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
1347             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
1348                                (i_pcr + 11 ) * 9 / 100);
1349             return VLC_SUCCESS;
1350         }
1351
1352         case ES_OUT_RESET_PCR:
1353             for( i = 0; i < p_sys->i_pgrm; i++ )
1354             {
1355                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
1356                 p_sys->pgrm[i]->clock.last_pts = 0;
1357             }
1358             return VLC_SUCCESS;
1359
1360         case ES_OUT_GET_TS:
1361             if( p_sys->p_pgrm )
1362             {
1363                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1364                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1365                 *pi_ts = input_ClockGetTS( p_sys->p_input,
1366                                            &p_sys->p_pgrm->clock,
1367                                            ( i_ts + 11 ) * 9 / 100 );
1368                 return VLC_SUCCESS;
1369             }
1370             return VLC_EGENERIC;
1371
1372         case ES_OUT_GET_GROUP:
1373             pi = (int*) va_arg( args, int* );
1374             if( p_sys->p_pgrm )
1375                 *pi = p_sys->p_pgrm->i_id;
1376             else
1377                 *pi = -1;    /* FIXME */
1378             return VLC_SUCCESS;
1379
1380         case ES_OUT_SET_GROUP:
1381         {
1382             int j;
1383             i = (int) va_arg( args, int );
1384             for( j = 0; j < p_sys->i_pgrm; j++ )
1385             {
1386                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1387                 if( p_pgrm->i_id == i )
1388                 {
1389                     EsOutProgramSelect( out, p_pgrm );
1390                     return VLC_SUCCESS;
1391                 }
1392             }
1393             return VLC_EGENERIC;
1394         }
1395
1396         case ES_OUT_SET_FMT:
1397         {
1398             /* This ain't pretty but is need by some demuxers (eg. Ogg )
1399              * to update the p_extra data */
1400             es_format_t *p_fmt;
1401             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1402             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1403             if( es == NULL ) return VLC_EGENERIC;
1404
1405             if( p_fmt->i_extra )
1406             {
1407                 es->fmt.i_extra = p_fmt->i_extra;
1408                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1409                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1410
1411                 if( !es->p_dec ) return VLC_SUCCESS;
1412
1413 #if 1
1414                 input_DecoderDelete( es->p_dec );
1415                 es->p_dec = input_DecoderNew( p_sys->p_input,
1416                                               &es->fmt, VLC_FALSE );
1417
1418 #else
1419                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1420                 es->p_dec->fmt_in.p_extra =
1421                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1422                 memcpy( es->p_dec->fmt_in.p_extra,
1423                         p_fmt->p_extra, p_fmt->i_extra );
1424 #endif
1425             }
1426
1427             return VLC_SUCCESS;
1428         }
1429
1430         case ES_OUT_SET_NEXT_DISPLAY_TIME:
1431         {
1432             int64_t i_date;
1433
1434             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1435             i_date = (int64_t)va_arg( args, int64_t );
1436
1437             if( !es || !es->p_dec )
1438                 return VLC_EGENERIC;
1439
1440             es->i_preroll_end = i_date;
1441             input_DecoderPreroll( es->p_dec, i_date );
1442
1443             return VLC_SUCCESS;
1444         }
1445         case ES_OUT_SET_GROUP_META:
1446         {
1447             int i_group = (int)va_arg( args, int );
1448             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1449
1450             EsOutProgramMeta( out, i_group, p_meta );
1451             return VLC_SUCCESS;
1452         }
1453         case ES_OUT_DEL_GROUP:
1454         {
1455             int i_group = (int)va_arg( args, int );
1456
1457             return EsOutProgramDel( out, i_group );
1458         }
1459
1460         default:
1461             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1462             return VLC_EGENERIC;
1463     }
1464 }
1465
1466 /****************************************************************************
1467  * LanguageGetName: try to expend iso639 into plain name
1468  ****************************************************************************/
1469 static char *LanguageGetName( const char *psz_code )
1470 {
1471     const iso639_lang_t *pl;
1472
1473     if( psz_code == NULL )
1474     {
1475         return strdup( "" );
1476     }
1477
1478     if( strlen( psz_code ) == 2 )
1479     {
1480         pl = GetLang_1( psz_code );
1481     }
1482     else if( strlen( psz_code ) == 3 )
1483     {
1484         pl = GetLang_2B( psz_code );
1485         if( !strcmp( pl->psz_iso639_1, "??" ) )
1486         {
1487             pl = GetLang_2T( psz_code );
1488         }
1489     }
1490     else
1491     {
1492         return strdup( psz_code );
1493     }
1494
1495     if( !strcmp( pl->psz_iso639_1, "??" ) )
1496     {
1497        return strdup( psz_code );
1498     }
1499     else
1500     {
1501         if( *pl->psz_native_name )
1502         {
1503             return strdup( pl->psz_native_name );
1504         }
1505         return strdup( pl->psz_eng_name );
1506     }
1507 }
1508
1509 /* Get a 2 char code */
1510 static char *LanguageGetCode( const char *psz_lang )
1511 {
1512     const iso639_lang_t *pl;
1513
1514     if( psz_lang == NULL || *psz_lang == '\0' )
1515         return strdup("??");
1516
1517     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1518     {
1519         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1520             !strcasecmp( pl->psz_native_name, psz_lang ) ||
1521             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1522             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1523             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1524             break;
1525     }
1526
1527     if( pl->psz_iso639_1 != NULL )
1528         return strdup( pl->psz_iso639_1 );
1529
1530     return strdup("??");
1531 }
1532
1533 static char **LanguageSplit( const char *psz_langs )
1534 {
1535     char *psz_dup;
1536     char *psz_parser;
1537     char **ppsz = NULL;
1538     int i_psz = 0;
1539
1540     if( psz_langs == NULL ) return NULL;
1541
1542     psz_parser = psz_dup = strdup(psz_langs);
1543
1544     while( psz_parser && *psz_parser )
1545     {
1546         char *psz;
1547         char *psz_code;
1548
1549         psz = strchr(psz_parser, ',' );
1550         if( psz ) *psz++ = '\0';
1551
1552         psz_code = LanguageGetCode( psz_parser );
1553         if( strcmp( psz_code, "??" ) )
1554         {
1555             TAB_APPEND( i_psz, ppsz, psz_code );
1556         }
1557
1558         psz_parser = psz;
1559     }
1560
1561     if( i_psz )
1562     {
1563         TAB_APPEND( i_psz, ppsz, NULL );
1564     }
1565
1566     free( psz_dup );
1567     return ppsz;
1568 }
1569
1570 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1571 {
1572     int i;
1573
1574     if( !ppsz_langs || !psz_lang ) return -1;
1575
1576     for( i = 0; ppsz_langs[i]; i++ )
1577         if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i;
1578
1579     return -1;
1580 }
1581
1582 /****************************************************************************
1583  * EsOutAddInfo:
1584  * - add meta info to the playlist item
1585  ****************************************************************************/
1586 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1587 {
1588     es_out_sys_t   *p_sys = out->p_sys;
1589     input_thread_t *p_input = p_sys->p_input;
1590     es_format_t    *fmt = &es->fmt;
1591     char           *psz_cat;
1592     lldiv_t         div;
1593
1594     /* Add stream info */
1595     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1596
1597     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1598                    "%.4s", (char*)&fmt->i_codec );
1599
1600     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1601                    "%s", es->psz_language );
1602
1603     /* Add information */
1604     switch( fmt->i_cat )
1605     {
1606     case AUDIO_ES:
1607         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1608                        _("Type"), _("Audio") );
1609
1610         if( fmt->audio.i_channels > 0 )
1611             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1612                            "%d", fmt->audio.i_channels );
1613
1614         if( fmt->audio.i_rate > 0 )
1615         {
1616             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
1617                            _("%d Hz"), fmt->audio.i_rate );
1618             var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
1619         }
1620
1621         if( fmt->audio.i_bitspersample > 0 )
1622             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1623                            _("Bits per sample"), "%d",
1624                            fmt->audio.i_bitspersample );
1625
1626         if( fmt->i_bitrate > 0 )
1627         {
1628             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
1629                            _("%d kb/s"), fmt->i_bitrate / 1000 );
1630             var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
1631         }
1632         break;
1633
1634     case VIDEO_ES:
1635         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1636                        _("Type"), _("Video") );
1637
1638         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
1639             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1640                            _("Resolution"), "%dx%d",
1641                            fmt->video.i_width, fmt->video.i_height );
1642
1643         if( fmt->video.i_visible_width > 0 &&
1644             fmt->video.i_visible_height > 0 )
1645             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1646                            _("Display resolution"), "%dx%d",
1647                            fmt->video.i_visible_width,
1648                            fmt->video.i_visible_height);
1649        if( fmt->video.i_frame_rate > 0 &&
1650            fmt->video.i_frame_rate_base > 0 )
1651        {
1652            div = lldiv( (float)fmt->video.i_frame_rate /
1653                                fmt->video.i_frame_rate_base * 1000000,
1654                                1000000 );
1655            input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1656                           _("Frame rate"), I64Fd".%06u",
1657                           div.quot, (unsigned int )div.rem );
1658        }
1659        break;
1660
1661     case SPU_ES:
1662         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1663                        _("Type"), _("Subtitle") );
1664         break;
1665
1666     default:
1667         break;
1668     }
1669
1670     free( psz_cat );
1671 }