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