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