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