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