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