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