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