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