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