]> git.sesse.net Git - vlc/blob - src/input/es_out.c
Partially fixed preroll support.
[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         p_es->i_preroll_end = -1;
592
593         if( !p_es->p_dec )
594             continue;
595         input_DecoderWaitBuffering( p_es->p_dec );
596         if( p_es->p_dec_record )
597             input_DecoderWaitBuffering( p_es->p_dec_record );
598     }
599
600     msg_Dbg( p_sys->p_input, "Decoder buffering done in %d ms",
601               (int)(mdate() - i_decoder_buffering_start)/1000 );
602
603     const mtime_t i_ts_delay = 10*1000 + /* FIXME CLEANUP thread wake up time*/
604                                mdate();
605     //msg_Dbg( p_sys->p_input, "==> %lld", i_ts_delay - p_sys->p_input->i_pts_delay );
606     input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_clock, i_ts_delay - p_sys->p_input->i_pts_delay - i_preroll_duration );
607
608     for( int i = 0; i < p_sys->i_es; i++ )
609     {
610         es_out_id_t *p_es = p_sys->es[i];
611
612         if( !p_es->p_dec )
613             continue;
614
615         input_DecoderStopBuffering( p_es->p_dec );
616         if( p_es->p_dec_record )
617             input_DecoderStopBuffering( p_es->p_dec );
618     }
619 }
620 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
621 {
622     es_out_sys_t *p_sys = out->p_sys;
623
624     /* Pause decoders first */
625     for( int i = 0; i < p_sys->i_es; i++ )
626     {
627         es_out_id_t *es = p_sys->es[i];
628
629         /* Send a dummy block to let decoder know that
630          * there is a discontinuity */
631         if( es->p_dec )
632         {
633             input_DecoderChangePause( es->p_dec, b_paused, i_date );
634             if( es->p_dec_record )
635                 input_DecoderChangePause( es->p_dec_record, b_paused, i_date );
636         }
637     }
638 }
639 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
640 {
641     es_out_sys_t *p_sys = out->p_sys;
642
643     for( int i = 0; i < p_sys->i_pgrm; i++ )
644         input_clock_ChangePause( p_sys->pgrm[i]->p_clock, b_paused, i_date );
645 }
646
647 static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es )
648 {
649     es_out_sys_t *p_sys = out->p_sys;
650
651     mtime_t i_delay = 0;
652     if( p_es->fmt.i_cat == AUDIO_ES )
653         i_delay = p_sys->i_audio_delay;
654     else if( p_es->fmt.i_cat == SPU_ES )
655         i_delay = p_sys->i_spu_delay;
656
657     if( i_delay != 0 )
658     {
659         if( p_es->p_dec )
660             input_DecoderChangeDelay( p_es->p_dec, i_delay );
661         if( p_es->p_dec_record )
662             input_DecoderChangeDelay( p_es->p_dec_record, i_delay );
663     }
664 }
665
666
667 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
668                                      bool b_delete )
669 {
670     es_out_sys_t      *p_sys = out->p_sys;
671     input_thread_t    *p_input = p_sys->p_input;
672     const  bool b_teletext = fmt->i_cat == SPU_ES && fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' );
673     vlc_value_t       val, text;
674
675     const char *psz_var;
676
677     if( fmt->i_cat == AUDIO_ES )
678         psz_var = "audio-es";
679     else if( fmt->i_cat == VIDEO_ES )
680         psz_var = "video-es";
681     else if( fmt->i_cat == SPU_ES )
682         psz_var = "spu-es";
683     else
684         return;
685
686     if( b_delete )
687     {
688         if( b_teletext )
689             var_SetInteger( p_sys->p_input, "teletext-es", -1 );
690
691         val.i_int = i_id;
692         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
693
694         var_SetBool( p_sys->p_input, "intf-change", true );
695         return;
696     }
697
698     /* Get the number of ES already added */
699     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
700     if( val.i_int == 0 )
701     {
702         vlc_value_t val2;
703
704         /* First one, we need to add the "Disable" choice */
705         val2.i_int = -1; text.psz_string = _("Disable");
706         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
707         val.i_int++;
708     }
709
710     /* Take care of the ES description */
711     if( fmt->psz_description && *fmt->psz_description )
712     {
713         if( psz_language && *psz_language )
714         {
715             text.psz_string = malloc( strlen( fmt->psz_description) +
716                                       strlen( psz_language ) + 10 );
717             sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
718                                                    psz_language );
719         }
720         else text.psz_string = strdup( fmt->psz_description );
721     }
722     else
723     {
724         if( psz_language && *psz_language )
725         {
726             if( asprintf( &text.psz_string, "%s %i - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
727                 text.psz_string = NULL;
728         }
729         else
730         {
731             if( asprintf( &text.psz_string, "%s %i", _( "Track" ), val.i_int ) == -1 )
732                 text.psz_string = NULL;
733         }
734     }
735
736     val.i_int = i_id;
737     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
738
739     free( text.psz_string );
740
741     if( b_teletext )
742     {
743         if( var_GetInteger( p_sys->p_input, "teletext-es" ) < 0 )
744             var_SetInteger( p_sys->p_input, "teletext-es", i_id );
745     }
746
747     var_SetBool( p_sys->p_input, "intf-change", true );
748 }
749
750 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
751                               bool b_delete )
752 {
753     EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
754 }
755
756 /* EsOutProgramSelect:
757  *  Select a program and update the object variable
758  */
759 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
760 {
761     es_out_sys_t      *p_sys = out->p_sys;
762     input_thread_t    *p_input = p_sys->p_input;
763     vlc_value_t       val;
764     int               i;
765
766     if( p_sys->p_pgrm == p_pgrm )
767         return; /* Nothing to do */
768
769     if( p_sys->p_pgrm )
770     {
771         es_out_pgrm_t *old = p_sys->p_pgrm;
772         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
773
774         for( i = 0; i < p_sys->i_es; i++ )
775         {
776             if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
777                 p_sys->i_mode != ES_OUT_MODE_ALL )
778                 EsUnselect( out, p_sys->es[i], true );
779         }
780
781         p_sys->p_es_audio = NULL;
782         p_sys->p_es_sub = NULL;
783         p_sys->p_es_video = NULL;
784     }
785
786     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
787
788     /* Mark it selected */
789     p_pgrm->b_selected = true;
790
791     /* Switch master stream */
792     p_sys->p_pgrm = p_pgrm;
793
794     /* Update "program" */
795     val.i_int = p_pgrm->i_id;
796     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
797
798     /* Update "es-*" */
799     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
800     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
801     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
802     var_SetInteger( p_input, "teletext-es", -1 );
803     for( i = 0; i < p_sys->i_es; i++ )
804     {
805         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
806             EsOutESVarUpdate( out, p_sys->es[i], false );
807         EsOutSelect( out, p_sys->es[i], false );
808     }
809
810     /* Update now playing */
811     input_item_SetNowPlaying( p_input->p->input.p_item,
812                               p_pgrm->psz_now_playing );
813     input_item_SetPublisher( p_input->p->input.p_item,
814                              p_pgrm->psz_publisher );
815
816     var_SetBool( p_sys->p_input, "intf-change", true );
817 }
818
819 /* EsOutAddProgram:
820  *  Add a program
821  */
822 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
823 {
824     es_out_sys_t      *p_sys = out->p_sys;
825     input_thread_t    *p_input = p_sys->p_input;
826     vlc_value_t       val;
827
828     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
829     if( !p_pgrm )
830         return NULL;
831
832     /* Init */
833     p_pgrm->i_id = i_group;
834     p_pgrm->i_es = 0;
835     p_pgrm->b_selected = false;
836     p_pgrm->psz_name = NULL;
837     p_pgrm->psz_now_playing = NULL;
838     p_pgrm->psz_publisher = NULL;
839     p_pgrm->p_epg = NULL;
840     p_pgrm->p_clock = input_clock_New( p_input->p->input.i_cr_average, p_sys->i_rate );
841     if( !p_pgrm->p_clock )
842     {
843         free( p_pgrm );
844         return NULL;
845     }
846
847     /* Append it */
848     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
849
850     /* Update "program" variable */
851     val.i_int = i_group;
852     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
853
854     if( i_group == var_GetInteger( p_input, "program" ) )
855     {
856         EsOutProgramSelect( out, p_pgrm );
857     }
858     else
859     {
860         var_SetBool( p_sys->p_input, "intf-change", true );
861     }
862     return p_pgrm;
863 }
864
865 /* EsOutDelProgram:
866  *  Delete a program
867  */
868 static int EsOutProgramDel( es_out_t *out, int i_group )
869 {
870     es_out_sys_t      *p_sys = out->p_sys;
871     input_thread_t    *p_input = p_sys->p_input;
872     es_out_pgrm_t     *p_pgrm = NULL;
873     vlc_value_t       val;
874     int               i;
875
876     for( i = 0; i < p_sys->i_pgrm; i++ )
877     {
878         if( p_sys->pgrm[i]->i_id == i_group )
879         {
880             p_pgrm = p_sys->pgrm[i];
881             break;
882         }
883     }
884
885     if( p_pgrm == NULL )
886         return VLC_EGENERIC;
887
888     if( p_pgrm->i_es )
889     {
890         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
891                  i_group, p_pgrm->i_es );
892         return VLC_EGENERIC;
893     }
894
895     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
896
897     /* If program is selected we need to unselect it */
898     if( p_sys->p_pgrm == p_pgrm )
899         p_sys->p_pgrm = NULL;
900
901     input_clock_Delete( p_pgrm->p_clock );
902
903     free( p_pgrm->psz_name );
904     free( p_pgrm->psz_now_playing );
905     free( p_pgrm->psz_publisher );
906     if( p_pgrm->p_epg )
907         vlc_epg_Delete( p_pgrm->p_epg );
908     free( p_pgrm );
909
910     /* Update "program" variable */
911     val.i_int = i_group;
912     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
913
914     var_SetBool( p_sys->p_input, "intf-change", true );
915
916     return VLC_SUCCESS;
917 }
918
919 /* EsOutProgramMeta:
920  */
921 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
922 {
923     char *psz = NULL;
924     if( p_pgrm->psz_name )
925     {
926         if( asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ) == -1 )
927             return NULL;
928     }
929     else
930     {
931         if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
932             return NULL;
933     }
934     return psz;
935 }
936
937 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
938 {
939     es_out_sys_t      *p_sys = out->p_sys;
940     es_out_pgrm_t     *p_pgrm = NULL;
941     input_thread_t    *p_input = p_sys->p_input;
942     char              *psz_cat;
943     const char        *psz_title = NULL;
944     const char        *psz_provider = NULL;
945     int i;
946
947     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
948
949     /* Check against empty meta data (empty for what we handle) */
950     if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
951         !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
952         !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
953         vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
954     {
955         return;
956     }
957     /* Find program */
958     for( i = 0; i < p_sys->i_pgrm; i++ )
959     {
960         if( p_sys->pgrm[i]->i_id == i_group )
961         {
962             p_pgrm = p_sys->pgrm[i];
963             break;
964         }
965     }
966     if( p_pgrm == NULL )
967         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
968
969     /* */
970     psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
971     psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
972
973     /* Update the description text of the program */
974     if( psz_title && *psz_title )
975     {
976         vlc_value_t val;
977         vlc_value_t text;
978
979         if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
980         {
981             char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
982
983             /* Remove old entries */
984             input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
985             /* TODO update epg name */
986             free( psz_cat );
987         }
988         free( p_pgrm->psz_name );
989         p_pgrm->psz_name = strdup( psz_title );
990
991         /* ugly but it works */
992         val.i_int = i_group;
993         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
994
995         if( psz_provider && *psz_provider )
996         {
997             if( asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ) != -1 )
998             {
999                 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
1000                 free( text.psz_string );
1001             }
1002         }
1003         else
1004         {
1005             text.psz_string = (char *)psz_title;
1006             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
1007         }
1008     }
1009
1010     psz_cat = EsOutProgramGetMetaName( p_pgrm );
1011     if( psz_provider )
1012     {
1013         if( p_sys->p_pgrm == p_pgrm )
1014             input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
1015         input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
1016     }
1017     char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
1018     for( i = 0; ppsz_all_keys[i]; i++ )
1019     {
1020         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
1021                        vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
1022         free( ppsz_all_keys[i] );
1023     }
1024     free( ppsz_all_keys );
1025
1026     free( psz_cat );
1027 }
1028
1029 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
1030 {
1031     int i;
1032
1033     /* Add new event */
1034     for( i = 0; i < p_src->i_event; i++ )
1035     {
1036         vlc_epg_event_t *p_evt = p_src->pp_event[i];
1037         bool b_add = true;
1038         int j;
1039
1040         for( j = 0; j < p_dst->i_event; j++ )
1041         {
1042             if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
1043             {
1044                 b_add = false;
1045                 break;
1046             }
1047             if( p_dst->pp_event[j]->i_start > p_evt->i_start )
1048                 break;
1049         }
1050         if( b_add )
1051         {
1052             vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
1053             if( !p_copy )
1054                 break;
1055             memset( p_copy, 0, sizeof(vlc_epg_event_t) );
1056             p_copy->i_start = p_evt->i_start;
1057             p_copy->i_duration = p_evt->i_duration;
1058             p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
1059             p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
1060             p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
1061             TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
1062         }
1063     }
1064     /* Update current */
1065     vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
1066
1067     /* Keep only 1 old event  */
1068     if( p_dst->p_current )
1069     {
1070         while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
1071             TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
1072     }
1073 }
1074
1075 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
1076 {
1077     es_out_sys_t      *p_sys = out->p_sys;
1078     input_thread_t    *p_input = p_sys->p_input;
1079     es_out_pgrm_t     *p_pgrm = NULL;
1080     char *psz_cat;
1081     int i;
1082
1083     /* Find program */
1084     for( i = 0; i < p_sys->i_pgrm; i++ )
1085     {
1086         if( p_sys->pgrm[i]->i_id == i_group )
1087         {
1088             p_pgrm = p_sys->pgrm[i];
1089             break;
1090         }
1091     }
1092     if( p_pgrm == NULL )
1093         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1094
1095     /* Merge EPG */
1096     if( !p_pgrm->p_epg )
1097         p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
1098     vlc_epg_Merge( p_pgrm->p_epg, p_epg );
1099
1100     /* Update info */
1101     psz_cat = EsOutProgramGetMetaName( p_pgrm );
1102 #ifdef HAVE_LOCALTIME_R
1103     char *psz_epg;
1104     if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
1105         psz_epg = NULL;
1106     input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
1107     msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
1108     for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
1109     {
1110         const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
1111         time_t t_start = (time_t)p_evt->i_start;
1112         struct tm tm_start;
1113         char psz_start[128];
1114
1115         localtime_r( &t_start, &tm_start );
1116
1117         snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
1118         if( p_evt->psz_short_description || p_evt->psz_description )
1119             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
1120                            p_evt->psz_name,
1121                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
1122                            p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
1123         else
1124             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
1125                            p_evt->psz_name,
1126                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
1127     }
1128     free( psz_epg );
1129 #endif
1130     /* Update now playing */
1131     free( p_pgrm->psz_now_playing );
1132     p_pgrm->psz_now_playing = NULL;
1133     if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
1134         p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
1135
1136     if( p_pgrm == p_sys->p_pgrm )
1137         input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
1138
1139     if( p_pgrm->psz_now_playing )
1140     {
1141         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1142             input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
1143             p_pgrm->psz_now_playing );
1144     }
1145     else
1146     {
1147         input_Control( p_input, INPUT_DEL_INFO, psz_cat,
1148             input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
1149     }
1150
1151     free( psz_cat );
1152 }
1153
1154 /* EsOutAdd:
1155  *  Add an es_out
1156  */
1157 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
1158 {
1159     es_out_sys_t      *p_sys = out->p_sys;
1160     input_thread_t    *p_input = p_sys->p_input;
1161
1162     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
1163     es_out_pgrm_t     *p_pgrm = NULL;
1164     int i;
1165
1166     if( !es ) return NULL;
1167
1168     if( fmt->i_group < 0 )
1169     {
1170         msg_Err( p_input, "invalid group number" );
1171         free( es );
1172         return NULL;
1173     }
1174
1175     /* Search the program */
1176     for( i = 0; i < p_sys->i_pgrm; i++ )
1177     {
1178         if( fmt->i_group == p_sys->pgrm[i]->i_id )
1179         {
1180             p_pgrm = p_sys->pgrm[i];
1181             break;
1182         }
1183     }
1184     if( p_pgrm == NULL )
1185     {
1186         /* Create a new one */
1187         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
1188     }
1189
1190     /* Increase ref count for program */
1191     p_pgrm->i_es++;
1192
1193     /* Set up ES */
1194     if( fmt->i_id < 0 )
1195         fmt->i_id = out->p_sys->i_id;
1196     es->i_id = fmt->i_id;
1197     es->p_pgrm = p_pgrm;
1198     es_format_Copy( &es->fmt, fmt );
1199     es->i_preroll_end = -1;
1200
1201     switch( fmt->i_cat )
1202     {
1203     case AUDIO_ES:
1204     {
1205         audio_replay_gain_t rg;
1206
1207         es->i_channel = p_sys->i_audio;
1208
1209         memset( &rg, 0, sizeof(rg) );
1210         vlc_mutex_lock( &p_input->p->input.p_item->lock );
1211         vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
1212         vlc_mutex_unlock( &p_input->p->input.p_item->lock );
1213
1214         for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
1215         {
1216             if( !es->fmt.audio_replay_gain.pb_peak[i] )
1217             {
1218                 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
1219                 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
1220             }
1221             if( !es->fmt.audio_replay_gain.pb_gain[i] )
1222             {
1223                 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
1224                 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
1225             }
1226         }
1227         break;
1228     }
1229
1230     case VIDEO_ES:
1231         es->i_channel = p_sys->i_video;
1232         if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
1233             vlc_ureduce( &es->fmt.video.i_frame_rate,
1234                          &es->fmt.video.i_frame_rate_base,
1235                          fmt->video.i_frame_rate,
1236                          fmt->video.i_frame_rate_base, 0 );
1237         break;
1238
1239     case SPU_ES:
1240         es->i_channel = p_sys->i_sub;
1241         break;
1242
1243     default:
1244         es->i_channel = 0;
1245         break;
1246     }
1247     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
1248     es->psz_language_code = LanguageGetCode( fmt->psz_language );
1249     es->p_dec = NULL;
1250     es->p_dec_record = NULL;
1251     for( i = 0; i < 4; i++ )
1252         es->pb_cc_present[i] = false;
1253     es->p_master = NULL;
1254
1255     if( es->p_pgrm == p_sys->p_pgrm )
1256         EsOutESVarUpdate( out, es, false );
1257
1258     /* Select it if needed */
1259     EsOutSelect( out, es, false );
1260
1261
1262     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
1263     p_sys->i_id++;  /* always incremented */
1264     switch( fmt->i_cat )
1265     {
1266         case AUDIO_ES:
1267             p_sys->i_audio++;
1268             break;
1269         case SPU_ES:
1270             p_sys->i_sub++;
1271             break;
1272         case VIDEO_ES:
1273             p_sys->i_video++;
1274             break;
1275     }
1276
1277     EsOutAddInfo( out, es );
1278
1279     return es;
1280 }
1281
1282 static bool EsIsSelected( es_out_id_t *es )
1283 {
1284     if( es->p_master )
1285     {
1286         bool b_decode = false;
1287         if( es->p_master->p_dec )
1288         {
1289             int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1290             if( i_channel != -1 )
1291                 input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
1292         }
1293         return b_decode;
1294     }
1295     else
1296     {
1297         return es->p_dec != NULL;
1298     }
1299 }
1300 static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
1301 {
1302     es_out_sys_t   *p_sys = out->p_sys;
1303     input_thread_t *p_input = p_sys->p_input;
1304
1305     p_es->p_dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_input->p->p_sout );
1306     if( p_es->p_dec )
1307     {
1308         if( p_sys->b_buffering )
1309             input_DecoderStartBuffering( p_es->p_dec );
1310
1311         if( !p_es->p_master && p_sys->p_sout_record )
1312         {
1313             p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
1314             if( p_es->p_dec_record && p_sys->b_buffering )
1315                 input_DecoderStartBuffering( p_es->p_dec_record );
1316         }
1317     }
1318
1319     EsOutDecoderChangeDelay( out, p_es );
1320 }
1321 static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
1322 {
1323     VLC_UNUSED(out);
1324
1325     if( !p_es->p_dec )
1326         return;
1327
1328     input_DecoderDelete( p_es->p_dec );
1329     p_es->p_dec = NULL;
1330
1331     if( p_es->p_dec_record )
1332     {
1333         input_DecoderDelete( p_es->p_dec_record );
1334         p_es->p_dec_record = NULL;
1335     }
1336 }
1337
1338 static void EsSelect( es_out_t *out, es_out_id_t *es )
1339 {
1340     es_out_sys_t   *p_sys = out->p_sys;
1341     input_thread_t *p_input = p_sys->p_input;
1342     vlc_value_t    val;
1343     const char     *psz_var;
1344
1345     if( EsIsSelected( es ) )
1346     {
1347         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1348         return;
1349     }
1350
1351     if( es->p_master )
1352     {
1353         int i_channel;
1354         if( !es->p_master->p_dec )
1355             return;
1356
1357         i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1358         if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) )
1359             return;
1360     }
1361     else
1362     {
1363         if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1364         {
1365             if( !var_GetBool( p_input, out->b_sout ? "sout-video" : "video" ) )
1366             {
1367                 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1368                          es->i_id );
1369                 return;
1370             }
1371         }
1372         else if( es->fmt.i_cat == AUDIO_ES )
1373         {
1374             var_Get( p_input, "audio", &val );
1375             if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) )
1376             {
1377                 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1378                          es->i_id );
1379                 return;
1380             }
1381         }
1382         if( es->fmt.i_cat == SPU_ES )
1383         {
1384             var_Get( p_input, "spu", &val );
1385             if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) )
1386             {
1387                 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1388                          es->i_id );
1389                 return;
1390             }
1391         }
1392
1393         es->i_preroll_end = -1;
1394         EsCreateDecoder( out, es );
1395
1396         if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1397             return;
1398     }
1399
1400     if( es->fmt.i_cat == VIDEO_ES )
1401         psz_var = "video-es";
1402     else if( es->fmt.i_cat == AUDIO_ES )
1403         psz_var = "audio-es";
1404     else if( es->fmt.i_cat == SPU_ES )
1405         psz_var = "spu-es";
1406     else
1407         return;
1408
1409     /* Mark it as selected */
1410     val.i_int = es->i_id;
1411     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1412
1413     var_SetBool( p_sys->p_input, "intf-change", true );
1414 }
1415
1416 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1417 {
1418     es_out_sys_t   *p_sys = out->p_sys;
1419     input_thread_t *p_input = p_sys->p_input;
1420     vlc_value_t    val;
1421     const char     *psz_var;
1422
1423     if( !EsIsSelected( es ) )
1424     {
1425         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1426         return;
1427     }
1428
1429     if( es->p_master )
1430     {
1431         if( es->p_master->p_dec )
1432         {
1433             int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1434             if( i_channel != -1 )
1435                 input_DecoderSetCcState( es->p_master->p_dec, false, i_channel );
1436         }
1437     }
1438     else
1439     {
1440         const int i_spu_id = var_GetInteger( p_input, "spu-es");
1441         int i;
1442         for( i = 0; i < 4; i++ )
1443         {
1444             if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1445                 continue;
1446
1447             if( i_spu_id == es->pp_cc_es[i]->i_id )
1448             {
1449                 /* Force unselection of the CC */
1450                 val.i_int = -1;
1451                 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1452                 if( !b_update )
1453                     var_SetBool( p_sys->p_input, "intf-change", true );
1454             }
1455             EsOutDel( out, es->pp_cc_es[i] );
1456
1457             es->pb_cc_present[i] = false;
1458         }
1459         EsDestroyDecoder( out, es );
1460     }
1461
1462     if( !b_update )
1463         return;
1464
1465     /* Update var */
1466     if( es->p_dec == NULL )
1467         return;
1468     if( es->fmt.i_cat == VIDEO_ES )
1469         psz_var = "video-es";
1470     else if( es->fmt.i_cat == AUDIO_ES )
1471         psz_var = "audio-es";
1472     else if( es->fmt.i_cat == SPU_ES )
1473         psz_var = "spu-es";
1474     else
1475         return;
1476
1477     /* Mark it as unselected */
1478     val.i_int = -1;
1479     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1480
1481     var_SetBool( p_sys->p_input, "intf-change", true );
1482 }
1483
1484 /**
1485  * Select an ES given the current mode
1486  * XXX: you need to take a the lock before (stream.stream_lock)
1487  *
1488  * \param out The es_out structure
1489  * \param es es_out_id structure
1490  * \param b_force ...
1491  * \return nothing
1492  */
1493 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1494 {
1495     es_out_sys_t      *p_sys = out->p_sys;
1496
1497     int i_cat = es->fmt.i_cat;
1498
1499     if( !p_sys->b_active ||
1500         ( !b_force && es->fmt.i_priority < 0 ) )
1501     {
1502         return;
1503     }
1504
1505     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1506     {
1507         if( !EsIsSelected( es ) )
1508             EsSelect( out, es );
1509     }
1510     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1511     {
1512         vlc_value_t val;
1513         int i;
1514         var_Get( p_sys->p_input, "programs", &val );
1515         for ( i = 0; i < val.p_list->i_count; i++ )
1516         {
1517             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1518             {
1519                 if( !EsIsSelected( es ) )
1520                     EsSelect( out, es );
1521                 break;
1522             }
1523         }
1524         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1525     }
1526     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1527     {
1528         int i_wanted  = -1;
1529
1530         if( es->p_pgrm != p_sys->p_pgrm )
1531             return;
1532
1533         if( i_cat == AUDIO_ES )
1534         {
1535             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1536                                      es->psz_language_code );
1537
1538             if( p_sys->p_es_audio &&
1539                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1540             {
1541                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1542                                          p_sys->p_es_audio->psz_language_code );
1543
1544                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1545                     return;
1546                 i_wanted = es->i_channel;
1547             }
1548             else
1549             {
1550                 /* Select audio if (no audio selected yet)
1551                  * - no audio-language
1552                  * - no audio code for the ES
1553                  * - audio code in the requested list */
1554                 if( idx1 >= 0 ||
1555                     !strcmp( es->psz_language_code, "??" ) ||
1556                     !p_sys->ppsz_audio_language )
1557                     i_wanted = es->i_channel;
1558             }
1559
1560             if( p_sys->i_audio_last >= 0 )
1561                 i_wanted = p_sys->i_audio_last;
1562
1563             if( p_sys->i_audio_id >= 0 )
1564             {
1565                 if( es->i_id == p_sys->i_audio_id )
1566                     i_wanted = es->i_channel;
1567                 else
1568                     return;
1569             }
1570         }
1571         else if( i_cat == SPU_ES )
1572         {
1573             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1574                                      es->psz_language_code );
1575
1576             if( p_sys->p_es_sub &&
1577                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1578             {
1579                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1580                                          p_sys->p_es_sub->psz_language_code );
1581
1582                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1583                         idx1, es->psz_language_code, idx2,
1584                         p_sys->p_es_sub->psz_language_code );
1585
1586                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1587                     return;
1588                 /* We found a SPU that matches our language request */
1589                 i_wanted  = es->i_channel;
1590             }
1591             else if( idx1 >= 0 )
1592             {
1593                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1594                         idx1, es->psz_language_code );
1595
1596                 i_wanted  = es->i_channel;
1597             }
1598             else if( p_sys->i_default_sub_id >= 0 )
1599             {
1600                 if( es->i_id == p_sys->i_default_sub_id )
1601                     i_wanted = es->i_channel;
1602             }
1603
1604             if( p_sys->i_sub_last >= 0 )
1605                 i_wanted  = p_sys->i_sub_last;
1606
1607             if( p_sys->i_sub_id >= 0 )
1608             {
1609                 if( es->i_id == p_sys->i_sub_id )
1610                     i_wanted = es->i_channel;
1611                 else
1612                     return;
1613             }
1614         }
1615         else if( i_cat == VIDEO_ES )
1616         {
1617             i_wanted  = es->i_channel;
1618         }
1619
1620         if( i_wanted == es->i_channel && !EsIsSelected( es ) )
1621             EsSelect( out, es );
1622     }
1623
1624     /* FIXME TODO handle priority here */
1625     if( EsIsSelected( es ) )
1626     {
1627         if( i_cat == AUDIO_ES )
1628         {
1629             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1630                 p_sys->p_es_audio &&
1631                 p_sys->p_es_audio != es &&
1632                 EsIsSelected( p_sys->p_es_audio ) )
1633             {
1634                 EsUnselect( out, p_sys->p_es_audio, false );
1635             }
1636             p_sys->p_es_audio = es;
1637         }
1638         else if( i_cat == SPU_ES )
1639         {
1640             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1641                 p_sys->p_es_sub &&
1642                 p_sys->p_es_sub != es &&
1643                 EsIsSelected( p_sys->p_es_sub ) )
1644             {
1645                 EsUnselect( out, p_sys->p_es_sub, false );
1646             }
1647             p_sys->p_es_sub = es;
1648         }
1649         else if( i_cat == VIDEO_ES )
1650         {
1651             p_sys->p_es_video = es;
1652         }
1653     }
1654 }
1655
1656 /**
1657  * Send a block for the given es_out
1658  *
1659  * \param out the es_out to send from
1660  * \param es the es_out_id
1661  * \param p_block the data block to send
1662  */
1663 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1664 {
1665     es_out_sys_t   *p_sys = out->p_sys;
1666     input_thread_t *p_input = p_sys->p_input;
1667     int i_total = 0;
1668
1669     if( libvlc_stats( p_input ) )
1670     {
1671         vlc_mutex_lock( &p_input->p->counters.counters_lock );
1672         stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1673                              p_block->i_buffer, &i_total );
1674         stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1675                            (float)i_total, NULL );
1676         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1677     }
1678
1679     /* Mark preroll blocks */
1680     if( es->i_preroll_end >= 0 )
1681     {
1682         int64_t i_date = p_block->i_pts;
1683         if( i_date <= 0 )
1684             i_date = p_block->i_dts;
1685
1686         if( i_date < es->i_preroll_end )
1687             p_block->i_flags |= BLOCK_FLAG_PREROLL;
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 }