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