]> git.sesse.net Git - vlc/blob - src/input/es_out.c
es_out: Put a msg_Dbg in input_EsOutDelete.
[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 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc/vlc.h>
33
34 #include <stdio.h>
35
36 #include <vlc_input.h>
37 #include <vlc_es_out.h>
38 #include <vlc_block.h>
39 #include <vlc_aout.h>
40
41 #include "input_internal.h"
42
43 #include "vlc_playlist.h"
44 #include "iso_lang.h"
45 /* FIXME we should find a better way than including that */
46 #include "../text/iso-639_def.h"
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 typedef struct
52 {
53     /* Program ID */
54     int i_id;
55
56     /* Number of es for this pgrm */
57     int i_es;
58
59     vlc_bool_t b_selected;
60
61     /* Clock for this program */
62     input_clock_t clock;
63
64     char    *psz_name;
65     char    *psz_now_playing;
66     char    *psz_publisher;
67
68     vlc_epg_t *p_epg;
69 } es_out_pgrm_t;
70
71 struct es_out_id_t
72 {
73     /* ES ID */
74     int       i_id;
75     es_out_pgrm_t *p_pgrm;
76
77     /* Misc. */
78     int64_t i_preroll_end;
79
80     /* Channel in the track type */
81     int         i_channel;
82     es_format_t fmt;
83     char        *psz_language;
84     char        *psz_language_code;
85
86     decoder_t   *p_dec;
87
88     /* Fields for Video with CC */
89     vlc_bool_t  pb_cc_present[4];
90     es_out_id_t  *pp_cc_es[4];
91
92     /* Field for CC track from a master video */
93     es_out_id_t *p_master;
94 };
95
96 struct es_out_sys_t
97 {
98     input_thread_t *p_input;
99
100     /* all programs */
101     int           i_pgrm;
102     es_out_pgrm_t **pgrm;
103     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
104     es_out_pgrm_t *p_pgrm;  /* Master program */
105
106     /* all es */
107     int         i_id;
108     int         i_es;
109     es_out_id_t **es;
110
111     /* mode gestion */
112     vlc_bool_t  b_active;
113     int         i_mode;
114
115     /* es count */
116     int         i_audio;
117     int         i_video;
118     int         i_sub;
119
120     /* es to select */
121     int         i_audio_last, i_audio_id;
122     int         i_sub_last, i_sub_id;
123     int         i_default_sub_id;   /* As specified in container; if applicable */
124     char        **ppsz_audio_language;
125     char        **ppsz_sub_language;
126
127     /* current main es */
128     es_out_id_t *p_es_audio;
129     es_out_id_t *p_es_video;
130     es_out_id_t *p_es_sub;
131
132     /* delay */
133     int64_t i_audio_delay;
134     int64_t i_spu_delay;
135
136     /* Rate used to rescale ES ts */
137     int         i_rate;
138 };
139
140 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
141 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
142 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
143 static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
144 static int          EsOutControl( es_out_t *, int i_query, va_list );
145
146 static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
147
148 static vlc_bool_t EsIsSelected( es_out_id_t *es );
149 static void EsSelect( es_out_t *out, es_out_id_t *es );
150 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
151 static char *LanguageGetName( const char *psz_code );
152 static char *LanguageGetCode( const char *psz_lang );
153 static char **LanguageSplit( const char *psz_langs );
154 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
155
156 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
157
158 static const vlc_fourcc_t EsOutFourccClosedCaptions[4] = {
159     VLC_FOURCC('c', 'c', '1', ' '),
160     VLC_FOURCC('c', 'c', '2', ' '),
161     VLC_FOURCC('c', 'c', '3', ' '),
162     VLC_FOURCC('c', 'c', '4', ' '),
163 };
164 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc )
165 {
166     int i;
167     for( i = 0; i < 4; i++ )
168     {
169         if( fcc == EsOutFourccClosedCaptions[i] )
170             return i;
171     }
172     return -1;
173 }
174
175
176 /*****************************************************************************
177  * input_EsOutNew:
178  *****************************************************************************/
179 es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
180 {
181     es_out_t     *out = malloc( sizeof( es_out_t ) );
182     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
183     vlc_value_t  val;
184     int i;
185
186     out->pf_add     = EsOutAdd;
187     out->pf_send    = EsOutSend;
188     out->pf_del     = EsOutDel;
189     out->pf_control = EsOutControl;
190     out->p_sys      = p_sys;
191     out->b_sout     = (p_input->p->p_sout != NULL ? VLC_TRUE : VLC_FALSE);
192
193     p_sys->p_input = p_input;
194
195     p_sys->b_active = VLC_FALSE;
196     p_sys->i_mode   = ES_OUT_MODE_AUTO;
197
198
199     TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
200     p_sys->p_pgrm   = NULL;
201
202     p_sys->i_id    = 0;
203
204     TAB_INIT( p_sys->i_es, p_sys->es );
205
206     p_sys->i_audio = 0;
207     p_sys->i_video = 0;
208     p_sys->i_sub   = 0;
209
210     /* */
211     var_Get( p_input, "audio-track", &val );
212     p_sys->i_audio_last = val.i_int;
213
214     var_Get( p_input, "sub-track", &val );
215     p_sys->i_sub_last = val.i_int;
216
217     p_sys->i_default_sub_id   = -1;
218
219     if( !p_input->b_preparsing )
220     {
221         var_Get( p_input, "audio-language", &val );
222         p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
223         if( p_sys->ppsz_audio_language )
224         {
225             for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
226                 msg_Dbg( p_input, "selected audio language[%d] %s",
227                          i, p_sys->ppsz_audio_language[i] );
228         }
229         free( val.psz_string );
230
231         var_Get( p_input, "sub-language", &val );
232         p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
233         if( p_sys->ppsz_sub_language )
234         {
235             for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
236                 msg_Dbg( p_input, "selected subtitle language[%d] %s",
237                          i, p_sys->ppsz_sub_language[i] );
238         }
239         free( val.psz_string );
240     }
241     else
242     {
243         p_sys->ppsz_sub_language = NULL;
244         p_sys->ppsz_audio_language = NULL;
245     }
246
247     var_Get( p_input, "audio-track-id", &val );
248     p_sys->i_audio_id = val.i_int;
249
250     var_Get( p_input, "sub-track-id", &val );
251     p_sys->i_sub_id = val.i_int;
252
253     p_sys->p_es_audio = NULL;
254     p_sys->p_es_video = NULL;
255     p_sys->p_es_sub   = NULL;
256
257     p_sys->i_audio_delay= 0;
258     p_sys->i_spu_delay  = 0;
259
260     p_sys->i_rate = i_rate;
261
262     return out;
263 }
264
265 /*****************************************************************************
266  * input_EsOutDelete:
267  *****************************************************************************/
268 void input_EsOutDelete( es_out_t *out )
269 {
270     es_out_sys_t *p_sys = out->p_sys;
271     int i;
272
273     msg_Dbg( out, "deleting es out" );
274
275     for( i = 0; i < p_sys->i_es; i++ )
276     {
277         if( p_sys->es[i]->p_dec )
278         {
279             input_DecoderDelete( p_sys->es[i]->p_dec );
280         }
281         free( p_sys->es[i]->psz_language );
282         free( p_sys->es[i]->psz_language_code );
283         es_format_Clean( &p_sys->es[i]->fmt );
284
285         free( p_sys->es[i] );
286     }
287     if( p_sys->ppsz_audio_language )
288     {
289         for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
290             free( p_sys->ppsz_audio_language[i] );
291         free( p_sys->ppsz_audio_language );
292     }
293     if( p_sys->ppsz_sub_language )
294     {
295         for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
296             free( p_sys->ppsz_sub_language[i] );
297         free( p_sys->ppsz_sub_language );
298     }
299
300     free( p_sys->es );
301
302     /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
303     for( i = 0; i < p_sys->i_pgrm; i++ )
304     {
305         es_out_pgrm_t *p_pgrm = p_sys->pgrm[i];
306         free( p_pgrm->psz_now_playing );
307         free( p_pgrm->psz_publisher );
308         free( p_pgrm->psz_name );
309         if( p_pgrm->p_epg )
310             vlc_epg_Delete( p_pgrm->p_epg );
311
312         free( p_pgrm );
313     }
314     TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
315
316     free( p_sys );
317     free( out );
318 }
319
320 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
321 {
322     int i;
323     if( i_id < 0 )
324     {
325         /* Special HACK, -i_id is tha cat of the stream */
326         return (es_out_id_t*)((uint8_t*)NULL-i_id);
327     }
328
329     for( i = 0; i < out->p_sys->i_es; i++ )
330     {
331         if( out->p_sys->es[i]->i_id == i_id )
332             return out->p_sys->es[i];
333     }
334     return NULL;
335 }
336
337 static void EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio )
338 {
339     es_out_sys_t      *p_sys = out->p_sys;
340     int i;
341
342     for( i = 0; i < p_sys->i_es; i++ )
343     {
344         es_out_id_t *es = p_sys->es[i];
345
346         /* Send a dummy block to let decoder know that
347          * there is a discontinuity */
348         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
349             input_DecoderDiscontinuity( es->p_dec, b_flush );
350     }
351 }
352 void input_EsOutChangeRate( es_out_t *out, int i_rate )
353 {
354     es_out_sys_t      *p_sys = out->p_sys;
355     int i;
356
357     p_sys->i_rate = i_rate;
358     EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE );
359
360     for( i = 0; i < p_sys->i_pgrm; i++ )
361         input_ClockSetRate( &p_sys->pgrm[i]->clock, i_rate );
362 }
363
364 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
365 {
366     es_out_sys_t *p_sys = out->p_sys;
367
368     if( i_cat == AUDIO_ES )
369         p_sys->i_audio_delay = i_delay;
370     else if( i_cat == SPU_ES )
371         p_sys->i_spu_delay = i_delay;
372 }
373 void input_EsOutChangeState( es_out_t *out )
374 {
375     es_out_sys_t *p_sys = out->p_sys;
376     input_thread_t *p_input = p_sys->p_input;
377
378     if( p_input->i_state  == PAUSE_S )
379     {
380         /* Send discontinuity to decoders (it will allow them to flush
381          *                  * if implemented */
382         EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE );
383     }
384     else
385     {
386         /* Out of pause, reset pcr */
387         es_out_Control( out, ES_OUT_RESET_PCR );
388     }
389 }
390 void input_EsOutChangePosition( es_out_t *out )
391 {
392     //es_out_sys_t *p_sys = out->p_sys;
393
394     es_out_Control( out, ES_OUT_RESET_PCR );
395     EsOutDiscontinuity( out, VLC_TRUE, VLC_FALSE );
396 }
397
398 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
399 {
400     es_out_sys_t      *p_sys = out->p_sys;
401     int i;
402
403     for( i = 0; i < p_sys->i_es; i++ )
404     {
405         es_out_id_t *es = p_sys->es[i];
406
407         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
408             return VLC_FALSE;
409     }
410     return VLC_TRUE;
411 }
412
413 /*****************************************************************************
414  *
415  *****************************************************************************/
416 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
417                                      vlc_bool_t b_delete )
418 {
419     es_out_sys_t      *p_sys = out->p_sys;
420     input_thread_t    *p_input = p_sys->p_input;
421     vlc_value_t       val, text;
422
423     const char *psz_var;
424
425     if( fmt->i_cat == AUDIO_ES )
426         psz_var = "audio-es";
427     else if( fmt->i_cat == VIDEO_ES )
428         psz_var = "video-es";
429     else if( fmt->i_cat == SPU_ES )
430         psz_var = "spu-es";
431     else
432         return;
433
434     if( b_delete )
435     {
436         val.i_int = i_id;
437         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
438         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
439         return;
440     }
441
442     /* Get the number of ES already added */
443     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
444     if( val.i_int == 0 )
445     {
446         vlc_value_t val2;
447
448         /* First one, we need to add the "Disable" choice */
449         val2.i_int = -1; text.psz_string = _("Disable");
450         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
451         val.i_int++;
452     }
453
454     /* Take care of the ES description */
455     if( fmt->psz_description && *fmt->psz_description )
456     {
457         if( psz_language && *psz_language )
458         {
459             text.psz_string = malloc( strlen( fmt->psz_description) +
460                                       strlen( psz_language ) + 10 );
461             sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
462                                                    psz_language );
463         }
464         else text.psz_string = strdup( fmt->psz_description );
465     }
466     else
467     {
468         if( psz_language && *psz_language )
469         {
470             char *temp;
471             text.psz_string = malloc( strlen( _("Track %i") )+
472                                       strlen( psz_language ) + 30 );
473             asprintf( &temp,  _("Track %i"), val.i_int );
474             sprintf( text.psz_string, "%s - [%s]", temp, psz_language );
475             free( temp );
476         }
477         else
478         {
479             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
480             sprintf( text.psz_string, _("Track %i"), val.i_int );
481         }
482     }
483
484     val.i_int = i_id;
485     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
486
487     free( text.psz_string );
488
489     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
490 }
491
492 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
493                               vlc_bool_t b_delete )
494 {
495     EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
496 }
497
498 /* EsOutProgramSelect:
499  *  Select a program and update the object variable
500  */
501 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
502 {
503     es_out_sys_t      *p_sys = out->p_sys;
504     input_thread_t    *p_input = p_sys->p_input;
505     vlc_value_t       val;
506     int               i;
507
508     if( p_sys->p_pgrm == p_pgrm )
509         return; /* Nothing to do */
510
511     if( p_sys->p_pgrm )
512     {
513         es_out_pgrm_t *old = p_sys->p_pgrm;
514         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
515
516         for( i = 0; i < p_sys->i_es; i++ )
517         {
518             if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
519                 p_sys->i_mode != ES_OUT_MODE_ALL )
520                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
521         }
522
523         p_sys->p_es_audio = NULL;
524         p_sys->p_es_sub = NULL;
525         p_sys->p_es_video = NULL;
526     }
527
528     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
529
530     /* Mark it selected */
531     p_pgrm->b_selected = VLC_TRUE;
532
533     /* Switch master stream */
534     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
535     {
536         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
537     }
538     p_pgrm->clock.b_master = VLC_TRUE;
539     p_sys->p_pgrm = p_pgrm;
540
541     /* Update "program" */
542     val.i_int = p_pgrm->i_id;
543     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
544
545     /* Update "es-*" */
546     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
547     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
548     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
549     for( i = 0; i < p_sys->i_es; i++ )
550     {
551         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
552             EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
553         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
554     }
555
556     /* Update now playing */
557     input_item_SetNowPlaying( p_input->p->input.p_item,
558                               p_pgrm->psz_now_playing );
559     input_item_SetPublisher( p_input->p->input.p_item,
560                              p_pgrm->psz_publisher );
561
562     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
563 }
564
565 /* EsOutAddProgram:
566  *  Add a program
567  */
568 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
569 {
570     es_out_sys_t      *p_sys = out->p_sys;
571     input_thread_t    *p_input = p_sys->p_input;
572     vlc_value_t       val;
573
574     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
575
576     /* Init */
577     p_pgrm->i_id = i_group;
578     p_pgrm->i_es = 0;
579     p_pgrm->b_selected = VLC_FALSE;
580     p_pgrm->psz_name = NULL;
581     p_pgrm->psz_now_playing = NULL;
582     p_pgrm->psz_publisher = NULL;
583     p_pgrm->p_epg = NULL;
584     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average, p_sys->i_rate );
585
586     /* Append it */
587     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
588
589     /* Update "program" variable */
590     val.i_int = i_group;
591     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
592
593     if( i_group == var_GetInteger( p_input, "program" ) )
594     {
595         EsOutProgramSelect( out, p_pgrm );
596     }
597     else
598     {
599         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
600     }
601     return p_pgrm;
602 }
603
604 /* EsOutDelProgram:
605  *  Delete a program
606  */
607 static int EsOutProgramDel( es_out_t *out, int i_group )
608 {
609     es_out_sys_t      *p_sys = out->p_sys;
610     input_thread_t    *p_input = p_sys->p_input;
611     es_out_pgrm_t     *p_pgrm = NULL;
612     vlc_value_t       val;
613     int               i;
614
615     for( i = 0; i < p_sys->i_pgrm; i++ )
616     {
617         if( p_sys->pgrm[i]->i_id == i_group )
618         {
619             p_pgrm = p_sys->pgrm[i];
620             break;
621         }
622     }
623
624     if( p_pgrm == NULL )
625         return VLC_EGENERIC;
626
627     if( p_pgrm->i_es )
628     {
629         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
630                  i_group, p_pgrm->i_es );
631         return VLC_EGENERIC;
632     }
633
634     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
635
636     /* If program is selected we need to unselect it */
637     if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL;
638
639     free( p_pgrm->psz_name );
640     free( p_pgrm->psz_now_playing );
641     free( p_pgrm->psz_publisher );
642     if( p_pgrm->p_epg )
643         vlc_epg_Delete( p_pgrm->p_epg );
644     free( p_pgrm );
645
646     /* Update "program" variable */
647     val.i_int = i_group;
648     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
649
650     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
651
652     return VLC_SUCCESS;
653 }
654
655 /* EsOutProgramMeta:
656  */
657 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
658 {
659     char *psz = NULL;
660     if( p_pgrm->psz_name )
661         asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id );
662     else
663         asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id );
664     return psz;
665 }
666
667 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
668 {
669     es_out_sys_t      *p_sys = out->p_sys;
670     es_out_pgrm_t     *p_pgrm = NULL;
671     input_thread_t    *p_input = p_sys->p_input;
672     char              *psz_cat;
673     const char        *psz_title = NULL;
674     const char        *psz_provider = NULL;
675     int i;
676
677     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
678
679     /* Check against empty meta data (empty for what we handle) */
680     if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
681         !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
682         !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
683         vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
684     {
685         return;
686     }
687     /* Find program */
688     for( i = 0; i < p_sys->i_pgrm; i++ )
689     {
690         if( p_sys->pgrm[i]->i_id == i_group )
691         {
692             p_pgrm = p_sys->pgrm[i];
693             break;
694         }
695     }
696     if( p_pgrm == NULL )
697         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
698
699     /* */
700     psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
701     psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
702
703     /* Update the description text of the program */
704     if( psz_title && *psz_title )
705     {
706         vlc_value_t val;
707         vlc_value_t text;
708
709         if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
710         {
711             char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
712
713             /* Remove old entries */
714             input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
715             /* TODO update epg name */
716             free( psz_cat );
717         }
718         free( p_pgrm->psz_name );
719         p_pgrm->psz_name = strdup( psz_title );
720
721         /* ugly but it works */
722         val.i_int = i_group;
723         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
724
725         if( psz_provider && *psz_provider )
726         {
727             asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider );
728             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
729             free( text.psz_string );
730         }
731         else
732         {
733             text.psz_string = (char *)psz_title;
734             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
735         }
736     }
737
738     psz_cat = EsOutProgramGetMetaName( p_pgrm );
739     if( psz_provider )
740     {
741         if( p_sys->p_pgrm == p_pgrm )
742             input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
743         input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
744     }
745     char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
746     for( i = 0; ppsz_all_keys[i]; i++ )
747     {
748         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
749                        vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
750         free( ppsz_all_keys[i] );
751     }
752     free( ppsz_all_keys );
753
754     free( psz_cat );
755 }
756
757 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
758 {
759     int i;
760
761     /* Add new event */
762     for( i = 0; i < p_src->i_event; i++ )
763     {
764         vlc_epg_event_t *p_evt = p_src->pp_event[i];
765         vlc_bool_t b_add = VLC_TRUE;
766         int j;
767
768         for( j = 0; j < p_dst->i_event; j++ )
769         {
770             if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
771             {
772                 b_add = VLC_FALSE;
773                 break;
774             }
775             if( p_dst->pp_event[j]->i_start > p_evt->i_start )
776                 break;
777         }
778         if( b_add )
779         {
780             vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
781             if( !p_copy )
782                 break;
783             memset( p_copy, 0, sizeof(vlc_epg_event_t) );
784             p_copy->i_start = p_evt->i_start;
785             p_copy->i_duration = p_evt->i_duration;
786             p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
787             p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
788             p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
789             TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
790         }
791     }
792     /* Update current */
793     vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
794
795     /* Keep only 1 old event  */
796     if( p_dst->p_current )
797     {
798         while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
799             TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
800     }
801 }
802
803 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
804 {
805     es_out_sys_t      *p_sys = out->p_sys;
806     input_thread_t    *p_input = p_sys->p_input;
807     es_out_pgrm_t     *p_pgrm = NULL;
808     char *psz_cat;
809     int i;
810
811     /* Find program */
812     for( i = 0; i < p_sys->i_pgrm; i++ )
813     {
814         if( p_sys->pgrm[i]->i_id == i_group )
815         {
816             p_pgrm = p_sys->pgrm[i];
817             break;
818         }
819     }
820     if( p_pgrm == NULL )
821         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
822
823     /* Merge EPG */
824     if( !p_pgrm->p_epg )
825         p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
826     vlc_epg_Merge( p_pgrm->p_epg, p_epg );
827
828     /* Update info */
829     psz_cat = EsOutProgramGetMetaName( p_pgrm );
830 #ifdef HAVE_LOCALTIME_R
831     char *psz_epg;
832     if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
833         psz_epg = NULL;
834     input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
835     msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
836     for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
837     {
838         const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
839         time_t t_start = (time_t)p_evt->i_start;
840         struct tm tm_start;
841         char psz_start[128];
842
843         localtime_r( &t_start, &tm_start );
844
845         snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
846         if( p_evt->psz_short_description || p_evt->psz_description )
847             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
848                            p_evt->psz_name,
849                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
850                            p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
851         else
852             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
853                            p_evt->psz_name,
854                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
855     }
856     free( psz_epg );
857 #endif
858     /* Update now playing */
859     free( p_pgrm->psz_now_playing );
860     p_pgrm->psz_now_playing = NULL;
861     if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
862         p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
863
864     if( p_pgrm == p_sys->p_pgrm )
865         input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
866
867     if( p_pgrm->psz_now_playing )
868     {
869         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
870             input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
871             p_pgrm->psz_now_playing );
872     }
873     else
874     {
875         input_Control( p_input, INPUT_DEL_INFO, psz_cat,
876             input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
877     }
878
879     free( psz_cat );
880 }
881
882 /* EsOutAdd:
883  *  Add an es_out
884  */
885 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
886 {
887     es_out_sys_t      *p_sys = out->p_sys;
888     input_thread_t    *p_input = p_sys->p_input;
889
890     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
891     es_out_pgrm_t     *p_pgrm = NULL;
892     int i;
893
894     if( fmt->i_group < 0 )
895     {
896         msg_Err( p_input, "invalid group number" );
897         return NULL;
898     }
899
900     /* Search the program */
901     for( i = 0; i < p_sys->i_pgrm; i++ )
902     {
903         if( fmt->i_group == p_sys->pgrm[i]->i_id )
904         {
905             p_pgrm = p_sys->pgrm[i];
906             break;
907         }
908     }
909     if( p_pgrm == NULL )
910     {
911         /* Create a new one */
912         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
913     }
914
915     /* Increase ref count for program */
916     p_pgrm->i_es++;
917
918     /* Set up ES */
919     if( fmt->i_id < 0 )
920         fmt->i_id = out->p_sys->i_id;
921     es->i_id = fmt->i_id;
922     es->p_pgrm = p_pgrm;
923     es_format_Copy( &es->fmt, fmt );
924     es->i_preroll_end = -1;
925
926     switch( fmt->i_cat )
927     {
928     case AUDIO_ES:
929     {
930         audio_replay_gain_t rg;
931
932         es->i_channel = p_sys->i_audio;
933
934         vlc_mutex_lock( &p_input->p->input.p_item->lock );
935         memset( &rg, 0, sizeof(rg) );
936         vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
937         vlc_mutex_unlock( &p_input->p->input.p_item->lock );
938
939         for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
940         {
941             if( !es->fmt.audio_replay_gain.pb_peak[i] )
942             {
943                 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
944                 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
945             }
946             if( !es->fmt.audio_replay_gain.pb_gain[i] )
947             {
948                 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
949                 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
950             }
951         }
952         break;
953     }
954
955     case VIDEO_ES:
956         es->i_channel = p_sys->i_video;
957         if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
958             vlc_ureduce( &es->fmt.video.i_frame_rate,
959                          &es->fmt.video.i_frame_rate_base,
960                          fmt->video.i_frame_rate,
961                          fmt->video.i_frame_rate_base, 0 );
962         break;
963
964     case SPU_ES:
965         es->i_channel = p_sys->i_sub;
966         break;
967
968     default:
969         es->i_channel = 0;
970         break;
971     }
972     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
973     es->psz_language_code = LanguageGetCode( fmt->psz_language );
974     es->p_dec = NULL;
975     for( i = 0; i < 4; i++ )
976         es->pb_cc_present[i] = VLC_FALSE;
977     es->p_master = VLC_FALSE;
978
979     if( es->p_pgrm == p_sys->p_pgrm )
980         EsOutESVarUpdate( out, es, VLC_FALSE );
981
982     /* Select it if needed */
983     EsOutSelect( out, es, VLC_FALSE );
984
985
986     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
987     p_sys->i_id++;  /* always incremented */
988     switch( fmt->i_cat )
989     {
990         case AUDIO_ES:
991             p_sys->i_audio++;
992             break;
993         case SPU_ES:
994             p_sys->i_sub++;
995             break;
996         case VIDEO_ES:
997             p_sys->i_video++;
998             break;
999     }
1000
1001     EsOutAddInfo( out, es );
1002
1003     return es;
1004 }
1005
1006 static vlc_bool_t EsIsSelected( es_out_id_t *es )
1007 {
1008     if( es->p_master )
1009     {
1010         vlc_bool_t b_decode = VLC_FALSE;
1011         if( es->p_master->p_dec )
1012         {
1013             int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1014             if( i_channel != -1 )
1015                 input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
1016         }
1017         return b_decode;
1018     }
1019     else
1020     {
1021         return es->p_dec != NULL;
1022     }
1023 }
1024 static void EsSelect( es_out_t *out, es_out_id_t *es )
1025 {
1026     es_out_sys_t   *p_sys = out->p_sys;
1027     input_thread_t *p_input = p_sys->p_input;
1028     vlc_value_t    val;
1029     const char     *psz_var;
1030
1031     if( EsIsSelected( es ) )
1032     {
1033         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1034         return;
1035     }
1036
1037     if( es->p_master )
1038     {
1039         int i_channel;
1040         if( !es->p_master->p_dec )
1041             return;
1042
1043         i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1044         if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, VLC_TRUE, i_channel ) )
1045             return;
1046     }
1047     else
1048     {
1049         if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1050         {
1051             if( !var_GetBool( p_input, "video" ) ||
1052                 ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
1053             {
1054                 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1055                          es->i_id );
1056                 return;
1057             }
1058         }
1059         else if( es->fmt.i_cat == AUDIO_ES )
1060         {
1061             var_Get( p_input, "audio", &val );
1062             if( !var_GetBool( p_input, "audio" ) ||
1063                 ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
1064             {
1065                 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1066                          es->i_id );
1067                 return;
1068             }
1069         }
1070         if( es->fmt.i_cat == SPU_ES )
1071         {
1072             var_Get( p_input, "spu", &val );
1073             if( !var_GetBool( p_input, "spu" ) ||
1074                 ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) )
1075             {
1076                 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1077                          es->i_id );
1078                 return;
1079             }
1080         }
1081
1082         es->i_preroll_end = -1;
1083         es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
1084         if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1085             return;
1086     }
1087
1088     if( es->fmt.i_cat == VIDEO_ES )
1089         psz_var = "video-es";
1090     else if( es->fmt.i_cat == AUDIO_ES )
1091         psz_var = "audio-es";
1092     else if( es->fmt.i_cat == SPU_ES )
1093         psz_var = "spu-es";
1094     else
1095         return;
1096
1097     /* Mark it as selected */
1098     val.i_int = es->i_id;
1099     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1100
1101     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1102 }
1103
1104 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
1105 {
1106     es_out_sys_t   *p_sys = out->p_sys;
1107     input_thread_t *p_input = p_sys->p_input;
1108     vlc_value_t    val;
1109     const char     *psz_var;
1110
1111     if( !EsIsSelected( es ) )
1112     {
1113         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1114         return;
1115     }
1116
1117     if( es->p_master )
1118     {
1119         if( es->p_master->p_dec )
1120         {
1121             int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1122             if( i_channel != -1 )
1123                 input_DecoderSetCcState( es->p_master->p_dec, VLC_FALSE, i_channel );
1124         }
1125     }
1126     else
1127     {
1128         const int i_spu_id = var_GetInteger( p_input, "spu-es");
1129         int i;
1130         for( i = 0; i < 4; i++ )
1131         {
1132             if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1133                 continue;
1134
1135             if( i_spu_id == es->pp_cc_es[i]->i_id )
1136             {
1137                 /* Force unselection of the CC */
1138                 val.i_int = -1;
1139                 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1140                 if( !b_update )
1141                     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1142             }
1143             EsOutDel( out, es->pp_cc_es[i] );
1144
1145             es->pb_cc_present[i] = VLC_FALSE;
1146         }
1147         input_DecoderDelete( es->p_dec );
1148         es->p_dec = NULL;
1149     }
1150
1151     if( !b_update )
1152         return;
1153
1154     /* Update var */
1155     if( es->p_dec == NULL )
1156         return;
1157     if( es->fmt.i_cat == VIDEO_ES )
1158         psz_var = "video-es";
1159     else if( es->fmt.i_cat == AUDIO_ES )
1160         psz_var = "audio-es";
1161     else if( es->fmt.i_cat == SPU_ES )
1162         psz_var = "spu-es";
1163     else
1164         return;
1165
1166     /* Mark it as unselected */
1167     val.i_int = -1;
1168     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1169
1170     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1171 }
1172
1173 /**
1174  * Select an ES given the current mode
1175  * XXX: you need to take a the lock before (stream.stream_lock)
1176  *
1177  * \param out The es_out structure
1178  * \param es es_out_id structure
1179  * \param b_force ...
1180  * \return nothing
1181  */
1182 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
1183 {
1184     es_out_sys_t      *p_sys = out->p_sys;
1185
1186     int i_cat = es->fmt.i_cat;
1187
1188     if( !p_sys->b_active ||
1189         ( !b_force && es->fmt.i_priority < 0 ) )
1190     {
1191         return;
1192     }
1193
1194     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1195     {
1196         if( !EsIsSelected( es ) )
1197             EsSelect( out, es );
1198     }
1199     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1200     {
1201         vlc_value_t val;
1202         int i;
1203         var_Get( p_sys->p_input, "programs", &val );
1204         for ( i = 0; i < val.p_list->i_count; i++ )
1205         {
1206             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1207             {
1208                 if( !EsIsSelected( es ) )
1209                     EsSelect( out, es );
1210                 break;
1211             }
1212         }
1213         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1214     }
1215     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1216     {
1217         int i_wanted  = -1;
1218
1219         if( es->p_pgrm != p_sys->p_pgrm )
1220             return;
1221
1222         if( i_cat == AUDIO_ES )
1223         {
1224             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1225                                      es->psz_language_code );
1226
1227             if( p_sys->p_es_audio &&
1228                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1229             {
1230                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1231                                          p_sys->p_es_audio->psz_language_code );
1232
1233                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1234                     return;
1235                 i_wanted = es->i_channel;
1236             }
1237             else
1238             {
1239                 /* Select audio if (no audio selected yet)
1240                  * - no audio-language
1241                  * - no audio code for the ES
1242                  * - audio code in the requested list */
1243                 if( idx1 >= 0 ||
1244                     !strcmp( es->psz_language_code, "??" ) ||
1245                     !p_sys->ppsz_audio_language )
1246                     i_wanted = es->i_channel;
1247             }
1248
1249             if( p_sys->i_audio_last >= 0 )
1250                 i_wanted = p_sys->i_audio_last;
1251
1252             if( p_sys->i_audio_id >= 0 )
1253             {
1254                 if( es->i_id == p_sys->i_audio_id )
1255                     i_wanted = es->i_channel;
1256                 else
1257                     return;
1258             }
1259         }
1260         else if( i_cat == SPU_ES )
1261         {
1262             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1263                                      es->psz_language_code );
1264
1265             if( p_sys->p_es_sub &&
1266                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1267             {
1268                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1269                                          p_sys->p_es_sub->psz_language_code );
1270
1271                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1272                         idx1, es->psz_language_code, idx2,
1273                         p_sys->p_es_sub->psz_language_code );
1274
1275                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1276                     return;
1277                 /* We found a SPU that matches our language request */
1278                 i_wanted  = es->i_channel;
1279             }
1280             else if( idx1 >= 0 )
1281             {
1282                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1283                         idx1, es->psz_language_code );
1284
1285                 i_wanted  = es->i_channel;
1286             }
1287             else if( p_sys->i_default_sub_id >= 0 )
1288             {
1289                 if( es->i_id == p_sys->i_default_sub_id )
1290                     i_wanted = es->i_channel;
1291             }
1292
1293             if( p_sys->i_sub_last >= 0 )
1294                 i_wanted  = p_sys->i_sub_last;
1295
1296             if( p_sys->i_sub_id >= 0 )
1297             {
1298                 if( es->i_id == p_sys->i_sub_id )
1299                     i_wanted = es->i_channel;
1300                 else
1301                     return;
1302             }
1303         }
1304         else if( i_cat == VIDEO_ES )
1305         {
1306             i_wanted  = es->i_channel;
1307         }
1308
1309         if( i_wanted == es->i_channel && !EsIsSelected( es ) )
1310             EsSelect( out, es );
1311     }
1312
1313     /* FIXME TODO handle priority here */
1314     if( EsIsSelected( es ) )
1315     {
1316         if( i_cat == AUDIO_ES )
1317         {
1318             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1319                 p_sys->p_es_audio &&
1320                 p_sys->p_es_audio != es &&
1321                 EsIsSelected( p_sys->p_es_audio ) )
1322             {
1323                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
1324             }
1325             p_sys->p_es_audio = es;
1326         }
1327         else if( i_cat == SPU_ES )
1328         {
1329             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1330                 p_sys->p_es_sub &&
1331                 p_sys->p_es_sub != es &&
1332                 EsIsSelected( p_sys->p_es_sub ) )
1333             {
1334                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
1335             }
1336             p_sys->p_es_sub = es;
1337         }
1338         else if( i_cat == VIDEO_ES )
1339         {
1340             p_sys->p_es_video = es;
1341         }
1342     }
1343 }
1344
1345 /**
1346  * Send a block for the given es_out
1347  *
1348  * \param out the es_out to send from
1349  * \param es the es_out_id
1350  * \param p_block the data block to send
1351  */
1352 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1353 {
1354     es_out_sys_t *p_sys = out->p_sys;
1355     input_thread_t    *p_input = p_sys->p_input;
1356     es_out_pgrm_t *p_pgrm = es->p_pgrm;
1357     int64_t i_delay;
1358     int i_total=0;
1359
1360     if( es->fmt.i_cat == AUDIO_ES )
1361         i_delay = p_sys->i_audio_delay;
1362     else if( es->fmt.i_cat == SPU_ES )
1363         i_delay = p_sys->i_spu_delay;
1364     else
1365         i_delay = 0;
1366
1367     if( p_input->p_libvlc->b_stats )
1368     {
1369         vlc_mutex_lock( &p_input->p->counters.counters_lock );
1370         stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1371                              p_block->i_buffer, &i_total );
1372         stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1373                            (float)i_total, NULL );
1374         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1375     }
1376
1377     /* Mark preroll blocks */
1378     if( es->i_preroll_end >= 0 )
1379     {
1380         int64_t i_date = p_block->i_pts;
1381         if( i_date <= 0 )
1382             i_date = p_block->i_dts;
1383
1384         if( i_date < es->i_preroll_end )
1385             p_block->i_flags |= BLOCK_FLAG_PREROLL;
1386         else
1387             es->i_preroll_end = -1;
1388     }
1389
1390     if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1391     {
1392         p_block->i_dts += i_delay;
1393     }
1394     else if( p_block->i_dts > 0 )
1395     {
1396         p_block->i_dts =
1397             input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay;
1398     }
1399     if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1400     {
1401         p_block->i_pts += i_delay;
1402     }
1403     else if( p_block->i_pts > 0 )
1404     {
1405         p_block->i_pts =
1406             input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay;
1407     }
1408     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1409     {
1410         mtime_t current_date = mdate();
1411         if( !p_block->i_pts
1412                || p_block->i_pts > current_date + 10000000
1413                || current_date > p_block->i_pts )
1414         {
1415             /* ETSI EN 300 472 Annex A : do not take into account the PTS
1416              * for teletext streams. */
1417             p_block->i_pts = current_date + 400000
1418                                + p_input->i_pts_delay + i_delay;
1419         }
1420     }
1421
1422     p_block->i_rate = p_sys->i_rate;
1423
1424     /* TODO handle mute */
1425     if( es->p_dec &&
1426         ( es->fmt.i_cat != AUDIO_ES ||
1427           ( p_sys->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
1428             p_sys->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
1429     {
1430         vlc_bool_t pb_cc[4];
1431         vlc_bool_t b_cc_new = VLC_FALSE;
1432         int i;
1433         input_DecoderDecode( es->p_dec, p_block );
1434
1435         /* Check CC status */
1436         input_DecoderIsCcPresent( es->p_dec, pb_cc );
1437         for( i = 0; i < 4; i++ )
1438         {
1439             static const vlc_fourcc_t fcc[4] = {
1440                 VLC_FOURCC('c', 'c', '1', ' '),
1441                 VLC_FOURCC('c', 'c', '2', ' '),
1442                 VLC_FOURCC('c', 'c', '3', ' '),
1443                 VLC_FOURCC('c', 'c', '4', ' '),
1444             };
1445             static const char *ppsz_description[4] = {
1446                 N_("Closed captions 1"),
1447                 N_("Closed captions 2"),
1448                 N_("Closed captions 3"),
1449                 N_("Closed captions 4"),
1450             };
1451             es_format_t fmt;
1452
1453             if(  es->pb_cc_present[i] || !pb_cc[i] )
1454                 continue;
1455             msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
1456
1457             es_format_Init( &fmt, SPU_ES, fcc[i] );
1458             fmt.i_group = es->fmt.i_group;
1459             fmt.psz_description = strdup( _(ppsz_description[i] ) );
1460             es->pp_cc_es[i] = EsOutAdd( out, &fmt );
1461             es->pp_cc_es[i]->p_master = es;
1462             es_format_Clean( &fmt );
1463
1464             /* */
1465             es->pb_cc_present[i] = VLC_TRUE;
1466             b_cc_new = VLC_TRUE;
1467         }
1468         if( b_cc_new )
1469             var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1470     }
1471     else
1472     {
1473         block_Release( p_block );
1474     }
1475
1476     return VLC_SUCCESS;
1477 }
1478
1479 /*****************************************************************************
1480  * EsOutDel:
1481  *****************************************************************************/
1482 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1483 {
1484     es_out_sys_t *p_sys = out->p_sys;
1485     vlc_bool_t b_reselect = VLC_FALSE;
1486     int i;
1487
1488     /* We don't try to reselect */
1489     if( es->p_dec )
1490     {
1491         while( !out->p_sys->p_input->b_die && es->p_dec )
1492         {
1493             if( input_DecoderEmpty( es->p_dec ) )
1494                 break;
1495             msleep( 20*1000 );
1496         }
1497         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1498     }
1499
1500     if( es->p_pgrm == p_sys->p_pgrm )
1501         EsOutESVarUpdate( out, es, VLC_TRUE );
1502
1503     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1504
1505     es->p_pgrm->i_es--;
1506     if( es->p_pgrm->i_es == 0 )
1507     {
1508         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1509     }
1510
1511     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1512         p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
1513
1514     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1515     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1516     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
1517
1518     switch( es->fmt.i_cat )
1519     {
1520         case AUDIO_ES:
1521             p_sys->i_audio--;
1522             break;
1523         case SPU_ES:
1524             p_sys->i_sub--;
1525             break;
1526         case VIDEO_ES:
1527             p_sys->i_video--;
1528             break;
1529     }
1530
1531     /* Re-select another track when needed */
1532     if( b_reselect )
1533         for( i = 0; i < p_sys->i_es; i++ )
1534         {
1535             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1536                 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1537         }
1538
1539     free( es->psz_language );
1540     free( es->psz_language_code );
1541
1542     es_format_Clean( &es->fmt );
1543
1544     free( es );
1545 }
1546
1547 /**
1548  * Control query handler
1549  *
1550  * \param out the es_out to control
1551  * \param i_query A es_out query as defined in include/ninput.h
1552  * \param args a variable list of arguments for the query
1553  * \return VLC_SUCCESS or an error code
1554  */
1555 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1556 {
1557     es_out_sys_t *p_sys = out->p_sys;
1558     vlc_bool_t  b, *pb;
1559     int         i, *pi;
1560
1561     es_out_id_t *es;
1562
1563     switch( i_query )
1564     {
1565         case ES_OUT_SET_ES_STATE:
1566             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1567             b = (bool) va_arg( args, int );
1568             if( b && !EsIsSelected( es ) )
1569             {
1570                 EsSelect( out, es );
1571                 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
1572             }
1573             else if( !b && EsIsSelected( es ) )
1574             {
1575                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1576                 return VLC_SUCCESS;
1577             }
1578             return VLC_SUCCESS;
1579
1580         case ES_OUT_GET_ES_STATE:
1581             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1582             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1583
1584             *pb = EsIsSelected( es );
1585             return VLC_SUCCESS;
1586
1587         case ES_OUT_SET_ACTIVE:
1588         {
1589             b = (bool) va_arg( args, int );
1590             p_sys->b_active = b;
1591             /* Needed ? */
1592             if( b )
1593                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1594             return VLC_SUCCESS;
1595         }
1596
1597         case ES_OUT_GET_ACTIVE:
1598             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1599             *pb = p_sys->b_active;
1600             return VLC_SUCCESS;
1601
1602         case ES_OUT_SET_MODE:
1603             i = (int) va_arg( args, int );
1604             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1605                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1606             {
1607                 p_sys->i_mode = i;
1608
1609                 /* Reapply policy mode */
1610                 for( i = 0; i < p_sys->i_es; i++ )
1611                 {
1612                     if( EsIsSelected( p_sys->es[i] ) )
1613                     {
1614                         EsUnselect( out, p_sys->es[i],
1615                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1616                     }
1617                 }
1618                 for( i = 0; i < p_sys->i_es; i++ )
1619                 {
1620                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1621                 }
1622                 return VLC_SUCCESS;
1623             }
1624             return VLC_EGENERIC;
1625
1626         case ES_OUT_GET_MODE:
1627             pi = (int*) va_arg( args, int* );
1628             *pi = p_sys->i_mode;
1629             return VLC_SUCCESS;
1630
1631         case ES_OUT_SET_ES:
1632             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1633             /* Special case NULL, NULL+i_cat */
1634             if( es == NULL )
1635             {
1636                 for( i = 0; i < p_sys->i_es; i++ )
1637                 {
1638                     if( EsIsSelected( p_sys->es[i] ) )
1639                         EsUnselect( out, p_sys->es[i],
1640                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1641                 }
1642             }
1643             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1644             {
1645                 for( i = 0; i < p_sys->i_es; i++ )
1646                 {
1647                     if( p_sys->es[i]->fmt.i_cat == AUDIO_ES &&
1648                         EsIsSelected( p_sys->es[i] ) )
1649                         EsUnselect( out, p_sys->es[i],
1650                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1651                 }
1652             }
1653             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1654             {
1655                 for( i = 0; i < p_sys->i_es; i++ )
1656                 {
1657                     if( p_sys->es[i]->fmt.i_cat == VIDEO_ES &&
1658                         EsIsSelected( p_sys->es[i] ) )
1659                         EsUnselect( out, p_sys->es[i],
1660                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1661                 }
1662             }
1663             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1664             {
1665                 for( i = 0; i < p_sys->i_es; i++ )
1666                 {
1667                     if( p_sys->es[i]->fmt.i_cat == SPU_ES &&
1668                         EsIsSelected( p_sys->es[i] ) )
1669                         EsUnselect( out, p_sys->es[i],
1670                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1671                 }
1672             }
1673             else
1674             {
1675                 for( i = 0; i < p_sys->i_es; i++ )
1676                 {
1677                     if( es == p_sys->es[i] )
1678                     {
1679                         EsOutSelect( out, es, VLC_TRUE );
1680                         break;
1681                     }
1682                 }
1683             }
1684             {
1685                 playlist_t * p_playlist = pl_Yield( p_sys->p_input );
1686                 PL_LOCK;
1687                 p_playlist->gc_date = mdate();
1688                 vlc_object_signal_unlocked( p_playlist );
1689                 PL_UNLOCK;
1690                 pl_Release( p_playlist );
1691             }
1692             return VLC_SUCCESS;
1693  
1694         case ES_OUT_SET_DEFAULT:
1695         {
1696             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1697
1698             if( es == NULL )
1699             {
1700                 /*p_sys->i_default_video_id = -1;*/
1701                 /*p_sys->i_default_audio_id = -1;*/
1702                 p_sys->i_default_sub_id = -1;
1703             }
1704             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1705             {
1706                 /*p_sys->i_default_video_id = -1;*/
1707             }
1708             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1709             {
1710                 /*p_sys->i_default_audio_id = -1;*/
1711             }
1712             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1713             {
1714                 p_sys->i_default_sub_id = -1;
1715             }
1716             else
1717             {
1718                 /*if( es->fmt.i_cat == VIDEO_ES )
1719                     p_sys->i_default_video_id = es->i_id;
1720                 else
1721                 if( es->fmt.i_cat == AUDIO_ES )
1722                     p_sys->i_default_audio_id = es->i_id;
1723                 else*/
1724                 if( es->fmt.i_cat == SPU_ES )
1725                     p_sys->i_default_sub_id = es->i_id;
1726             }
1727             return VLC_SUCCESS;
1728         }
1729
1730         case ES_OUT_SET_PCR:
1731         case ES_OUT_SET_GROUP_PCR:
1732         {
1733             es_out_pgrm_t *p_pgrm = NULL;
1734             int            i_group = 0;
1735             int64_t        i_pcr;
1736
1737             if( i_query == ES_OUT_SET_PCR )
1738             {
1739                 p_pgrm = p_sys->p_pgrm;
1740             }
1741             else
1742             {
1743                 int i;
1744                 i_group = (int)va_arg( args, int );
1745                 for( i = 0; i < p_sys->i_pgrm; i++ )
1746                 {
1747                     if( p_sys->pgrm[i]->i_id == i_group )
1748                     {
1749                         p_pgrm = p_sys->pgrm[i];
1750                         break;
1751                     }
1752                 }
1753             }
1754             if( p_pgrm == NULL )
1755                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1756
1757             i_pcr = (int64_t)va_arg( args, int64_t );
1758             /* search program */
1759             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr );
1760             return VLC_SUCCESS;
1761         }
1762
1763         case ES_OUT_RESET_PCR:
1764             for( i = 0; i < p_sys->i_pgrm; i++ )
1765                 input_ClockResetPCR( &p_sys->pgrm[i]->clock );
1766             return VLC_SUCCESS;
1767
1768         case ES_OUT_GET_TS:
1769             if( p_sys->p_pgrm )
1770             {
1771                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1772                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1773                 *pi_ts = input_ClockGetTS( p_sys->p_input,
1774                                            &p_sys->p_pgrm->clock, i_ts );
1775                 return VLC_SUCCESS;
1776             }
1777             return VLC_EGENERIC;
1778
1779         case ES_OUT_GET_GROUP:
1780             pi = (int*) va_arg( args, int* );
1781             if( p_sys->p_pgrm )
1782                 *pi = p_sys->p_pgrm->i_id;
1783             else
1784                 *pi = -1;    /* FIXME */
1785             return VLC_SUCCESS;
1786
1787         case ES_OUT_SET_GROUP:
1788         {
1789             int j;
1790             i = (int) va_arg( args, int );
1791             for( j = 0; j < p_sys->i_pgrm; j++ )
1792             {
1793                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1794                 if( p_pgrm->i_id == i )
1795                 {
1796                     EsOutProgramSelect( out, p_pgrm );
1797                     return VLC_SUCCESS;
1798                 }
1799             }
1800             return VLC_EGENERIC;
1801         }
1802
1803         case ES_OUT_SET_FMT:
1804         {
1805             /* This ain't pretty but is need by some demuxers (eg. Ogg )
1806              * to update the p_extra data */
1807             es_format_t *p_fmt;
1808             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1809             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1810             if( es == NULL ) return VLC_EGENERIC;
1811
1812             if( p_fmt->i_extra )
1813             {
1814                 es->fmt.i_extra = p_fmt->i_extra;
1815                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1816                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1817
1818                 if( !es->p_dec ) return VLC_SUCCESS;
1819
1820 #if 1
1821                 input_DecoderDelete( es->p_dec );
1822                 es->p_dec = input_DecoderNew( p_sys->p_input,
1823                                               &es->fmt, VLC_FALSE );
1824
1825 #else
1826                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1827                 es->p_dec->fmt_in.p_extra =
1828                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1829                 memcpy( es->p_dec->fmt_in.p_extra,
1830                         p_fmt->p_extra, p_fmt->i_extra );
1831 #endif
1832             }
1833
1834             return VLC_SUCCESS;
1835         }
1836
1837         case ES_OUT_SET_NEXT_DISPLAY_TIME:
1838         {
1839             int64_t i_date;
1840
1841             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1842             i_date = (int64_t)va_arg( args, int64_t );
1843
1844             if( !es || !es->p_dec )
1845                 return VLC_EGENERIC;
1846
1847             /* XXX We should call input_ClockGetTS but PCR has been reseted
1848              * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
1849              * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
1850             es->i_preroll_end = i_date;
1851
1852             return VLC_SUCCESS;
1853         }
1854         case ES_OUT_SET_GROUP_META:
1855         {
1856             int i_group = (int)va_arg( args, int );
1857             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1858
1859             EsOutProgramMeta( out, i_group, p_meta );
1860             return VLC_SUCCESS;
1861         }
1862         case ES_OUT_SET_GROUP_EPG:
1863         {
1864             int i_group = (int)va_arg( args, int );
1865             vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1866
1867             EsOutProgramEpg( out, i_group, p_epg );
1868             return VLC_SUCCESS;
1869         }
1870         case ES_OUT_DEL_GROUP:
1871         {
1872             int i_group = (int)va_arg( args, int );
1873
1874             return EsOutProgramDel( out, i_group );
1875         }
1876
1877         default:
1878             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1879             return VLC_EGENERIC;
1880     }
1881 }
1882
1883 /****************************************************************************
1884  * LanguageGetName: try to expend iso639 into plain name
1885  ****************************************************************************/
1886 static char *LanguageGetName( const char *psz_code )
1887 {
1888     const iso639_lang_t *pl;
1889
1890     if( psz_code == NULL )
1891     {
1892         return strdup( "" );
1893     }
1894
1895     if( strlen( psz_code ) == 2 )
1896     {
1897         pl = GetLang_1( psz_code );
1898     }
1899     else if( strlen( psz_code ) == 3 )
1900     {
1901         pl = GetLang_2B( psz_code );
1902         if( !strcmp( pl->psz_iso639_1, "??" ) )
1903         {
1904             pl = GetLang_2T( psz_code );
1905         }
1906     }
1907     else
1908     {
1909         return strdup( psz_code );
1910     }
1911
1912     if( !strcmp( pl->psz_iso639_1, "??" ) )
1913     {
1914        return strdup( psz_code );
1915     }
1916     else
1917     {
1918         if( *pl->psz_native_name )
1919         {
1920             return strdup( pl->psz_native_name );
1921         }
1922         return strdup( pl->psz_eng_name );
1923     }
1924 }
1925
1926 /* Get a 2 char code */
1927 static char *LanguageGetCode( const char *psz_lang )
1928 {
1929     const iso639_lang_t *pl;
1930
1931     if( psz_lang == NULL || *psz_lang == '\0' )
1932         return strdup("??");
1933
1934     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1935     {
1936         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1937             !strcasecmp( pl->psz_native_name, psz_lang ) ||
1938             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1939             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1940             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1941             break;
1942     }
1943
1944     if( pl->psz_iso639_1 != NULL )
1945         return strdup( pl->psz_iso639_1 );
1946
1947     return strdup("??");
1948 }
1949
1950 static char **LanguageSplit( const char *psz_langs )
1951 {
1952     char *psz_dup;
1953     char *psz_parser;
1954     char **ppsz = NULL;
1955     int i_psz = 0;
1956
1957     if( psz_langs == NULL ) return NULL;
1958
1959     psz_parser = psz_dup = strdup(psz_langs);
1960
1961     while( psz_parser && *psz_parser )
1962     {
1963         char *psz;
1964         char *psz_code;
1965
1966         psz = strchr(psz_parser, ',' );
1967         if( psz ) *psz++ = '\0';
1968
1969         if( !strcmp( psz_parser, "any" ) )
1970         {
1971             TAB_APPEND( i_psz, ppsz, strdup("any") );
1972         }
1973         else
1974         {
1975             psz_code = LanguageGetCode( psz_parser );
1976             if( strcmp( psz_code, "??" ) )
1977             {
1978                 TAB_APPEND( i_psz, ppsz, psz_code );
1979             }
1980             else
1981             {
1982                 free( psz_code );
1983             }
1984         }
1985
1986         psz_parser = psz;
1987     }
1988
1989     if( i_psz )
1990     {
1991         TAB_APPEND( i_psz, ppsz, NULL );
1992     }
1993
1994     free( psz_dup );
1995     return ppsz;
1996 }
1997
1998 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1999 {
2000     int i;
2001
2002     if( !ppsz_langs || !psz_lang ) return -1;
2003
2004     for( i = 0; ppsz_langs[i]; i++ )
2005     {
2006         if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2007             !strcasecmp( ppsz_langs[i], "any" ) )
2008         {
2009             return i;
2010         }
2011     }
2012
2013     return -1;
2014 }
2015
2016 /****************************************************************************
2017  * EsOutAddInfo:
2018  * - add meta info to the playlist item
2019  ****************************************************************************/
2020 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
2021 {
2022     es_out_sys_t   *p_sys = out->p_sys;
2023     input_thread_t *p_input = p_sys->p_input;
2024     es_format_t    *fmt = &es->fmt;
2025     char           *psz_cat;
2026     lldiv_t         div;
2027
2028     /* Add stream info */
2029     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
2030
2031     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
2032                    "%.4s", (char*)&fmt->i_codec );
2033
2034     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
2035                    "%s", es->psz_language );
2036
2037     /* Add information */
2038     switch( fmt->i_cat )
2039     {
2040     case AUDIO_ES:
2041         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2042                        _("Type"), _("Audio") );
2043
2044         if( fmt->audio.i_channels > 0 )
2045             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
2046                            "%u", fmt->audio.i_channels );
2047
2048         if( fmt->audio.i_rate > 0 )
2049         {
2050             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
2051                            _("%u Hz"), fmt->audio.i_rate );
2052             var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
2053         }
2054
2055         if( fmt->audio.i_bitspersample > 0 )
2056             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2057                            _("Bits per sample"), "%u",
2058                            fmt->audio.i_bitspersample );
2059
2060         if( fmt->i_bitrate > 0 )
2061         {
2062             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
2063                            _("%u kb/s"), fmt->i_bitrate / 1000 );
2064             var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
2065         }
2066         break;
2067
2068     case VIDEO_ES:
2069         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2070                        _("Type"), _("Video") );
2071
2072         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
2073             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2074                            _("Resolution"), "%ux%u",
2075                            fmt->video.i_width, fmt->video.i_height );
2076
2077         if( fmt->video.i_visible_width > 0 &&
2078             fmt->video.i_visible_height > 0 )
2079             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2080                            _("Display resolution"), "%ux%u",
2081                            fmt->video.i_visible_width,
2082                            fmt->video.i_visible_height);
2083        if( fmt->video.i_frame_rate > 0 &&
2084            fmt->video.i_frame_rate_base > 0 )
2085        {
2086            div = lldiv( (float)fmt->video.i_frame_rate /
2087                                fmt->video.i_frame_rate_base * 1000000,
2088                                1000000 );
2089            input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2090                           _("Frame rate"), I64Fd".%06u",
2091                           div.quot, (unsigned int )div.rem );
2092        }
2093        break;
2094
2095     case SPU_ES:
2096         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2097                        _("Type"), _("Subtitle") );
2098         break;
2099
2100     default:
2101         break;
2102     }
2103
2104     free( psz_cat );
2105 }