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