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