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