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