]> git.sesse.net Git - vlc/blob - src/input/es_out.c
Privatized i_pts_delay (input_thread_t).
[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 *, const vlc_meta_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->p->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     input_SendEventCache( p_sys->p_input, 0.0 );
579
580     for( int i = 0; i < p_sys->i_es; i++ )
581     {
582         es_out_id_t *p_es = p_sys->es[i];
583
584         if( !p_es->p_dec )
585             continue;
586
587         input_DecoderStartBuffering( p_es->p_dec );
588
589         if( p_es->p_dec_record )
590             input_DecoderStartBuffering( p_es->p_dec_record );
591     }
592
593     for( int i = 0; i < p_sys->i_pgrm; i++ )
594         input_clock_Reset( p_sys->pgrm[i]->p_clock );
595
596     p_sys->b_buffering = true;
597     p_sys->i_buffering_extra_initial = 0;
598     p_sys->i_buffering_extra_stream = 0;
599     p_sys->i_buffering_extra_system = 0;
600     p_sys->i_preroll_end = -1;
601 }
602
603
604
605 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
606 {
607     es_out_sys_t *p_sys = out->p_sys;
608     int i_ret;
609
610     mtime_t i_stream_start;
611     mtime_t i_system_start;
612     mtime_t i_stream_duration;
613     mtime_t i_system_duration;
614     i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
615                                   &i_stream_start, &i_system_start,
616                                   &i_stream_duration, &i_system_duration );
617     assert( !i_ret || b_forced );
618     if( i_ret )
619         return;
620
621     mtime_t i_preroll_duration = 0;
622     if( p_sys->i_preroll_end >= 0 )
623         i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
624
625     const mtime_t i_buffering_duration = p_sys->p_input->p->i_pts_delay +
626                                          i_preroll_duration +
627                                          p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
628
629     if( i_stream_duration <= i_buffering_duration && !b_forced )
630     {
631         const double f_level = (double)i_stream_duration / i_buffering_duration;
632         input_SendEventCache( p_sys->p_input, f_level );
633
634         msg_Dbg( p_sys->p_input, "Buffering %d%%", (int)(100 * f_level) );
635         return;
636     }
637     input_SendEventCache( p_sys->p_input, 1.0 );
638
639     msg_Dbg( p_sys->p_input, "Stream buffering done (%d ms in %d ms)",
640               (int)(i_stream_duration/1000), (int)(i_system_duration/1000) );
641     p_sys->b_buffering = false;
642     p_sys->i_preroll_end = -1;
643
644     if( p_sys->i_buffering_extra_initial > 0 )
645     {
646         /* FIXME wrong ? */
647         return;
648     }
649
650     const mtime_t i_decoder_buffering_start = mdate();
651     for( int i = 0; i < p_sys->i_es; i++ )
652     {
653         es_out_id_t *p_es = p_sys->es[i];
654
655         if( !p_es->p_dec || p_es->fmt.i_cat == SPU_ES )
656             continue;
657         input_DecoderWaitBuffering( p_es->p_dec );
658         if( p_es->p_dec_record )
659             input_DecoderWaitBuffering( p_es->p_dec_record );
660     }
661
662     msg_Dbg( p_sys->p_input, "Decoder buffering done in %d ms",
663               (int)(mdate() - i_decoder_buffering_start)/1000 );
664
665     /* Here is a good place to destroy unused vout with every demuxer */
666     input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
667
668     /* */
669     const mtime_t i_wakeup_delay = 10*1000; /* FIXME CLEANUP thread wake up time*/
670     const mtime_t i_current_date = p_sys->b_paused ? p_sys->i_pause_date : mdate();
671
672     input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_clock, i_current_date + i_wakeup_delay - i_buffering_duration );
673
674     for( int i = 0; i < p_sys->i_es; i++ )
675     {
676         es_out_id_t *p_es = p_sys->es[i];
677
678         if( !p_es->p_dec )
679             continue;
680
681         input_DecoderStopBuffering( p_es->p_dec );
682         if( p_es->p_dec_record )
683             input_DecoderStopBuffering( p_es->p_dec_record );
684     }
685 }
686 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
687 {
688     es_out_sys_t *p_sys = out->p_sys;
689
690     /* Pause decoders first */
691     for( int i = 0; i < p_sys->i_es; i++ )
692     {
693         es_out_id_t *es = p_sys->es[i];
694
695         if( es->p_dec )
696         {
697             input_DecoderChangePause( es->p_dec, b_paused, i_date );
698             if( es->p_dec_record )
699                 input_DecoderChangePause( es->p_dec_record, b_paused, i_date );
700         }
701     }
702 }
703 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
704 {
705     es_out_sys_t *p_sys = out->p_sys;
706
707     for( int i = 0; i < p_sys->i_pgrm; i++ )
708         input_clock_ChangePause( p_sys->pgrm[i]->p_clock, b_paused, i_date );
709 }
710
711 static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es )
712 {
713     es_out_sys_t *p_sys = out->p_sys;
714
715     mtime_t i_delay = 0;
716     if( p_es->fmt.i_cat == AUDIO_ES )
717         i_delay = p_sys->i_audio_delay;
718     else if( p_es->fmt.i_cat == SPU_ES )
719         i_delay = p_sys->i_spu_delay;
720
721     if( i_delay != 0 )
722     {
723         if( p_es->p_dec )
724             input_DecoderChangeDelay( p_es->p_dec, i_delay );
725         if( p_es->p_dec_record )
726             input_DecoderChangeDelay( p_es->p_dec_record, i_delay );
727     }
728 }
729 static void EsOutProgramsChangeRate( es_out_t *out )
730 {
731     es_out_sys_t      *p_sys = out->p_sys;
732
733     for( int i = 0; i < p_sys->i_pgrm; i++ )
734         input_clock_ChangeRate( p_sys->pgrm[i]->p_clock, p_sys->i_rate );
735 }
736
737 static void EsOutFrameNext( es_out_t *out )
738 {
739     es_out_sys_t *p_sys = out->p_sys;
740     es_out_id_t *p_es_video = NULL;
741
742     if( p_sys->b_buffering )
743     {
744         msg_Warn( p_sys->p_input, "buffering, ignoring 'frame next'" );
745         return;
746     }
747
748     assert( p_sys->b_paused );
749
750     for( int i = 0; i < p_sys->i_es; i++ )
751     {
752         es_out_id_t *p_es = p_sys->es[i];
753
754         if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
755         {
756             p_es_video = p_es;
757             break;
758         }
759     }
760
761     if( !p_es_video )
762     {
763         msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame next'" );
764         return;
765     }
766
767     mtime_t i_duration;
768     input_DecoderFrameNext( p_es_video->p_dec, &i_duration );
769
770     msg_Dbg( out->p_sys->p_input, "EsOutFrameNext consummed %d ms", (int)(i_duration/1000) );
771
772     if( i_duration <= 0 )
773         i_duration = 40*1000;
774
775     /* FIXME it is not a clean way ? */
776     if( p_sys->i_buffering_extra_initial <= 0 )
777     {
778         mtime_t i_stream_start;
779         mtime_t i_system_start;
780         mtime_t i_stream_duration;
781         mtime_t i_system_duration;
782         int i_ret;
783
784         i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
785                                       &i_stream_start, &i_system_start,
786                                       &i_stream_duration, &i_system_duration );
787         if( i_ret )
788             return;
789
790         p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->p_input->p->i_pts_delay; /* FIXME < 0 ? */
791         p_sys->i_buffering_extra_system =
792         p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
793     }
794
795     const int i_rate = input_clock_GetRate( p_sys->p_pgrm->p_clock );
796
797     p_sys->b_buffering = true;
798     p_sys->i_buffering_extra_system += i_duration;
799     p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial +
800                                       ( p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial ) *
801                                                 INPUT_RATE_DEFAULT / i_rate;
802
803     p_sys->i_preroll_end = -1;
804 }
805 static mtime_t EsOutGetBuffering( es_out_t *out )
806 {
807     es_out_sys_t *p_sys = out->p_sys;
808
809     if( !p_sys->p_pgrm )
810         return 0;
811
812     int i_ret;
813     mtime_t i_stream_start;
814     mtime_t i_system_start;
815     mtime_t i_stream_duration;
816     mtime_t i_system_duration;
817     i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
818                                   &i_stream_start, &i_system_start,
819                                   &i_stream_duration, &i_system_duration );
820
821     if( i_ret )
822         return 0;
823
824     mtime_t i_delay;
825
826     if( p_sys->b_buffering && p_sys->i_buffering_extra_initial <= 0 )
827     {
828         i_delay = i_stream_duration;
829     }
830     else
831     {
832         mtime_t i_system_duration;
833         if( p_sys->b_paused )
834         {
835             i_system_duration = p_sys->i_pause_date  - i_system_start;
836             if( p_sys->i_buffering_extra_initial > 0 )
837                 i_system_duration += p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
838         }
839         else
840         {
841             i_system_duration = mdate() - i_system_start;
842         }
843
844         const mtime_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration;
845         i_delay = p_sys->p_input->p->i_pts_delay - i_consumed;
846     }
847     if( i_delay < 0 )
848         return 0;
849     return i_delay;
850 }
851
852 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
853                                      bool b_delete )
854 {
855     es_out_sys_t      *p_sys = out->p_sys;
856     input_thread_t    *p_input = p_sys->p_input;
857     const  bool b_teletext = fmt->i_cat == SPU_ES && fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' );
858     vlc_value_t       val, text;
859
860     if( b_delete )
861     {
862         /* TODO it should probably be a list */
863         if( b_teletext )
864             input_SendEventTeletext( p_sys->p_input, -1 );
865
866         input_SendEventEsDel( p_input, SPU_ES, i_id );
867         return;
868     }
869
870     /* Get the number of ES already added */
871     const char *psz_var;
872     if( fmt->i_cat == AUDIO_ES )
873         psz_var = "audio-es";
874     else if( fmt->i_cat == VIDEO_ES )
875         psz_var = "video-es";
876     else
877         psz_var = "spu-es";
878
879     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
880     if( val.i_int == 0 )
881     {
882         vlc_value_t val2;
883
884         /* First one, we need to add the "Disable" choice */
885         val2.i_int = -1; text.psz_string = _("Disable");
886         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
887         val.i_int++;
888     }
889
890     /* Take care of the ES description */
891     if( fmt->psz_description && *fmt->psz_description )
892     {
893         if( psz_language && *psz_language )
894         {
895             text.psz_string = malloc( strlen( fmt->psz_description) +
896                                       strlen( psz_language ) + 10 );
897             sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
898                                                    psz_language );
899         }
900         else text.psz_string = strdup( fmt->psz_description );
901     }
902     else
903     {
904         if( psz_language && *psz_language )
905         {
906             if( asprintf( &text.psz_string, "%s %i - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
907                 text.psz_string = NULL;
908         }
909         else
910         {
911             if( asprintf( &text.psz_string, "%s %i", _( "Track" ), val.i_int ) == -1 )
912                 text.psz_string = NULL;
913         }
914     }
915
916     input_SendEventEsAdd( p_input, fmt->i_cat, i_id, text.psz_string );
917
918     free( text.psz_string );
919
920     if( b_teletext )
921     {
922         /* TODO it should probably be a list */
923         if( var_GetInteger( p_sys->p_input, "teletext-es" ) < 0 )
924             input_SendEventTeletext( p_sys->p_input, i_id );
925     }
926 }
927
928 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
929                               bool b_delete )
930 {
931     EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
932 }
933
934 /* EsOutProgramSelect:
935  *  Select a program and update the object variable
936  */
937 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
938 {
939     es_out_sys_t      *p_sys = out->p_sys;
940     input_thread_t    *p_input = p_sys->p_input;
941     int               i;
942
943     if( p_sys->p_pgrm == p_pgrm )
944         return; /* Nothing to do */
945
946     if( p_sys->p_pgrm )
947     {
948         es_out_pgrm_t *old = p_sys->p_pgrm;
949         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
950
951         for( i = 0; i < p_sys->i_es; i++ )
952         {
953             if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
954                 p_sys->i_mode != ES_OUT_MODE_ALL )
955                 EsUnselect( out, p_sys->es[i], true );
956         }
957
958         p_sys->p_es_audio = NULL;
959         p_sys->p_es_sub = NULL;
960         p_sys->p_es_video = NULL;
961     }
962
963     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
964
965     /* Mark it selected */
966     p_pgrm->b_selected = true;
967
968     /* Switch master stream */
969     p_sys->p_pgrm = p_pgrm;
970
971     /* Update "program" */
972     input_SendEventProgramSelect( p_input, p_pgrm->i_id );
973
974     /* Update "es-*" */
975     input_SendEventEsDel( p_input, AUDIO_ES, -1 );
976     input_SendEventEsDel( p_input, VIDEO_ES, -1 );
977     input_SendEventEsDel( p_input, SPU_ES, -1 );
978
979     /* TODO event */
980     var_SetInteger( p_input, "teletext-es", -1 );
981
982     for( i = 0; i < p_sys->i_es; i++ )
983     {
984         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
985             EsOutESVarUpdate( out, p_sys->es[i], false );
986         EsOutSelect( out, p_sys->es[i], false );
987     }
988
989     /* Update now playing */
990     input_item_SetNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
991     input_item_SetPublisher( p_input->p->p_item, p_pgrm->psz_publisher );
992
993     input_SendEventMeta( p_input );
994 }
995
996 /* EsOutAddProgram:
997  *  Add a program
998  */
999 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
1000 {
1001     es_out_sys_t      *p_sys = out->p_sys;
1002     input_thread_t    *p_input = p_sys->p_input;
1003
1004     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
1005     if( !p_pgrm )
1006         return NULL;
1007
1008     /* Init */
1009     p_pgrm->i_id = i_group;
1010     p_pgrm->i_es = 0;
1011     p_pgrm->b_selected = false;
1012     p_pgrm->psz_name = NULL;
1013     p_pgrm->psz_now_playing = NULL;
1014     p_pgrm->psz_publisher = NULL;
1015     p_pgrm->p_epg = NULL;
1016     p_pgrm->p_clock = input_clock_New( p_input->p->i_cr_average, p_sys->i_rate );
1017     if( !p_pgrm->p_clock )
1018     {
1019         free( p_pgrm );
1020         return NULL;
1021     }
1022
1023     /* Append it */
1024     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
1025
1026     /* Update "program" variable */
1027     input_SendEventProgramAdd( p_input, i_group, NULL );
1028
1029     if( i_group == var_GetInteger( p_input, "program" ) )
1030         EsOutProgramSelect( out, p_pgrm );
1031
1032     return p_pgrm;
1033 }
1034
1035 /* EsOutDelProgram:
1036  *  Delete a program
1037  */
1038 static int EsOutProgramDel( es_out_t *out, int i_group )
1039 {
1040     es_out_sys_t      *p_sys = out->p_sys;
1041     input_thread_t    *p_input = p_sys->p_input;
1042     es_out_pgrm_t     *p_pgrm = NULL;
1043     int               i;
1044
1045     for( i = 0; i < p_sys->i_pgrm; i++ )
1046     {
1047         if( p_sys->pgrm[i]->i_id == i_group )
1048         {
1049             p_pgrm = p_sys->pgrm[i];
1050             break;
1051         }
1052     }
1053
1054     if( p_pgrm == NULL )
1055         return VLC_EGENERIC;
1056
1057     if( p_pgrm->i_es )
1058     {
1059         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
1060                  i_group, p_pgrm->i_es );
1061         return VLC_EGENERIC;
1062     }
1063
1064     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
1065
1066     /* If program is selected we need to unselect it */
1067     if( p_sys->p_pgrm == p_pgrm )
1068         p_sys->p_pgrm = NULL;
1069
1070     input_clock_Delete( p_pgrm->p_clock );
1071
1072     free( p_pgrm->psz_name );
1073     free( p_pgrm->psz_now_playing );
1074     free( p_pgrm->psz_publisher );
1075     if( p_pgrm->p_epg )
1076         vlc_epg_Delete( p_pgrm->p_epg );
1077     free( p_pgrm );
1078
1079     /* Update "program" variable */
1080     input_SendEventProgramDel( p_input, i_group );
1081
1082     return VLC_SUCCESS;
1083 }
1084
1085 /* EsOutProgramMeta:
1086  */
1087 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
1088 {
1089     char *psz = NULL;
1090     if( p_pgrm->psz_name )
1091     {
1092         if( asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ) == -1 )
1093             return NULL;
1094     }
1095     else
1096     {
1097         if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
1098             return NULL;
1099     }
1100     return psz;
1101 }
1102
1103 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
1104 {
1105     es_out_sys_t      *p_sys = out->p_sys;
1106     es_out_pgrm_t     *p_pgrm = NULL;
1107     input_thread_t    *p_input = p_sys->p_input;
1108     char              *psz_cat;
1109     const char        *psz_title = NULL;
1110     const char        *psz_provider = NULL;
1111     int i;
1112
1113     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
1114
1115     /* Check against empty meta data (empty for what we handle) */
1116     if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
1117         !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
1118         !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
1119         vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
1120     {
1121         return;
1122     }
1123     /* Find program */
1124     for( i = 0; i < p_sys->i_pgrm; i++ )
1125     {
1126         if( p_sys->pgrm[i]->i_id == i_group )
1127         {
1128             p_pgrm = p_sys->pgrm[i];
1129             break;
1130         }
1131     }
1132     if( p_pgrm == NULL )
1133         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1134
1135     /* */
1136     psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
1137     psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
1138
1139     /* Update the description text of the program */
1140     if( psz_title && *psz_title )
1141     {
1142         if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
1143         {
1144             char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
1145
1146             /* Remove old entries */
1147             input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
1148             /* TODO update epg name */
1149             free( psz_cat );
1150         }
1151         free( p_pgrm->psz_name );
1152         p_pgrm->psz_name = strdup( psz_title );
1153
1154         char *psz_text;
1155         if( psz_provider && *psz_provider )
1156         {
1157             if( asprintf( &psz_text, "%s [%s]", psz_title, psz_provider ) < 0 )
1158                 psz_text = NULL;
1159         }
1160         else
1161         {
1162             psz_text = strdup( psz_title );
1163         }
1164
1165         /* ugly but it works */
1166         if( psz_text )
1167         {
1168             input_SendEventProgramDel( p_input, i_group );
1169             input_SendEventProgramAdd( p_input, i_group, psz_text );
1170
1171             free( psz_text );
1172         }
1173     }
1174
1175     psz_cat = EsOutProgramGetMetaName( p_pgrm );
1176     if( psz_provider )
1177     {
1178         if( p_sys->p_pgrm == p_pgrm )
1179         {
1180             input_item_SetPublisher( p_input->p->p_item, psz_provider );
1181             input_SendEventMeta( p_input );
1182         }
1183         input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
1184     }
1185     char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
1186     for( i = 0; ppsz_all_keys[i]; i++ )
1187     {
1188         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
1189                        vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
1190         free( ppsz_all_keys[i] );
1191     }
1192     free( ppsz_all_keys );
1193
1194     free( psz_cat );
1195 }
1196
1197 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
1198 {
1199     int i;
1200
1201     /* Add new event */
1202     for( i = 0; i < p_src->i_event; i++ )
1203     {
1204         vlc_epg_event_t *p_evt = p_src->pp_event[i];
1205         bool b_add = true;
1206         int j;
1207
1208         for( j = 0; j < p_dst->i_event; j++ )
1209         {
1210             if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
1211             {
1212                 b_add = false;
1213                 break;
1214             }
1215             if( p_dst->pp_event[j]->i_start > p_evt->i_start )
1216                 break;
1217         }
1218         if( b_add )
1219         {
1220             vlc_epg_event_t *p_copy = calloc( 1, sizeof(vlc_epg_event_t) );
1221             if( !p_copy )
1222                 break;
1223             p_copy->i_start = p_evt->i_start;
1224             p_copy->i_duration = p_evt->i_duration;
1225             p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
1226             p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
1227             p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
1228             TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
1229         }
1230     }
1231     /* Update current */
1232     vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
1233
1234     /* Keep only 1 old event  */
1235     if( p_dst->p_current )
1236     {
1237         while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
1238             TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
1239     }
1240 }
1241
1242 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
1243 {
1244     es_out_sys_t      *p_sys = out->p_sys;
1245     input_thread_t    *p_input = p_sys->p_input;
1246     es_out_pgrm_t     *p_pgrm = NULL;
1247     char *psz_cat;
1248     int i;
1249
1250     /* Find program */
1251     for( i = 0; i < p_sys->i_pgrm; i++ )
1252     {
1253         if( p_sys->pgrm[i]->i_id == i_group )
1254         {
1255             p_pgrm = p_sys->pgrm[i];
1256             break;
1257         }
1258     }
1259     if( p_pgrm == NULL )
1260         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1261
1262     /* Merge EPG */
1263     if( !p_pgrm->p_epg )
1264         p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
1265     vlc_epg_Merge( p_pgrm->p_epg, p_epg );
1266
1267     /* Update info */
1268     psz_cat = EsOutProgramGetMetaName( p_pgrm );
1269 #ifdef HAVE_LOCALTIME_R
1270     char *psz_epg;
1271     if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
1272         psz_epg = NULL;
1273     input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
1274     msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
1275     for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
1276     {
1277         const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
1278         time_t t_start = (time_t)p_evt->i_start;
1279         struct tm tm_start;
1280         char psz_start[128];
1281
1282         localtime_r( &t_start, &tm_start );
1283
1284         snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
1285         if( p_evt->psz_short_description || p_evt->psz_description )
1286             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
1287                            p_evt->psz_name,
1288                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
1289                            p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
1290         else
1291             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
1292                            p_evt->psz_name,
1293                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
1294     }
1295     free( psz_epg );
1296 #endif
1297     /* Update now playing */
1298     free( p_pgrm->psz_now_playing );
1299     p_pgrm->psz_now_playing = NULL;
1300     if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
1301         p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
1302
1303     if( p_pgrm == p_sys->p_pgrm )
1304     {
1305         input_item_SetNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
1306         input_SendEventMeta( p_input );
1307     }
1308
1309     if( p_pgrm->psz_now_playing )
1310     {
1311         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1312             input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
1313             p_pgrm->psz_now_playing );
1314     }
1315     else
1316     {
1317         input_Control( p_input, INPUT_DEL_INFO, psz_cat,
1318             input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
1319     }
1320
1321     free( psz_cat );
1322 }
1323
1324 /* EsOutAdd:
1325  *  Add an es_out
1326  */
1327 static es_out_id_t *EsOutAdd( es_out_t *out, const es_format_t *fmt )
1328 {
1329     es_out_sys_t      *p_sys = out->p_sys;
1330     input_thread_t    *p_input = p_sys->p_input;
1331
1332     if( fmt->i_group < 0 )
1333     {
1334         msg_Err( p_input, "invalid group number" );
1335         return NULL;
1336     }
1337
1338     es_out_id_t       *es = malloc( sizeof( *es ) );
1339     es_out_pgrm_t     *p_pgrm = NULL;
1340     int i;
1341
1342     if( !es )
1343         return NULL;
1344
1345     vlc_mutex_lock( &p_sys->lock );
1346
1347     /* Search the program */
1348     for( i = 0; i < p_sys->i_pgrm; i++ )
1349     {
1350         if( fmt->i_group == p_sys->pgrm[i]->i_id )
1351         {
1352             p_pgrm = p_sys->pgrm[i];
1353             break;
1354         }
1355     }
1356     if( p_pgrm == NULL )
1357     {
1358         /* Create a new one */
1359         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
1360     }
1361
1362     /* Increase ref count for program */
1363     p_pgrm->i_es++;
1364
1365     /* Set up ES */
1366     es->p_pgrm = p_pgrm;
1367     es_format_Copy( &es->fmt, fmt );
1368     if( es->fmt.i_id < 0 )
1369         es->fmt.i_id = out->p_sys->i_id;
1370     es->i_id = es->fmt.i_id;
1371     es->i_meta_id = out->p_sys->i_id;
1372
1373     switch( es->fmt.i_cat )
1374     {
1375     case AUDIO_ES:
1376     {
1377         audio_replay_gain_t rg;
1378
1379         es->i_channel = p_sys->i_audio;
1380
1381         memset( &rg, 0, sizeof(rg) );
1382         vlc_mutex_lock( &p_input->p->p_item->lock );
1383         vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->p_item->p_meta );
1384         vlc_mutex_unlock( &p_input->p->p_item->lock );
1385
1386         for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
1387         {
1388             if( !es->fmt.audio_replay_gain.pb_peak[i] )
1389             {
1390                 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
1391                 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
1392             }
1393             if( !es->fmt.audio_replay_gain.pb_gain[i] )
1394             {
1395                 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
1396                 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
1397             }
1398         }
1399         break;
1400     }
1401
1402     case VIDEO_ES:
1403         es->i_channel = p_sys->i_video;
1404         if( es->fmt.video.i_frame_rate && es->fmt.video.i_frame_rate_base )
1405             vlc_ureduce( &es->fmt.video.i_frame_rate,
1406                          &es->fmt.video.i_frame_rate_base,
1407                          es->fmt.video.i_frame_rate,
1408                          es->fmt.video.i_frame_rate_base, 0 );
1409         break;
1410
1411     case SPU_ES:
1412         es->i_channel = p_sys->i_sub;
1413         break;
1414
1415     default:
1416         es->i_channel = 0;
1417         break;
1418     }
1419     es->psz_language = LanguageGetName( es->fmt.psz_language ); /* remember so we only need to do it once */
1420     es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
1421     es->p_dec = NULL;
1422     es->p_dec_record = NULL;
1423     for( i = 0; i < 4; i++ )
1424         es->pb_cc_present[i] = false;
1425     es->p_master = NULL;
1426
1427     if( es->p_pgrm == p_sys->p_pgrm )
1428         EsOutESVarUpdate( out, es, false );
1429
1430     /* Select it if needed */
1431     EsOutSelect( out, es, false );
1432
1433
1434     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
1435     p_sys->i_id++;  /* always incremented */
1436     switch( es->fmt.i_cat )
1437     {
1438         case AUDIO_ES:
1439             p_sys->i_audio++;
1440             break;
1441         case SPU_ES:
1442             p_sys->i_sub++;
1443             break;
1444         case VIDEO_ES:
1445             p_sys->i_video++;
1446             break;
1447     }
1448
1449     EsOutUpdateInfo( out, es, &es->fmt, NULL );
1450
1451     vlc_mutex_unlock( &p_sys->lock );
1452
1453     return es;
1454 }
1455
1456 static bool EsIsSelected( es_out_id_t *es )
1457 {
1458     if( es->p_master )
1459     {
1460         bool b_decode = false;
1461         if( es->p_master->p_dec )
1462         {
1463             int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1464             if( i_channel != -1 )
1465                 input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
1466         }
1467         return b_decode;
1468     }
1469     else
1470     {
1471         return es->p_dec != NULL;
1472     }
1473 }
1474 static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
1475 {
1476     es_out_sys_t   *p_sys = out->p_sys;
1477     input_thread_t *p_input = p_sys->p_input;
1478
1479     p_es->p_dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_input->p->p_sout );
1480     if( p_es->p_dec )
1481     {
1482         if( p_sys->b_buffering )
1483             input_DecoderStartBuffering( p_es->p_dec );
1484
1485         if( !p_es->p_master && p_sys->p_sout_record )
1486         {
1487             p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
1488             if( p_es->p_dec_record && p_sys->b_buffering )
1489                 input_DecoderStartBuffering( p_es->p_dec_record );
1490         }
1491     }
1492
1493     EsOutDecoderChangeDelay( out, p_es );
1494 }
1495 static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
1496 {
1497     VLC_UNUSED(out);
1498
1499     if( !p_es->p_dec )
1500         return;
1501
1502     input_DecoderDelete( p_es->p_dec );
1503     p_es->p_dec = NULL;
1504
1505     if( p_es->p_dec_record )
1506     {
1507         input_DecoderDelete( p_es->p_dec_record );
1508         p_es->p_dec_record = NULL;
1509     }
1510 }
1511
1512 static void EsSelect( es_out_t *out, es_out_id_t *es )
1513 {
1514     es_out_sys_t   *p_sys = out->p_sys;
1515     input_thread_t *p_input = p_sys->p_input;
1516     vlc_value_t    val;
1517
1518     if( EsIsSelected( es ) )
1519     {
1520         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1521         return;
1522     }
1523
1524     if( es->p_master )
1525     {
1526         int i_channel;
1527         if( !es->p_master->p_dec )
1528             return;
1529
1530         i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1531         if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) )
1532             return;
1533     }
1534     else
1535     {
1536         if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1537         {
1538             if( !var_GetBool( p_input, out->b_sout ? "sout-video" : "video" ) )
1539             {
1540                 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1541                          es->i_id );
1542                 return;
1543             }
1544         }
1545         else if( es->fmt.i_cat == AUDIO_ES )
1546         {
1547             var_Get( p_input, "audio", &val );
1548             if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) )
1549             {
1550                 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1551                          es->i_id );
1552                 return;
1553             }
1554         }
1555         if( es->fmt.i_cat == SPU_ES )
1556         {
1557             var_Get( p_input, "spu", &val );
1558             if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) )
1559             {
1560                 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1561                          es->i_id );
1562                 return;
1563             }
1564         }
1565
1566         EsCreateDecoder( out, es );
1567
1568         if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1569             return;
1570     }
1571
1572     /* Mark it as selected */
1573     input_SendEventEsSelect( p_input, es->fmt.i_cat, es->i_id );
1574 }
1575
1576 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1577 {
1578     es_out_sys_t   *p_sys = out->p_sys;
1579     input_thread_t *p_input = p_sys->p_input;
1580
1581     if( !EsIsSelected( es ) )
1582     {
1583         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1584         return;
1585     }
1586
1587     if( es->p_master )
1588     {
1589         if( es->p_master->p_dec )
1590         {
1591             int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1592             if( i_channel != -1 )
1593                 input_DecoderSetCcState( es->p_master->p_dec, false, i_channel );
1594         }
1595     }
1596     else
1597     {
1598         const int i_spu_id = var_GetInteger( p_input, "spu-es");
1599         int i;
1600         for( i = 0; i < 4; i++ )
1601         {
1602             if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1603                 continue;
1604
1605             if( i_spu_id == es->pp_cc_es[i]->i_id )
1606             {
1607                 /* Force unselection of the CC */
1608                 input_SendEventEsSelect( p_input, SPU_ES, -1 );
1609             }
1610             EsOutDel( out, es->pp_cc_es[i] );
1611
1612             es->pb_cc_present[i] = false;
1613         }
1614         EsDestroyDecoder( out, es );
1615     }
1616
1617     if( !b_update )
1618         return;
1619
1620     /* Update var */
1621     if( es->p_dec == NULL )
1622         return;
1623
1624     /* Mark it as unselected */
1625     input_SendEventEsSelect( p_input, es->fmt.i_cat, -1 );
1626 }
1627
1628 /**
1629  * Select an ES given the current mode
1630  * XXX: you need to take a the lock before (stream.stream_lock)
1631  *
1632  * \param out The es_out structure
1633  * \param es es_out_id structure
1634  * \param b_force ...
1635  * \return nothing
1636  */
1637 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1638 {
1639     es_out_sys_t      *p_sys = out->p_sys;
1640
1641     int i_cat = es->fmt.i_cat;
1642
1643     if( !p_sys->b_active ||
1644         ( !b_force && es->fmt.i_priority < 0 ) )
1645     {
1646         return;
1647     }
1648
1649     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1650     {
1651         if( !EsIsSelected( es ) )
1652             EsSelect( out, es );
1653     }
1654     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1655     {
1656         vlc_value_t val;
1657         int i;
1658         var_Get( p_sys->p_input, "programs", &val );
1659         for ( i = 0; i < val.p_list->i_count; i++ )
1660         {
1661             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1662             {
1663                 if( !EsIsSelected( es ) )
1664                     EsSelect( out, es );
1665                 break;
1666             }
1667         }
1668         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1669     }
1670     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1671     {
1672         int i_wanted  = -1;
1673
1674         if( es->p_pgrm != p_sys->p_pgrm )
1675             return;
1676
1677         if( i_cat == AUDIO_ES )
1678         {
1679             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1680                                      es->psz_language_code );
1681
1682             if( p_sys->p_es_audio &&
1683                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1684             {
1685                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1686                                          p_sys->p_es_audio->psz_language_code );
1687
1688                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1689                     return;
1690                 i_wanted = es->i_channel;
1691             }
1692             else
1693             {
1694                 /* Select audio if (no audio selected yet)
1695                  * - no audio-language
1696                  * - no audio code for the ES
1697                  * - audio code in the requested list */
1698                 if( idx1 >= 0 ||
1699                     !strcmp( es->psz_language_code, "??" ) ||
1700                     !p_sys->ppsz_audio_language )
1701                     i_wanted = es->i_channel;
1702             }
1703
1704             if( p_sys->i_audio_last >= 0 )
1705                 i_wanted = p_sys->i_audio_last;
1706
1707             if( p_sys->i_audio_id >= 0 )
1708             {
1709                 if( es->i_id == p_sys->i_audio_id )
1710                     i_wanted = es->i_channel;
1711                 else
1712                     return;
1713             }
1714         }
1715         else if( i_cat == SPU_ES )
1716         {
1717             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1718                                      es->psz_language_code );
1719
1720             if( p_sys->p_es_sub &&
1721                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1722             {
1723                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1724                                          p_sys->p_es_sub->psz_language_code );
1725
1726                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1727                         idx1, es->psz_language_code, idx2,
1728                         p_sys->p_es_sub->psz_language_code );
1729
1730                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1731                     return;
1732                 /* We found a SPU that matches our language request */
1733                 i_wanted  = es->i_channel;
1734             }
1735             else if( idx1 >= 0 )
1736             {
1737                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1738                         idx1, es->psz_language_code );
1739
1740                 i_wanted  = es->i_channel;
1741             }
1742             else if( p_sys->i_default_sub_id >= 0 )
1743             {
1744                 if( es->i_id == p_sys->i_default_sub_id )
1745                     i_wanted = es->i_channel;
1746             }
1747
1748             if( p_sys->i_sub_last >= 0 )
1749                 i_wanted  = p_sys->i_sub_last;
1750
1751             if( p_sys->i_sub_id >= 0 )
1752             {
1753                 if( es->i_id == p_sys->i_sub_id )
1754                     i_wanted = es->i_channel;
1755                 else
1756                     return;
1757             }
1758         }
1759         else if( i_cat == VIDEO_ES )
1760         {
1761             i_wanted  = es->i_channel;
1762         }
1763
1764         if( i_wanted == es->i_channel && !EsIsSelected( es ) )
1765             EsSelect( out, es );
1766     }
1767
1768     /* FIXME TODO handle priority here */
1769     if( EsIsSelected( es ) )
1770     {
1771         if( i_cat == AUDIO_ES )
1772         {
1773             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1774                 p_sys->p_es_audio &&
1775                 p_sys->p_es_audio != es &&
1776                 EsIsSelected( p_sys->p_es_audio ) )
1777             {
1778                 EsUnselect( out, p_sys->p_es_audio, false );
1779             }
1780             p_sys->p_es_audio = es;
1781         }
1782         else if( i_cat == SPU_ES )
1783         {
1784             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1785                 p_sys->p_es_sub &&
1786                 p_sys->p_es_sub != es &&
1787                 EsIsSelected( p_sys->p_es_sub ) )
1788             {
1789                 EsUnselect( out, p_sys->p_es_sub, false );
1790             }
1791             p_sys->p_es_sub = es;
1792         }
1793         else if( i_cat == VIDEO_ES )
1794         {
1795             p_sys->p_es_video = es;
1796         }
1797     }
1798 }
1799
1800 /**
1801  * Send a block for the given es_out
1802  *
1803  * \param out the es_out to send from
1804  * \param es the es_out_id
1805  * \param p_block the data block to send
1806  */
1807 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1808 {
1809     es_out_sys_t   *p_sys = out->p_sys;
1810     input_thread_t *p_input = p_sys->p_input;
1811     int i_total = 0;
1812
1813     if( libvlc_stats( p_input ) )
1814     {
1815         vlc_mutex_lock( &p_input->p->counters.counters_lock );
1816         stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1817                              p_block->i_buffer, &i_total );
1818         stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1819                            (float)i_total, NULL );
1820         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1821     }
1822
1823     vlc_mutex_lock( &p_sys->lock );
1824
1825     /* Mark preroll blocks */
1826     if( p_sys->i_preroll_end >= 0 )
1827     {
1828         int64_t i_date = p_block->i_pts;
1829         if( i_date <= 0 )
1830             i_date = p_block->i_dts;
1831
1832         if( i_date < p_sys->i_preroll_end )
1833             p_block->i_flags |= BLOCK_FLAG_PREROLL;
1834     }
1835
1836     p_block->i_rate = 0;
1837
1838     if( !es->p_dec )
1839     {
1840         block_Release( p_block );
1841         vlc_mutex_unlock( &p_sys->lock );
1842         return VLC_SUCCESS;
1843     }
1844
1845     /* Decode */
1846     if( es->p_dec_record )
1847     {
1848         block_t *p_dup = block_Duplicate( p_block );
1849         if( p_dup )
1850             input_DecoderDecode( es->p_dec_record, p_dup );
1851     }
1852     input_DecoderDecode( es->p_dec, p_block );
1853
1854     es_format_t fmt_dsc;
1855     vlc_meta_t  *p_meta_dsc;
1856     if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
1857     {
1858         EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );
1859
1860         es_format_Clean( &fmt_dsc );
1861         if( p_meta_dsc )
1862             vlc_meta_Delete( p_meta_dsc );
1863     }
1864
1865     /* Check CC status */
1866     bool pb_cc[4];
1867
1868     input_DecoderIsCcPresent( es->p_dec, pb_cc );
1869     for( int i = 0; i < 4; i++ )
1870     {
1871         static const vlc_fourcc_t fcc[4] = {
1872             VLC_FOURCC('c', 'c', '1', ' '),
1873             VLC_FOURCC('c', 'c', '2', ' '),
1874             VLC_FOURCC('c', 'c', '3', ' '),
1875             VLC_FOURCC('c', 'c', '4', ' '),
1876         };
1877         es_format_t fmt;
1878
1879         if(  es->pb_cc_present[i] || !pb_cc[i] )
1880             continue;
1881         msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
1882
1883         es_format_Init( &fmt, SPU_ES, fcc[i] );
1884         fmt.i_group = es->fmt.i_group;
1885         if( asprintf( &fmt.psz_description,
1886                       _("Closed captions %u"), 1 + i ) == -1 )
1887             fmt.psz_description = NULL;
1888         es->pp_cc_es[i] = EsOutAdd( out, &fmt );
1889         es->pp_cc_es[i]->p_master = es;
1890         es_format_Clean( &fmt );
1891
1892         /* */
1893         es->pb_cc_present[i] = true;
1894     }
1895
1896     vlc_mutex_unlock( &p_sys->lock );
1897
1898     return VLC_SUCCESS;
1899 }
1900
1901 /*****************************************************************************
1902  * EsOutDel:
1903  *****************************************************************************/
1904 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1905 {
1906     es_out_sys_t *p_sys = out->p_sys;
1907     bool b_reselect = false;
1908     int i;
1909
1910     vlc_mutex_lock( &p_sys->lock );
1911
1912     /* We don't try to reselect */
1913     if( es->p_dec )
1914     {
1915         while( !p_sys->p_input->b_die && !p_sys->b_buffering && es->p_dec )
1916         {
1917             if( input_DecoderIsEmpty( es->p_dec ) &&
1918                 ( !es->p_dec_record || input_DecoderIsEmpty( es->p_dec_record ) ))
1919                 break;
1920             /* FIXME there should be a way to have auto deleted es, but there will be
1921              * a problem when another codec of the same type is created (mainly video) */
1922             msleep( 20*1000 );
1923         }
1924         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1925     }
1926
1927     if( es->p_pgrm == p_sys->p_pgrm )
1928         EsOutESVarUpdate( out, es, true );
1929
1930     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1931
1932     es->p_pgrm->i_es--;
1933     if( es->p_pgrm->i_es == 0 )
1934     {
1935         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1936     }
1937
1938     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1939         p_sys->p_es_sub == es ) b_reselect = true;
1940
1941     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1942     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1943     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
1944
1945     switch( es->fmt.i_cat )
1946     {
1947         case AUDIO_ES:
1948             p_sys->i_audio--;
1949             break;
1950         case SPU_ES:
1951             p_sys->i_sub--;
1952             break;
1953         case VIDEO_ES:
1954             p_sys->i_video--;
1955             break;
1956     }
1957
1958     /* Re-select another track when needed */
1959     if( b_reselect )
1960     {
1961         for( i = 0; i < p_sys->i_es; i++ )
1962         {
1963             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1964                 EsOutSelect( out, p_sys->es[i], false );
1965         }
1966     }
1967
1968     free( es->psz_language );
1969     free( es->psz_language_code );
1970
1971     es_format_Clean( &es->fmt );
1972
1973     vlc_mutex_unlock( &p_sys->lock );
1974
1975     free( es );
1976 }
1977
1978 /**
1979  * Control query handler
1980  *
1981  * \param out the es_out to control
1982  * \param i_query A es_out query as defined in include/ninput.h
1983  * \param args a variable list of arguments for the query
1984  * \return VLC_SUCCESS or an error code
1985  */
1986 static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
1987 {
1988     es_out_sys_t *p_sys = out->p_sys;
1989     bool  b, *pb;
1990     int         i;
1991
1992     es_out_id_t *es;
1993
1994     switch( i_query )
1995     {
1996         case ES_OUT_SET_ES_STATE:
1997             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1998             b = (bool) va_arg( args, int );
1999             if( b && !EsIsSelected( es ) )
2000             {
2001                 EsSelect( out, es );
2002                 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
2003             }
2004             else if( !b && EsIsSelected( es ) )
2005             {
2006                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2007                 return VLC_SUCCESS;
2008             }
2009             return VLC_SUCCESS;
2010
2011         case ES_OUT_GET_ES_STATE:
2012             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
2013             pb = (bool*) va_arg( args, bool * );
2014
2015             *pb = EsIsSelected( es );
2016             return VLC_SUCCESS;
2017
2018         case ES_OUT_SET_ACTIVE:
2019         {
2020             b = (bool) va_arg( args, int );
2021             if( b && !p_sys->b_active && p_sys->i_es > 0 )
2022             {
2023                 /* XXX Terminate vout if there are tracks but no video one.
2024                  * This one is not mandatory but is he earliest place where it
2025                  * can be done */
2026                 for( i = 0; i < p_sys->i_es; i++ )
2027                 {
2028                     es_out_id_t *p_es = p_sys->es[i];
2029                     if( p_es->fmt.i_cat == VIDEO_ES )
2030                         break;
2031                 }
2032                 if( i >= p_sys->i_es )
2033                     input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
2034             }
2035             p_sys->b_active = b;
2036             return VLC_SUCCESS;
2037         }
2038
2039         case ES_OUT_SET_MODE:
2040             i = (int) va_arg( args, int );
2041             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
2042                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
2043             {
2044                 p_sys->i_mode = i;
2045
2046                 /* Reapply policy mode */
2047                 for( i = 0; i < p_sys->i_es; i++ )
2048                 {
2049                     if( EsIsSelected( p_sys->es[i] ) )
2050                     {
2051                         EsUnselect( out, p_sys->es[i],
2052                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
2053                     }
2054                 }
2055                 for( i = 0; i < p_sys->i_es; i++ )
2056                 {
2057                     EsOutSelect( out, p_sys->es[i], false );
2058                 }
2059                 return VLC_SUCCESS;
2060             }
2061             return VLC_EGENERIC;
2062
2063         case ES_OUT_SET_ES:
2064         case ES_OUT_RESTART_ES:
2065         {
2066             int i_cat;
2067
2068             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
2069
2070             if( es == NULL )
2071                 i_cat = UNKNOWN_ES;
2072             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
2073                 i_cat = AUDIO_ES;
2074             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
2075                 i_cat = VIDEO_ES;
2076             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
2077                 i_cat = SPU_ES;
2078             else
2079                 i_cat = -1;
2080
2081             for( i = 0; i < p_sys->i_es; i++ )
2082             {
2083                 if( i_cat == -1 )
2084                 {
2085                     if( es == p_sys->es[i] )
2086                     {
2087                         EsOutSelect( out, es, true );
2088                         break;
2089                     }
2090                 }
2091                 else
2092                 {
2093                     if( i_cat == UNKNOWN_ES || p_sys->es[i]->fmt.i_cat == i_cat )
2094                     {
2095                         if( EsIsSelected( p_sys->es[i] ) )
2096                         {
2097                             if( i_query == ES_OUT_RESTART_ES )
2098                             {
2099                                 if( p_sys->es[i]->p_dec )
2100                                 {
2101                                     EsDestroyDecoder( out, p_sys->es[i] );
2102                                     EsCreateDecoder( out, p_sys->es[i] );
2103                                 }
2104                             }
2105                             else
2106                             {
2107                                 EsUnselect( out, p_sys->es[i],
2108                                             p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
2109                             }
2110                         }
2111                     }
2112                 }
2113             }
2114             return VLC_SUCCESS;
2115         }
2116  
2117         case ES_OUT_SET_ES_DEFAULT:
2118         {
2119             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
2120
2121             if( es == NULL )
2122             {
2123                 /*p_sys->i_default_video_id = -1;*/
2124                 /*p_sys->i_default_audio_id = -1;*/
2125                 p_sys->i_default_sub_id = -1;
2126             }
2127             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
2128             {
2129                 /*p_sys->i_default_video_id = -1;*/
2130             }
2131             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
2132             {
2133                 /*p_sys->i_default_audio_id = -1;*/
2134             }
2135             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
2136             {
2137                 p_sys->i_default_sub_id = -1;
2138             }
2139             else
2140             {
2141                 /*if( es->fmt.i_cat == VIDEO_ES )
2142                     p_sys->i_default_video_id = es->i_id;
2143                 else
2144                 if( es->fmt.i_cat == AUDIO_ES )
2145                     p_sys->i_default_audio_id = es->i_id;
2146                 else*/
2147                 if( es->fmt.i_cat == SPU_ES )
2148                     p_sys->i_default_sub_id = es->i_id;
2149             }
2150             return VLC_SUCCESS;
2151         }
2152
2153         case ES_OUT_SET_PCR:
2154         case ES_OUT_SET_GROUP_PCR:
2155         {
2156             es_out_pgrm_t *p_pgrm = NULL;
2157             int            i_group = 0;
2158             int64_t        i_pcr;
2159
2160             if( i_query == ES_OUT_SET_PCR )
2161             {
2162                 p_pgrm = p_sys->p_pgrm;
2163             }
2164             else
2165             {
2166                 int i;
2167                 i_group = (int)va_arg( args, int );
2168                 for( i = 0; i < p_sys->i_pgrm; i++ )
2169                 {
2170                     if( p_sys->pgrm[i]->i_id == i_group )
2171                     {
2172                         p_pgrm = p_sys->pgrm[i];
2173                         break;
2174                     }
2175                 }
2176             }
2177             if( p_pgrm == NULL )
2178                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
2179
2180             i_pcr = (int64_t)va_arg( args, int64_t );
2181             /* search program
2182              * TODO do not use mdate() but proper stream acquisition date */
2183             input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
2184                                 p_sys->p_input->b_can_pace_control || p_sys->b_buffering, i_pcr, mdate() );
2185             /* Check buffering state on master clock update */
2186             if( p_sys->b_buffering && p_pgrm == p_sys->p_pgrm )
2187                 EsOutDecodersStopBuffering( out, false );
2188
2189             return VLC_SUCCESS;
2190         }
2191
2192         case ES_OUT_RESET_PCR:
2193             msg_Err( p_sys->p_input, "ES_OUT_RESET_PCR called" );
2194             EsOutChangePosition( out );
2195             return VLC_SUCCESS;
2196
2197         case ES_OUT_SET_GROUP:
2198         {
2199             int j;
2200             i = (int) va_arg( args, int );
2201             for( j = 0; j < p_sys->i_pgrm; j++ )
2202             {
2203                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
2204                 if( p_pgrm->i_id == i )
2205                 {
2206                     EsOutProgramSelect( out, p_pgrm );
2207                     return VLC_SUCCESS;
2208                 }
2209             }
2210             return VLC_EGENERIC;
2211         }
2212
2213         case ES_OUT_SET_ES_FMT:
2214         {
2215             /* This ain't pretty but is need by some demuxers (eg. Ogg )
2216              * to update the p_extra data */
2217             es_format_t *p_fmt;
2218             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
2219             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
2220             if( es == NULL )
2221                 return VLC_EGENERIC;
2222
2223             if( p_fmt->i_extra )
2224             {
2225                 es->fmt.i_extra = p_fmt->i_extra;
2226                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
2227                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
2228
2229                 if( !es->p_dec )
2230                     return VLC_SUCCESS;
2231 #if 1
2232                 EsDestroyDecoder( out, es );
2233
2234                 EsCreateDecoder( out, es );
2235 #else
2236                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
2237                 es->p_dec->fmt_in.p_extra =
2238                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
2239                 memcpy( es->p_dec->fmt_in.p_extra,
2240                         p_fmt->p_extra, p_fmt->i_extra );
2241 #endif
2242             }
2243
2244             return VLC_SUCCESS;
2245         }
2246
2247         case ES_OUT_SET_NEXT_DISPLAY_TIME:
2248         {
2249             const int64_t i_date = (int64_t)va_arg( args, int64_t );
2250
2251             if( i_date < 0 )
2252                 return VLC_EGENERIC;
2253
2254             p_sys->i_preroll_end = i_date;
2255
2256             return VLC_SUCCESS;
2257         }
2258         case ES_OUT_SET_GROUP_META:
2259         {
2260             int i_group = (int)va_arg( args, int );
2261             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
2262
2263             EsOutProgramMeta( out, i_group, p_meta );
2264             return VLC_SUCCESS;
2265         }
2266         case ES_OUT_SET_GROUP_EPG:
2267         {
2268             int i_group = (int)va_arg( args, int );
2269             vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
2270
2271             EsOutProgramEpg( out, i_group, p_epg );
2272             return VLC_SUCCESS;
2273         }
2274         case ES_OUT_DEL_GROUP:
2275         {
2276             int i_group = (int)va_arg( args, int );
2277
2278             return EsOutProgramDel( out, i_group );
2279         }
2280
2281         case ES_OUT_GET_WAKE_UP:
2282         {
2283             mtime_t *pi_wakeup = (mtime_t*)va_arg( args, mtime_t* );
2284             *pi_wakeup = EsOutGetWakeup( out );
2285             return VLC_SUCCESS;
2286         }
2287
2288         case ES_OUT_SET_ES_BY_ID:
2289         case ES_OUT_RESTART_ES_BY_ID:
2290         case ES_OUT_SET_ES_DEFAULT_BY_ID:
2291         {
2292             const int i_id = (int)va_arg( args, int );
2293             es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2294             int i_new_query;
2295
2296             switch( i_query )
2297             {
2298             case ES_OUT_SET_ES_BY_ID:         i_new_query = ES_OUT_SET_ES; break;
2299             case ES_OUT_RESTART_ES_BY_ID:     i_new_query = ES_OUT_RESTART_ES; break;
2300             case ES_OUT_SET_ES_DEFAULT_BY_ID: i_new_query = ES_OUT_SET_ES_DEFAULT; break;
2301             default:
2302               assert(0);
2303             }
2304             /* TODO if the lock is made non recursive it should be changed */
2305             int i_ret = es_out_Control( out, i_new_query, p_es );
2306
2307             /* Clean up vout after user action (in active mode only).
2308              * FIXME it does not work well with multiple video windows */
2309             if( p_sys->b_active )
2310                 input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
2311             return i_ret;
2312         }
2313
2314         case ES_OUT_GET_BUFFERING:
2315             pb = (bool *)va_arg( args, bool* );
2316             *pb = p_sys->b_buffering;
2317             return VLC_SUCCESS;
2318
2319         case ES_OUT_GET_EMPTY:
2320             pb = (bool *)va_arg( args, bool* );
2321             *pb = EsOutDecodersIsEmpty( out );
2322             return VLC_SUCCESS;
2323
2324         case ES_OUT_SET_DELAY:
2325         {
2326             const int i_cat = (int)va_arg( args, int );
2327             const mtime_t i_delay = (mtime_t)va_arg( args, mtime_t );
2328             EsOutSetDelay( out, i_cat, i_delay );
2329             return VLC_SUCCESS;
2330         }
2331
2332         case ES_OUT_SET_RECORD_STATE:
2333             b = (bool) va_arg( args, int );
2334             return EsOutSetRecord( out, b );
2335
2336         case ES_OUT_SET_PAUSE_STATE:
2337         {
2338             const bool b_source_paused = (bool)va_arg( args, int );
2339             const bool b_paused = (bool)va_arg( args, int );
2340             const mtime_t i_date = (mtime_t) va_arg( args, mtime_t );
2341
2342             assert( !b_source_paused == !b_paused );
2343             EsOutChangePause( out, b_paused, i_date );
2344
2345             return VLC_SUCCESS;
2346         }
2347
2348         case ES_OUT_SET_RATE:
2349         {
2350             const int i_src_rate = (int)va_arg( args, int );
2351             const int i_rate = (int)va_arg( args, int );
2352
2353             assert( i_src_rate == i_rate );
2354             EsOutChangeRate( out, i_rate );
2355
2356             return VLC_SUCCESS;
2357         }
2358
2359         case ES_OUT_SET_TIME:
2360         {
2361             const mtime_t i_date = (mtime_t)va_arg( args, mtime_t );
2362
2363             assert( i_date == -1 );
2364             EsOutChangePosition( out );
2365
2366             return VLC_SUCCESS;
2367         }
2368
2369         case ES_OUT_SET_FRAME_NEXT:
2370             EsOutFrameNext( out );
2371             return VLC_SUCCESS;
2372
2373         case ES_OUT_SET_TIMES:
2374         {
2375             double f_position = (double)va_arg( args, double );
2376             mtime_t i_time = (mtime_t)va_arg( args, mtime_t );
2377             mtime_t i_length = (mtime_t)va_arg( args, mtime_t );
2378
2379             /* Fix for buffering delay */
2380             const mtime_t i_delay = EsOutGetBuffering( out );
2381
2382             i_time -= i_delay;
2383             if( i_time < 0 )
2384                 i_time = 0;
2385
2386             if( i_length > 0 )
2387                 f_position -= (double)i_delay / i_length;
2388             if( f_position < 0 )
2389                 f_position = 0;
2390
2391             if( !p_sys->b_buffering )
2392                 input_SendEventTimes( p_sys->p_input, f_position, i_time, i_length );
2393             return VLC_SUCCESS;
2394         }
2395
2396         default:
2397             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
2398             return VLC_EGENERIC;
2399     }
2400 }
2401 static int EsOutControl( es_out_t *out, int i_query, va_list args )
2402 {
2403     es_out_sys_t *p_sys = out->p_sys;
2404     int i_ret;
2405
2406     vlc_mutex_lock( &p_sys->lock );
2407     i_ret = EsOutControlLocked( out, i_query, args );
2408     vlc_mutex_unlock( &p_sys->lock );
2409
2410     return i_ret;
2411 }
2412
2413 /****************************************************************************
2414  * LanguageGetName: try to expend iso639 into plain name
2415  ****************************************************************************/
2416 static char *LanguageGetName( const char *psz_code )
2417 {
2418     const iso639_lang_t *pl;
2419
2420     if( psz_code == NULL )
2421     {
2422         return strdup( "" );
2423     }
2424
2425     if( strlen( psz_code ) == 2 )
2426     {
2427         pl = GetLang_1( psz_code );
2428     }
2429     else if( strlen( psz_code ) == 3 )
2430     {
2431         pl = GetLang_2B( psz_code );
2432         if( !strcmp( pl->psz_iso639_1, "??" ) )
2433         {
2434             pl = GetLang_2T( psz_code );
2435         }
2436     }
2437     else
2438     {
2439         return strdup( psz_code );
2440     }
2441
2442     if( !strcmp( pl->psz_iso639_1, "??" ) )
2443     {
2444        return strdup( psz_code );
2445     }
2446     else
2447     {
2448         if( *pl->psz_native_name )
2449         {
2450             return strdup( pl->psz_native_name );
2451         }
2452         return strdup( pl->psz_eng_name );
2453     }
2454 }
2455
2456 /* Get a 2 char code */
2457 static char *LanguageGetCode( const char *psz_lang )
2458 {
2459     const iso639_lang_t *pl;
2460
2461     if( psz_lang == NULL || *psz_lang == '\0' )
2462         return strdup("??");
2463
2464     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
2465     {
2466         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
2467             !strcasecmp( pl->psz_native_name, psz_lang ) ||
2468             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
2469             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
2470             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
2471             break;
2472     }
2473
2474     if( pl->psz_iso639_1 != NULL )
2475         return strdup( pl->psz_iso639_1 );
2476
2477     return strdup("??");
2478 }
2479
2480 static char **LanguageSplit( const char *psz_langs )
2481 {
2482     char *psz_dup;
2483     char *psz_parser;
2484     char **ppsz = NULL;
2485     int i_psz = 0;
2486
2487     if( psz_langs == NULL ) return NULL;
2488
2489     psz_parser = psz_dup = strdup(psz_langs);
2490
2491     while( psz_parser && *psz_parser )
2492     {
2493         char *psz;
2494         char *psz_code;
2495
2496         psz = strchr(psz_parser, ',' );
2497         if( psz ) *psz++ = '\0';
2498
2499         if( !strcmp( psz_parser, "any" ) )
2500         {
2501             TAB_APPEND( i_psz, ppsz, strdup("any") );
2502         }
2503         else
2504         {
2505             psz_code = LanguageGetCode( psz_parser );
2506             if( strcmp( psz_code, "??" ) )
2507             {
2508                 TAB_APPEND( i_psz, ppsz, psz_code );
2509             }
2510             else
2511             {
2512                 free( psz_code );
2513             }
2514         }
2515
2516         psz_parser = psz;
2517     }
2518
2519     if( i_psz )
2520     {
2521         TAB_APPEND( i_psz, ppsz, NULL );
2522     }
2523
2524     free( psz_dup );
2525     return ppsz;
2526 }
2527
2528 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
2529 {
2530     int i;
2531
2532     if( !ppsz_langs || !psz_lang ) return -1;
2533
2534     for( i = 0; ppsz_langs[i]; i++ )
2535     {
2536         if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2537             !strcasecmp( ppsz_langs[i], "any" ) )
2538         {
2539             return i;
2540         }
2541     }
2542
2543     return -1;
2544 }
2545
2546 /****************************************************************************
2547  * EsOutUpdateInfo:
2548  * - add meta info to the playlist item
2549  ****************************************************************************/
2550 static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt, const vlc_meta_t *p_meta )
2551 {
2552     es_out_sys_t   *p_sys = out->p_sys;
2553     input_thread_t *p_input = p_sys->p_input;
2554     const es_format_t *p_fmt_es = &es->fmt;
2555     char           *psz_cat;
2556     lldiv_t         div;
2557
2558     /* Create category name */
2559     if( asprintf( &psz_cat, _("Stream %d"), es->i_meta_id ) == -1 )
2560         return;
2561
2562     /* Remove previous information */
2563     input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
2564
2565     /* Add informations */
2566     const char *psz_type;
2567     switch( fmt->i_cat )
2568     {
2569     case AUDIO_ES:
2570         psz_type = _("Audio");
2571         break;
2572     case VIDEO_ES:
2573         psz_type = _("Video");
2574         break;
2575     case SPU_ES:
2576         psz_type = _("Subtitle");
2577         break;
2578     default:
2579         psz_type = NULL;
2580         break;
2581     }
2582
2583     if( psz_type )
2584         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Type"), psz_type );
2585
2586     if( es->i_meta_id != es->i_id )
2587         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Original ID"),
2588                        "%d", es->i_id );
2589
2590     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
2591                    "%.4s", (char*)&p_fmt_es->i_codec );
2592
2593     if( es->psz_language && *es->psz_language )
2594         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
2595                        "%s", es->psz_language );
2596     if( fmt->psz_description && *fmt->psz_description )
2597         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Description"),
2598                        "%s", fmt->psz_description );
2599
2600     switch( fmt->i_cat )
2601     {
2602     case AUDIO_ES:
2603         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2604                        _("Type"), _("Audio") );
2605
2606         if( fmt->audio.i_physical_channels & AOUT_CHAN_PHYSMASK )
2607             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
2608                            "%s", aout_FormatPrintChannels( &fmt->audio ) );
2609         else if( fmt->audio.i_channels > 0 )
2610             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
2611                            "%u", fmt->audio.i_channels );
2612
2613         if( fmt->audio.i_rate > 0 )
2614         {
2615             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
2616                            _("%u Hz"), fmt->audio.i_rate );
2617             /* FIXME that should be removed or improved ! (used by text/strings.c) */
2618             var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
2619         }
2620
2621         unsigned int i_bitspersample = fmt->audio.i_bitspersample;
2622         if( i_bitspersample <= 0 )
2623             i_bitspersample = aout_BitsPerSample( p_fmt_es->i_codec );
2624         if( i_bitspersample > 0 )
2625             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2626                            _("Bits per sample"), "%u",
2627                            i_bitspersample );
2628
2629         if( fmt->i_bitrate > 0 )
2630         {
2631             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
2632                            _("%u kb/s"), fmt->i_bitrate / 1000 );
2633             /* FIXME that should be removed or improved ! (used by text/strings.c) */
2634             var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
2635         }
2636         for( int i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
2637         {
2638             const audio_replay_gain_t *p_rg = &fmt->audio_replay_gain;
2639             if( !p_rg->pb_gain[i] )
2640                 continue;
2641             const char *psz_name;
2642             if( i == AUDIO_REPLAY_GAIN_TRACK )
2643                 psz_name = _("Track replay gain");
2644             else
2645                 psz_name = _("Album replay gain");
2646             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2647                            psz_name, _("%.2f dB"), p_rg->pf_gain[i] );
2648         }
2649         break;
2650
2651     case VIDEO_ES:
2652         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2653                        _("Type"), _("Video") );
2654
2655         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
2656             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2657                            _("Resolution"), "%ux%u",
2658                            fmt->video.i_width, fmt->video.i_height );
2659
2660         if( fmt->video.i_visible_width > 0 &&
2661             fmt->video.i_visible_height > 0 )
2662             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2663                            _("Display resolution"), "%ux%u",
2664                            fmt->video.i_visible_width,
2665                            fmt->video.i_visible_height);
2666        if( fmt->video.i_frame_rate > 0 &&
2667            fmt->video.i_frame_rate_base > 0 )
2668        {
2669            div = lldiv( (float)fmt->video.i_frame_rate /
2670                                fmt->video.i_frame_rate_base * 1000000,
2671                                1000000 );
2672            if( div.rem > 0 )
2673                input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2674                               _("Frame rate"), "%"PRId64".%06u",
2675                               div.quot, (unsigned int )div.rem );
2676            else
2677                input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2678                               _("Frame rate"), "%"PRId64, div.quot );
2679        }
2680        break;
2681
2682     case SPU_ES:
2683         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2684                        _("Type"), _("Subtitle") );
2685         break;
2686
2687     default:
2688         break;
2689     }
2690
2691     /* Append generic meta */
2692     if( p_meta )
2693     {
2694         char **ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
2695         for( int i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
2696         {
2697             char *psz_key = ppsz_all_keys[i];
2698             char *psz_value = vlc_dictionary_value_for_key( &p_meta->extra_tags, psz_key );
2699
2700             if( psz_value )
2701                 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(psz_key), _(psz_value) );
2702             free( psz_key );
2703         }
2704         free( ppsz_all_keys );
2705     }
2706
2707     free( psz_cat );
2708 }