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