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