]> git.sesse.net Git - vlc/blob - src/input/es_out.c
* Do not take and release the structure lock for each element of the list while
[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 #include <vlc/vlc.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include <vlc_input.h>
34 #include <vlc_es_out.h>
35 #include <vlc_block.h>
36
37 #include "input_internal.h"
38
39 #include "vlc_playlist.h"
40 #include "iso_lang.h"
41 /* FIXME we should find a better way than including that */
42 #include "../text/iso-639_def.h"
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 typedef struct
48 {
49     /* Program ID */
50     int i_id;
51
52     /* Number of es for this pgrm */
53     int i_es;
54
55     vlc_bool_t b_selected;
56
57     /* Clock for this program */
58     input_clock_t clock;
59
60     char    *psz_now_playing;
61
62 } es_out_pgrm_t;
63
64 struct es_out_id_t
65 {
66     /* ES ID */
67     int       i_id;
68     es_out_pgrm_t *p_pgrm;
69
70     /* Signal a discontinuity in the timeline for every PID */
71     vlc_bool_t b_discontinuity;
72
73     /* Misc. */
74     int64_t i_preroll_end;
75
76     /* Channel in the track type */
77     int         i_channel;
78     es_format_t fmt;
79     char        *psz_language;
80     char        *psz_language_code;
81     decoder_t   *p_dec;
82 };
83
84 struct es_out_sys_t
85 {
86     input_thread_t *p_input;
87
88     /* all programs */
89     int           i_pgrm;
90     es_out_pgrm_t **pgrm;
91     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
92     es_out_pgrm_t *p_pgrm;  /* Master program */
93
94     /* all es */
95     int         i_id;
96     int         i_es;
97     es_out_id_t **es;
98
99     /* mode gestion */
100     vlc_bool_t  b_active;
101     int         i_mode;
102
103     /* es count */
104     int         i_audio;
105     int         i_video;
106     int         i_sub;
107
108     /* es to select */
109     int         i_audio_last, i_audio_id;
110     int         i_sub_last, i_sub_id;
111     char        **ppsz_audio_language;
112     char        **ppsz_sub_language;
113
114     /* current main es */
115     es_out_id_t *p_es_audio;
116     es_out_id_t *p_es_video;
117     es_out_id_t *p_es_sub;
118
119     /* delay */
120     int64_t i_audio_delay;
121     int64_t i_spu_delay;
122 };
123
124 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
125 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
126 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
127 static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
128 static int          EsOutControl( es_out_t *, int i_query, va_list );
129
130 static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
131
132 static void EsSelect( es_out_t *out, es_out_id_t *es );
133 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
134 static char *LanguageGetName( const char *psz_code );
135 static char *LanguageGetCode( const char *psz_lang );
136 static char **LanguageSplit( const char *psz_langs );
137 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
138
139 /*****************************************************************************
140  * input_EsOutNew:
141  *****************************************************************************/
142 es_out_t *input_EsOutNew( input_thread_t *p_input )
143 {
144     es_out_t     *out = malloc( sizeof( es_out_t ) );
145     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
146     vlc_value_t  val;
147     int i;
148
149     out->pf_add     = EsOutAdd;
150     out->pf_send    = EsOutSend;
151     out->pf_del     = EsOutDel;
152     out->pf_control = EsOutControl;
153     out->p_sys      = p_sys;
154
155     p_sys->p_input = p_input;
156
157     p_sys->b_active = VLC_FALSE;
158     p_sys->i_mode   = ES_OUT_MODE_AUTO;
159
160
161     p_sys->i_pgrm   = 0;
162     p_sys->pgrm     = NULL;
163     p_sys->p_pgrm   = NULL;
164
165     p_sys->i_id    = 0;
166     p_sys->i_es    = 0;
167     p_sys->es      = NULL;
168
169     p_sys->i_audio = 0;
170     p_sys->i_video = 0;
171     p_sys->i_sub   = 0;
172
173     /* */
174     var_Get( p_input, "audio-track", &val );
175     p_sys->i_audio_last = val.i_int;
176
177     var_Get( p_input, "sub-track", &val );
178     p_sys->i_sub_last = val.i_int;
179
180     if( !p_input->b_preparsing )
181     {
182         var_Get( p_input, "audio-language", &val );
183         p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
184         if( p_sys->ppsz_audio_language )
185         {
186             for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
187                 msg_Dbg( p_input, "selected audio language[%d] %s",
188                          i, p_sys->ppsz_audio_language[i] );
189         }
190         if( val.psz_string ) free( val.psz_string );
191
192         var_Get( p_input, "sub-language", &val );
193         p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
194         if( p_sys->ppsz_sub_language )
195         {
196             for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
197                 msg_Dbg( p_input, "selected subtitle language[%d] %s",
198                          i, p_sys->ppsz_sub_language[i] );
199         }
200         if( val.psz_string ) free( val.psz_string );
201     }
202     else
203     {
204         p_sys->ppsz_sub_language = NULL;
205         p_sys->ppsz_audio_language = NULL;
206     }
207
208     var_Get( p_input, "audio-track-id", &val );
209     p_sys->i_audio_id = val.i_int;
210
211     var_Get( p_input, "sub-track-id", &val );
212     p_sys->i_sub_id = val.i_int;
213
214     p_sys->p_es_audio = NULL;
215     p_sys->p_es_video = NULL;
216     p_sys->p_es_sub   = NULL;
217
218     p_sys->i_audio_delay= 0;
219     p_sys->i_spu_delay  = 0;
220
221     return out;
222 }
223
224 /*****************************************************************************
225  * input_EsOutDelete:
226  *****************************************************************************/
227 void input_EsOutDelete( es_out_t *out )
228 {
229     es_out_sys_t *p_sys = out->p_sys;
230     int i;
231
232     for( i = 0; i < p_sys->i_es; i++ )
233     {
234         if( p_sys->es[i]->p_dec )
235         {
236             input_DecoderDelete( p_sys->es[i]->p_dec );
237         }
238         if( p_sys->es[i]->psz_language )
239             free( p_sys->es[i]->psz_language );
240         if( p_sys->es[i]->psz_language_code )
241             free( p_sys->es[i]->psz_language_code );
242         es_format_Clean( &p_sys->es[i]->fmt );
243
244         free( p_sys->es[i] );
245     }
246     if( p_sys->ppsz_audio_language )
247     {
248         for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
249             free( p_sys->ppsz_audio_language[i] );
250         free( p_sys->ppsz_audio_language );
251     }
252     if( p_sys->ppsz_sub_language )
253     {
254         for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
255             free( p_sys->ppsz_sub_language[i] );
256         free( p_sys->ppsz_sub_language );
257     }
258
259     if( p_sys->es )
260         free( p_sys->es );
261
262     for( i = 0; i < p_sys->i_pgrm; i++ )
263     {
264         if( p_sys->pgrm[i]->psz_now_playing )
265             free( p_sys->pgrm[i]->psz_now_playing );
266         free( p_sys->pgrm[i] );
267     }
268     if( p_sys->pgrm )
269         free( p_sys->pgrm );
270
271     free( p_sys );
272     free( out );
273 }
274
275 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
276 {
277     int i;
278     if( i_id < 0 )
279     {
280         /* Special HACK, -i_id is tha cat of the stream */
281         return (es_out_id_t*)((uint8_t*)NULL-i_id);
282     }
283
284     for( i = 0; i < out->p_sys->i_es; i++ )
285     {
286         if( out->p_sys->es[i]->i_id == i_id )
287             return out->p_sys->es[i];
288     }
289     return NULL;
290 }
291
292 void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
293 {
294     es_out_sys_t      *p_sys = out->p_sys;
295     int i;
296
297     for( i = 0; i < p_sys->i_es; i++ )
298     {
299         es_out_id_t *es = p_sys->es[i];
300         es->b_discontinuity = VLC_TRUE; /* signal discontinuity */
301
302         /* Send a dummy block to let decoder know that
303          * there is a discontinuity */
304         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
305         {
306             input_DecoderDiscontinuity( es->p_dec );
307         }
308     }
309 }
310
311 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
312 {
313     es_out_sys_t *p_sys = out->p_sys;
314
315     if( i_cat == AUDIO_ES )
316         p_sys->i_audio_delay = i_delay;
317     else if( i_cat == SPU_ES )
318         p_sys->i_spu_delay = i_delay;
319 }
320
321 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
322 {
323     es_out_sys_t      *p_sys = out->p_sys;
324     int i;
325
326     for( i = 0; i < p_sys->i_es; i++ )
327     {
328         es_out_id_t *es = p_sys->es[i];
329
330         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
331             return VLC_FALSE;
332     }
333     return VLC_TRUE;
334 }
335
336 /*****************************************************************************
337  *
338  *****************************************************************************/
339 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
340                               vlc_bool_t b_delete )
341 {
342     es_out_sys_t      *p_sys = out->p_sys;
343     input_thread_t    *p_input = p_sys->p_input;
344     vlc_value_t       val, text;
345
346     const char *psz_var;
347
348     if( es->fmt.i_cat == AUDIO_ES )
349         psz_var = "audio-es";
350     else if( es->fmt.i_cat == VIDEO_ES )
351         psz_var = "video-es";
352     else if( es->fmt.i_cat == SPU_ES )
353         psz_var = "spu-es";
354     else
355         return;
356
357     if( b_delete )
358     {
359         val.i_int = es->i_id;
360         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
361         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
362         return;
363     }
364
365     /* Get the number of ES already added */
366     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
367     if( val.i_int == 0 )
368     {
369         vlc_value_t val2;
370
371         /* First one, we need to add the "Disable" choice */
372         val2.i_int = -1; text.psz_string = _("Disable");
373         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
374         val.i_int++;
375     }
376
377     /* Take care of the ES description */
378     if( es->fmt.psz_description && *es->fmt.psz_description )
379     {
380         if( es->psz_language && *es->psz_language )
381         {
382             text.psz_string = malloc( strlen( es->fmt.psz_description) +
383                                       strlen( es->psz_language ) + 10 );
384             sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description,
385                                                    es->psz_language );
386         }
387         else text.psz_string = strdup( es->fmt.psz_description );
388     }
389     else
390     {
391         if( es->psz_language && *es->psz_language )
392         {
393             char *temp;
394             text.psz_string = malloc( strlen( _("Track %i") )+
395                                       strlen( es->psz_language ) + 30 );
396             asprintf( &temp,  _("Track %i"), val.i_int );
397             sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
398             free( temp );
399         }
400         else
401         {
402             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
403             sprintf( text.psz_string, _("Track %i"), val.i_int );
404         }
405     }
406
407     val.i_int = es->i_id;
408     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
409
410     free( text.psz_string );
411
412     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
413 }
414
415 /* EsOutProgramSelect:
416  *  Select a program and update the object variable
417  */
418 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
419 {
420     es_out_sys_t      *p_sys = out->p_sys;
421     input_thread_t    *p_input = p_sys->p_input;
422     vlc_value_t       val;
423     int               i;
424
425     if( p_sys->p_pgrm == p_pgrm )
426         return; /* Nothing to do */
427
428     if( p_sys->p_pgrm )
429     {
430         es_out_pgrm_t *old = p_sys->p_pgrm;
431         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
432
433         for( i = 0; i < p_sys->i_es; i++ )
434         {
435             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
436                 p_sys->i_mode != ES_OUT_MODE_ALL )
437                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
438         }
439
440         p_sys->p_es_audio = NULL;
441         p_sys->p_es_sub = NULL;
442         p_sys->p_es_video = NULL;
443     }
444
445     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
446
447     /* Mark it selected */
448     p_pgrm->b_selected = VLC_TRUE;
449
450     /* Switch master stream */
451     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
452     {
453         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
454     }
455     p_pgrm->clock.b_master = VLC_TRUE;
456     p_sys->p_pgrm = p_pgrm;
457
458     /* Update "program" */
459     val.i_int = p_pgrm->i_id;
460     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
461
462     /* Update "es-*" */
463     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
464     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
465     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
466     for( i = 0; i < p_sys->i_es; i++ )
467     {
468         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
469             EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
470         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
471     }
472
473     /* Update now playing if defined per program */
474     if( p_pgrm->psz_now_playing )
475     {
476         char *psz_cat = malloc( strlen(_("Program")) + 10 );
477
478         sprintf( psz_cat, "%s %d", _("Program"), p_pgrm->i_id );
479         input_Control( p_input, INPUT_ADD_INFO, _(VLC_META_INFO_CAT),
480                        _(VLC_META_NOW_PLAYING), "%s", p_pgrm->psz_now_playing );
481         free( psz_cat );
482     }
483
484
485     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
486 }
487
488 /* EsOutAddProgram:
489  *  Add a program
490  */
491 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
492 {
493     es_out_sys_t      *p_sys = out->p_sys;
494     input_thread_t    *p_input = p_sys->p_input;
495     vlc_value_t       val;
496
497     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
498
499     /* Init */
500     p_pgrm->i_id = i_group;
501     p_pgrm->i_es = 0;
502     p_pgrm->b_selected = VLC_FALSE;
503     p_pgrm->psz_now_playing = NULL;
504     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average );
505
506     /* Append it */
507     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
508
509     /* Update "program" variable */
510     val.i_int = i_group;
511     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
512
513     if( i_group == var_GetInteger( p_input, "program" ) )
514     {
515         EsOutProgramSelect( out, p_pgrm );
516     }
517     else
518     {
519         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
520     }
521     return p_pgrm;
522 }
523
524 /* EsOutDelProgram:
525  *  Delete a program
526  */
527 static int EsOutProgramDel( es_out_t *out, int i_group )
528 {
529     es_out_sys_t      *p_sys = out->p_sys;
530     input_thread_t    *p_input = p_sys->p_input;
531     es_out_pgrm_t     *p_pgrm = NULL;
532     vlc_value_t       val;
533     int               i;
534
535     for( i = 0; i < p_sys->i_pgrm; i++ )
536     {
537         if( p_sys->pgrm[i]->i_id == i_group )
538         {
539             p_pgrm = p_sys->pgrm[i];
540             break;
541         }
542     }
543
544     if( p_pgrm == NULL )
545         return VLC_EGENERIC;
546
547     if( p_pgrm->i_es )
548     {
549         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
550                  i_group, p_pgrm->i_es );
551         return VLC_EGENERIC;
552     }
553
554     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
555
556     /* If program is selected we need to unselect it */
557     if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = 0;
558
559     if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
560     free( p_pgrm );
561
562     /* Update "program" variable */
563     val.i_int = i_group;
564     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
565
566     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
567
568     return VLC_SUCCESS;
569 }
570
571 /* EsOutProgramMeta:
572  */
573 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
574 {
575     es_out_sys_t      *p_sys = out->p_sys;
576     es_out_pgrm_t     *p_pgrm = NULL;
577     input_thread_t    *p_input = p_sys->p_input;
578     char              *psz_cat = malloc( strlen(_("Program")) + 10 );
579     char              *psz_title = NULL;
580     char              *psz_now_playing = NULL;
581     char              *psz_provider = NULL;
582     int i;
583
584     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
585     sprintf( psz_cat, "%s %d", _("Program"), i_group );
586
587     if( p_meta->psz_title ) psz_title = p_meta->psz_title;
588     if( p_meta->psz_publisher ) psz_provider = p_meta->psz_publisher;
589     if( p_meta->psz_nowplaying ) psz_now_playing = p_meta->psz_nowplaying;
590
591     if( !psz_title && !psz_now_playing )
592     {
593         free( psz_cat );
594         return;
595     }
596
597     for( i = 0; i < p_sys->i_pgrm; i++ )
598     {
599         if( p_sys->pgrm[i]->i_id == i_group )
600         {
601             p_pgrm = p_sys->pgrm[i];
602             break;
603         }
604     }
605
606     if( p_pgrm == NULL ) {
607         free( psz_cat );
608         msg_Dbg( p_input, "Trying to add meta for non-existing program" );
609         return;
610     }
611
612     /* Update the description text of the program */
613     if( psz_title && *psz_title )
614     {
615         vlc_value_t val;
616         vlc_value_t text;
617
618         /* ugly but it works */
619         val.i_int = i_group;
620         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
621
622         if( psz_provider && *psz_provider )
623         {
624             asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider );
625             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
626             free( text.psz_string );
627         }
628         else
629         {
630             text.psz_string = psz_title;
631             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
632         }
633     }
634     if( psz_now_playing )
635     {
636         if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
637         p_pgrm->psz_now_playing = strdup(psz_now_playing);
638
639         if( p_sys->p_pgrm == p_pgrm )
640         {
641             vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta,
642                                     psz_now_playing );
643         }
644     }
645     free( psz_cat );
646 }
647
648 /* EsOutAdd:
649  *  Add an es_out
650  */
651 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
652 {
653     es_out_sys_t      *p_sys = out->p_sys;
654     input_thread_t    *p_input = p_sys->p_input;
655
656     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
657     es_out_pgrm_t     *p_pgrm = NULL;
658     int i;
659
660     if( fmt->i_group < 0 )
661     {
662         msg_Err( p_input, "invalid group number" );
663         return NULL;
664     }
665
666     /* Search the program */
667     for( i = 0; i < p_sys->i_pgrm; i++ )
668     {
669         if( fmt->i_group == p_sys->pgrm[i]->i_id )
670         {
671             p_pgrm = p_sys->pgrm[i];
672             break;
673         }
674     }
675     if( p_pgrm == NULL )
676     {
677         /* Create a new one */
678         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
679     }
680
681     /* Increase ref count for program */
682     p_pgrm->i_es++;
683
684     /* Set up ES */
685     if( fmt->i_id < 0 )
686         fmt->i_id = out->p_sys->i_id;
687     es->i_id = fmt->i_id;
688     es->p_pgrm = p_pgrm;
689     es_format_Copy( &es->fmt, fmt );
690     es->i_preroll_end = -1;
691     es->b_discontinuity = VLC_FALSE;
692
693     switch( fmt->i_cat )
694     {
695     case AUDIO_ES:
696         es->i_channel = p_sys->i_audio;
697         break;
698
699     case VIDEO_ES:
700         es->i_channel = p_sys->i_video;
701         if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
702             vlc_ureduce( &es->fmt.video.i_frame_rate,
703                          &es->fmt.video.i_frame_rate_base,
704                          fmt->video.i_frame_rate,
705                          fmt->video.i_frame_rate_base, 0 );
706         break;
707
708     case SPU_ES:
709         es->i_channel = p_sys->i_sub;
710         break;
711
712     default:
713         es->i_channel = 0;
714         break;
715     }
716     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
717     es->psz_language_code = LanguageGetCode( fmt->psz_language );
718     es->p_dec = NULL;
719
720     if( es->p_pgrm == p_sys->p_pgrm )
721         EsOutESVarUpdate( out, es, VLC_FALSE );
722
723     /* Select it if needed */
724     EsOutSelect( out, es, VLC_FALSE );
725
726
727     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
728     p_sys->i_id++;  /* always incremented */
729     switch( fmt->i_cat )
730     {
731         case AUDIO_ES:
732             p_sys->i_audio++;
733             break;
734         case SPU_ES:
735             p_sys->i_sub++;
736             break;
737         case VIDEO_ES:
738             p_sys->i_video++;
739             break;
740     }
741
742     EsOutAddInfo( out, es );
743
744     return es;
745 }
746
747 static void EsSelect( es_out_t *out, es_out_id_t *es )
748 {
749     es_out_sys_t   *p_sys = out->p_sys;
750     input_thread_t *p_input = p_sys->p_input;
751     vlc_value_t    val;
752     const char     *psz_var;
753
754     if( es->p_dec )
755     {
756         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
757         return;
758     }
759
760     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
761     {
762         if( !var_GetBool( p_input, "video" ) ||
763             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
764         {
765             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
766                      es->i_id );
767             return;
768         }
769     }
770     else if( es->fmt.i_cat == AUDIO_ES )
771     {
772         var_Get( p_input, "audio", &val );
773         if( !var_GetBool( p_input, "audio" ) ||
774             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
775         {
776             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
777                      es->i_id );
778             return;
779         }
780     }
781     if( es->fmt.i_cat == SPU_ES )
782     {
783         var_Get( p_input, "spu", &val );
784         if( !var_GetBool( p_input, "spu" ) ||
785             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) )
786         {
787             msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
788                      es->i_id );
789             return;
790         }
791     }
792
793     es->i_preroll_end = -1;
794     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
795     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
796         return;
797
798     if( es->fmt.i_cat == VIDEO_ES )
799         psz_var = "video-es";
800     else if( es->fmt.i_cat == AUDIO_ES )
801         psz_var = "audio-es";
802     else if( es->fmt.i_cat == SPU_ES )
803         psz_var = "spu-es";
804     else
805         return;
806
807     /* Mark it as selected */
808     val.i_int = es->i_id;
809     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
810
811
812     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
813 }
814
815 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
816 {
817     es_out_sys_t   *p_sys = out->p_sys;
818     input_thread_t *p_input = p_sys->p_input;
819     vlc_value_t    val;
820     const char     *psz_var;
821
822     if( es->p_dec == NULL )
823     {
824         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
825         return;
826     }
827
828     input_DecoderDelete( es->p_dec );
829     es->p_dec = NULL;
830
831     if( !b_update )
832         return;
833
834     /* Update var */
835     if( es->p_dec == NULL )
836         return;
837     if( es->fmt.i_cat == VIDEO_ES )
838         psz_var = "video-es";
839     else if( es->fmt.i_cat == AUDIO_ES )
840         psz_var = "audio-es";
841     else if( es->fmt.i_cat == SPU_ES )
842         psz_var = "spu-es";
843     else
844         return;
845
846     /* Mark it as selected */
847     val.i_int = -1;
848     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
849
850     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
851 }
852
853 /**
854  * Select an ES given the current mode
855  * XXX: you need to take a the lock before (stream.stream_lock)
856  *
857  * \param out The es_out structure
858  * \param es es_out_id structure
859  * \param b_force ...
860  * \return nothing
861  */
862 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
863 {
864     es_out_sys_t      *p_sys = out->p_sys;
865
866     int i_cat = es->fmt.i_cat;
867
868     if( !p_sys->b_active ||
869         ( !b_force && es->fmt.i_priority < 0 ) )
870     {
871         return;
872     }
873
874     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
875     {
876         if( !es->p_dec )
877             EsSelect( out, es );
878     }
879     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
880     {
881         vlc_value_t val;
882         int i;
883         var_Get( p_sys->p_input, "programs", &val );
884         for ( i = 0; i < val.p_list->i_count; i++ )
885         {
886             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
887             {
888                 if( !es->p_dec )
889                     EsSelect( out, es );
890                 break;
891             }
892         }
893         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
894     }
895     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
896     {
897         int i_wanted  = -1;
898
899         if( es->p_pgrm != p_sys->p_pgrm )
900             return;
901
902         if( i_cat == AUDIO_ES )
903         {
904             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
905                                      es->psz_language_code );
906
907             if( p_sys->p_es_audio &&
908                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
909             {
910                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
911                                          p_sys->p_es_audio->psz_language_code );
912
913                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
914                     return;
915                 i_wanted = es->i_channel;
916             }
917             else
918             {
919                 /* Select audio if (no audio selected yet)
920                  * - no audio-language
921                  * - no audio code for the ES
922                  * - audio code in the requested list */
923                 if( idx1 >= 0 ||
924                     !strcmp( es->psz_language_code, "??" ) ||
925                     !p_sys->ppsz_audio_language )
926                     i_wanted = es->i_channel;
927             }
928
929             if( p_sys->i_audio_last >= 0 )
930                 i_wanted = p_sys->i_audio_last;
931
932             if( p_sys->i_audio_id >= 0 )
933             {
934                 if( es->i_id == p_sys->i_audio_id )
935                     i_wanted = es->i_channel;
936                 else
937                     return;
938             }
939         }
940         else if( i_cat == SPU_ES )
941         {
942             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
943                                      es->psz_language_code );
944
945             if( p_sys->p_es_sub &&
946                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
947             {
948                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
949                                          p_sys->p_es_sub->psz_language_code );
950
951                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
952                         idx1, es->psz_language_code, idx2,
953                         p_sys->p_es_sub->psz_language_code );
954
955                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
956                     return;
957                 /* We found a SPU that matches our language request */
958                 i_wanted  = es->i_channel;
959             }
960             else if( idx1 >= 0 )
961             {
962                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
963                         idx1, es->psz_language_code );
964
965                 i_wanted  = es->i_channel;
966             }
967             if( p_sys->i_sub_last >= 0 )
968                 i_wanted  = p_sys->i_sub_last;
969
970             if( p_sys->i_sub_id >= 0 )
971             {
972                 if( es->i_id == p_sys->i_sub_id )
973                     i_wanted = es->i_channel;
974                 else
975                     return;
976             }
977         }
978         else if( i_cat == VIDEO_ES )
979         {
980             i_wanted  = es->i_channel;
981         }
982
983         if( i_wanted == es->i_channel && es->p_dec == NULL )
984             EsSelect( out, es );
985     }
986
987     /* FIXME TODO handle priority here */
988     if( es->p_dec )
989     {
990         if( i_cat == AUDIO_ES )
991         {
992             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
993                 p_sys->p_es_audio &&
994                 p_sys->p_es_audio != es &&
995                 p_sys->p_es_audio->p_dec )
996             {
997                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
998             }
999             p_sys->p_es_audio = es;
1000         }
1001         else if( i_cat == SPU_ES )
1002         {
1003             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1004                 p_sys->p_es_sub &&
1005                 p_sys->p_es_sub != es &&
1006                 p_sys->p_es_sub->p_dec )
1007             {
1008                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
1009             }
1010             p_sys->p_es_sub = es;
1011         }
1012         else if( i_cat == VIDEO_ES )
1013         {
1014             p_sys->p_es_video = es;
1015         }
1016     }
1017 }
1018
1019 /**
1020  * Send a block for the given es_out
1021  *
1022  * \param out the es_out to send from
1023  * \param es the es_out_id
1024  * \param p_block the data block to send
1025  */
1026 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1027 {
1028     es_out_sys_t *p_sys = out->p_sys;
1029     input_thread_t    *p_input = p_sys->p_input;
1030     es_out_pgrm_t *p_pgrm = es->p_pgrm;
1031     int64_t i_delay;
1032     int i_total=0;
1033
1034     if( es->fmt.i_cat == AUDIO_ES )
1035         i_delay = p_sys->i_audio_delay;
1036     else if( es->fmt.i_cat == SPU_ES )
1037         i_delay = p_sys->i_spu_delay;
1038     else
1039         i_delay = 0;
1040
1041     if( p_input->p_libvlc->b_stats )
1042     {
1043         vlc_mutex_lock( &p_input->p->counters.counters_lock );
1044         stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1045                              p_block->i_buffer, &i_total );
1046         stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1047                            (float)i_total, NULL );
1048         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1049     }
1050
1051     /* Mark preroll blocks */
1052     if( es->i_preroll_end >= 0 )
1053     {
1054         int64_t i_date = p_block->i_pts;
1055         if( i_date <= 0 )
1056             i_date = p_block->i_dts;
1057
1058         if( i_date < es->i_preroll_end )
1059             p_block->i_flags |= BLOCK_FLAG_PREROLL;
1060         else
1061             es->i_preroll_end = -1;
1062     }
1063
1064     /* +11 -> avoid null value with non null dts/pts */
1065     if( p_block->i_dts > 0 )
1066     {
1067         p_block->i_dts =
1068             input_ClockGetTS( p_input, &p_pgrm->clock,
1069                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
1070     }
1071     if( p_block->i_pts > 0 )
1072     {
1073         p_block->i_pts =
1074             input_ClockGetTS( p_input, &p_pgrm->clock,
1075                               ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
1076     }
1077     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1078     {
1079         mtime_t current_date = mdate();
1080         if( !p_block->i_pts
1081                || p_block->i_pts > current_date + 10000000
1082                || current_date > p_block->i_pts )
1083         {
1084             /* ETSI EN 300 472 Annex A : do not take into account the PTS
1085              * for teletext streams. */
1086             p_block->i_pts = current_date + 400000
1087                                + p_input->i_pts_delay + i_delay;
1088         }
1089     }
1090
1091     p_block->i_rate = p_input->p->i_rate;
1092
1093     /* TODO handle mute */
1094     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
1095         p_input->p->i_rate == INPUT_RATE_DEFAULT ) )
1096     {
1097         input_DecoderDecode( es->p_dec, p_block );
1098     }
1099     else
1100     {
1101         block_Release( p_block );
1102     }
1103
1104     return VLC_SUCCESS;
1105 }
1106
1107 /*****************************************************************************
1108  * EsOutDel:
1109  *****************************************************************************/
1110 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1111 {
1112     es_out_sys_t *p_sys = out->p_sys;
1113     vlc_bool_t b_reselect = VLC_FALSE;
1114     int i;
1115
1116     /* We don't try to reselect */
1117     if( es->p_dec )
1118         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1119
1120     if( es->p_pgrm == p_sys->p_pgrm )
1121         EsOutESVarUpdate( out, es, VLC_TRUE );
1122
1123     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1124
1125     es->p_pgrm->i_es--;
1126     if( es->p_pgrm->i_es == 0 )
1127     {
1128         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1129     }
1130
1131     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1132         p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
1133
1134     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1135     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1136     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
1137
1138     switch( es->fmt.i_cat )
1139     {
1140         case AUDIO_ES:
1141             p_sys->i_audio--;
1142             break;
1143         case SPU_ES:
1144             p_sys->i_sub--;
1145             break;
1146         case VIDEO_ES:
1147             p_sys->i_video--;
1148             break;
1149     }
1150
1151     /* Re-select another track when needed */
1152     if( b_reselect )
1153         for( i = 0; i < p_sys->i_es; i++ )
1154         {
1155             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1156                 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1157         }
1158
1159     if( es->psz_language )
1160         free( es->psz_language );
1161     if( es->psz_language_code )
1162         free( es->psz_language_code );
1163
1164     es_format_Clean( &es->fmt );
1165
1166     free( es );
1167 }
1168
1169 /**
1170  * Control query handler
1171  *
1172  * \param out the es_out to control
1173  * \param i_query A es_out query as defined in include/ninput.h
1174  * \param args a variable list of arguments for the query
1175  * \return VLC_SUCCESS or an error code
1176  */
1177 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1178 {
1179     es_out_sys_t *p_sys = out->p_sys;
1180     vlc_bool_t  b, *pb;
1181     int         i, *pi;
1182
1183     es_out_id_t *es;
1184
1185     switch( i_query )
1186     {
1187         case ES_OUT_SET_ES_STATE:
1188             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1189             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1190             if( b && es->p_dec == NULL )
1191             {
1192                 EsSelect( out, es );
1193                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
1194             }
1195             else if( !b && es->p_dec )
1196             {
1197                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1198                 return VLC_SUCCESS;
1199             }
1200             return VLC_SUCCESS;
1201
1202         case ES_OUT_GET_ES_STATE:
1203             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1204             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1205
1206             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
1207             return VLC_SUCCESS;
1208
1209         case ES_OUT_SET_ACTIVE:
1210         {
1211             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1212             p_sys->b_active = b;
1213             /* Needed ? */
1214             if( b )
1215                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1216             return VLC_SUCCESS;
1217         }
1218
1219         case ES_OUT_GET_ACTIVE:
1220             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1221             *pb = p_sys->b_active;
1222             return VLC_SUCCESS;
1223
1224         case ES_OUT_SET_MODE:
1225             i = (int) va_arg( args, int );
1226             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1227                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1228             {
1229                 p_sys->i_mode = i;
1230
1231                 /* Reapply policy mode */
1232                 for( i = 0; i < p_sys->i_es; i++ )
1233                 {
1234                     if( p_sys->es[i]->p_dec )
1235                     {
1236                         EsUnselect( out, p_sys->es[i],
1237                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1238                     }
1239                 }
1240                 for( i = 0; i < p_sys->i_es; i++ )
1241                 {
1242                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1243                 }
1244                 return VLC_SUCCESS;
1245             }
1246             return VLC_EGENERIC;
1247
1248         case ES_OUT_GET_MODE:
1249             pi = (int*) va_arg( args, int* );
1250             *pi = p_sys->i_mode;
1251             return VLC_SUCCESS;
1252
1253         case ES_OUT_SET_ES:
1254             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1255             /* Special case NULL, NULL+i_cat */
1256             if( es == NULL )
1257             {
1258                 for( i = 0; i < p_sys->i_es; i++ )
1259                 {
1260                     if( p_sys->es[i]->p_dec )
1261                         EsUnselect( out, p_sys->es[i],
1262                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1263                 }
1264             }
1265             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1266             {
1267                 for( i = 0; i < p_sys->i_es; i++ )
1268                 {
1269                     if( p_sys->es[i]->p_dec &&
1270                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
1271                         EsUnselect( out, p_sys->es[i],
1272                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1273                 }
1274             }
1275             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1276             {
1277                 for( i = 0; i < p_sys->i_es; i++ )
1278                 {
1279                     if( p_sys->es[i]->p_dec &&
1280                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
1281                         EsUnselect( out, p_sys->es[i],
1282                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1283                 }
1284             }
1285             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1286             {
1287                 for( i = 0; i < p_sys->i_es; i++ )
1288                 {
1289                     if( p_sys->es[i]->p_dec &&
1290                         p_sys->es[i]->fmt.i_cat == SPU_ES )
1291                         EsUnselect( out, p_sys->es[i],
1292                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1293                 }
1294             }
1295             else
1296             {
1297                 for( i = 0; i < p_sys->i_es; i++ )
1298                 {
1299                     if( es == p_sys->es[i] )
1300                     {
1301                         EsOutSelect( out, es, VLC_TRUE );
1302                         break;
1303                     }
1304                 }
1305             }
1306             return VLC_SUCCESS;
1307
1308         case ES_OUT_SET_PCR:
1309         case ES_OUT_SET_GROUP_PCR:
1310         {
1311             es_out_pgrm_t *p_pgrm = NULL;
1312             int            i_group = 0;
1313             int64_t        i_pcr;
1314
1315             if( i_query == ES_OUT_SET_PCR )
1316             {
1317                 p_pgrm = p_sys->p_pgrm;
1318             }
1319             else
1320             {
1321                 int i;
1322                 i_group = (int)va_arg( args, int );
1323                 for( i = 0; i < p_sys->i_pgrm; i++ )
1324                 {
1325                     if( p_sys->pgrm[i]->i_id == i_group )
1326                     {
1327                         p_pgrm = p_sys->pgrm[i];
1328                         break;
1329                     }
1330                 }
1331             }
1332             if( p_pgrm == NULL )
1333                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1334
1335             i_pcr = (int64_t)va_arg( args, int64_t );
1336             /* search program */
1337             /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
1338             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
1339                                (i_pcr + 11 ) * 9 / 100);
1340             return VLC_SUCCESS;
1341         }
1342
1343         case ES_OUT_RESET_PCR:
1344             for( i = 0; i < p_sys->i_pgrm; i++ )
1345             {
1346                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
1347                 p_sys->pgrm[i]->clock.last_pts = 0;
1348             }
1349             return VLC_SUCCESS;
1350
1351         case ES_OUT_GET_TS:
1352             if( p_sys->p_pgrm )
1353             {
1354                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1355                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1356                 *pi_ts = input_ClockGetTS( p_sys->p_input,
1357                                            &p_sys->p_pgrm->clock,
1358                                            ( i_ts + 11 ) * 9 / 100 );
1359                 return VLC_SUCCESS;
1360             }
1361             return VLC_EGENERIC;
1362
1363         case ES_OUT_GET_GROUP:
1364             pi = (int*) va_arg( args, int* );
1365             if( p_sys->p_pgrm )
1366                 *pi = p_sys->p_pgrm->i_id;
1367             else
1368                 *pi = -1;    /* FIXME */
1369             return VLC_SUCCESS;
1370
1371         case ES_OUT_SET_GROUP:
1372         {
1373             int j;
1374             i = (int) va_arg( args, int );
1375             for( j = 0; j < p_sys->i_pgrm; j++ )
1376             {
1377                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1378                 if( p_pgrm->i_id == i )
1379                 {
1380                     EsOutProgramSelect( out, p_pgrm );
1381                     return VLC_SUCCESS;
1382                 }
1383             }
1384             return VLC_EGENERIC;
1385         }
1386
1387         case ES_OUT_SET_FMT:
1388         {
1389             /* This ain't pretty but is need by some demuxers (eg. Ogg )
1390              * to update the p_extra data */
1391             es_format_t *p_fmt;
1392             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1393             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1394             if( es == NULL ) return VLC_EGENERIC;
1395
1396             if( p_fmt->i_extra )
1397             {
1398                 es->fmt.i_extra = p_fmt->i_extra;
1399                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1400                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1401
1402                 if( !es->p_dec ) return VLC_SUCCESS;
1403
1404 #if 1
1405                 input_DecoderDelete( es->p_dec );
1406                 es->p_dec = input_DecoderNew( p_sys->p_input,
1407                                               &es->fmt, VLC_FALSE );
1408
1409 #else
1410                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1411                 es->p_dec->fmt_in.p_extra =
1412                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1413                 memcpy( es->p_dec->fmt_in.p_extra,
1414                         p_fmt->p_extra, p_fmt->i_extra );
1415 #endif
1416             }
1417
1418             return VLC_SUCCESS;
1419         }
1420
1421         case ES_OUT_SET_NEXT_DISPLAY_TIME:
1422         {
1423             int64_t i_date;
1424
1425             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1426             i_date = (int64_t)va_arg( args, int64_t );
1427
1428             if( !es || !es->p_dec )
1429                 return VLC_EGENERIC;
1430
1431             es->i_preroll_end = i_date;
1432             input_DecoderPreroll( es->p_dec, i_date );
1433
1434             return VLC_SUCCESS;
1435         }
1436         case ES_OUT_SET_GROUP_META:
1437         {
1438             int i_group = (int)va_arg( args, int );
1439             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1440
1441             EsOutProgramMeta( out, i_group, p_meta );
1442             return VLC_SUCCESS;
1443         }
1444         case ES_OUT_DEL_GROUP:
1445         {
1446             int i_group = (int)va_arg( args, int );
1447
1448             return EsOutProgramDel( out, i_group );
1449         }
1450
1451         default:
1452             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1453             return VLC_EGENERIC;
1454     }
1455 }
1456
1457 /****************************************************************************
1458  * LanguageGetName: try to expend iso639 into plain name
1459  ****************************************************************************/
1460 static char *LanguageGetName( const char *psz_code )
1461 {
1462     const iso639_lang_t *pl;
1463
1464     if( psz_code == NULL )
1465     {
1466         return strdup( "" );
1467     }
1468
1469     if( strlen( psz_code ) == 2 )
1470     {
1471         pl = GetLang_1( psz_code );
1472     }
1473     else if( strlen( psz_code ) == 3 )
1474     {
1475         pl = GetLang_2B( psz_code );
1476         if( !strcmp( pl->psz_iso639_1, "??" ) )
1477         {
1478             pl = GetLang_2T( psz_code );
1479         }
1480     }
1481     else
1482     {
1483         return strdup( psz_code );
1484     }
1485
1486     if( !strcmp( pl->psz_iso639_1, "??" ) )
1487     {
1488        return strdup( psz_code );
1489     }
1490     else
1491     {
1492         if( *pl->psz_native_name )
1493         {
1494             return strdup( pl->psz_native_name );
1495         }
1496         return strdup( pl->psz_eng_name );
1497     }
1498 }
1499
1500 /* Get a 2 char code */
1501 static char *LanguageGetCode( const char *psz_lang )
1502 {
1503     const iso639_lang_t *pl;
1504
1505     if( psz_lang == NULL || *psz_lang == '\0' )
1506         return strdup("??");
1507
1508     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1509     {
1510         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1511             !strcasecmp( pl->psz_native_name, psz_lang ) ||
1512             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1513             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1514             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1515             break;
1516     }
1517
1518     if( pl->psz_iso639_1 != NULL )
1519         return strdup( pl->psz_iso639_1 );
1520
1521     return strdup("??");
1522 }
1523
1524 static char **LanguageSplit( const char *psz_langs )
1525 {
1526     char *psz_dup;
1527     char *psz_parser;
1528     char **ppsz = NULL;
1529     int i_psz = 0;
1530
1531     if( psz_langs == NULL ) return NULL;
1532
1533     psz_parser = psz_dup = strdup(psz_langs);
1534
1535     while( psz_parser && *psz_parser )
1536     {
1537         char *psz;
1538         char *psz_code;
1539
1540         psz = strchr(psz_parser, ',' );
1541         if( psz ) *psz++ = '\0';
1542
1543         psz_code = LanguageGetCode( psz_parser );
1544         if( strcmp( psz_code, "??" ) )
1545         {
1546             TAB_APPEND( i_psz, ppsz, psz_code );
1547         }
1548
1549         psz_parser = psz;
1550     }
1551
1552     if( i_psz )
1553     {
1554         TAB_APPEND( i_psz, ppsz, NULL );
1555     }
1556
1557     free( psz_dup );
1558     return ppsz;
1559 }
1560
1561 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1562 {
1563     int i;
1564
1565     if( !ppsz_langs || !psz_lang ) return -1;
1566
1567     for( i = 0; ppsz_langs[i]; i++ )
1568         if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i;
1569
1570     return -1;
1571 }
1572
1573 /****************************************************************************
1574  * EsOutAddInfo:
1575  * - add meta info to the playlist item
1576  ****************************************************************************/
1577 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1578 {
1579     es_out_sys_t   *p_sys = out->p_sys;
1580     input_thread_t *p_input = p_sys->p_input;
1581     es_format_t    *fmt = &es->fmt;
1582     char           *psz_cat;
1583     lldiv_t         div;
1584
1585     /* Add stream info */
1586     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1587
1588     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1589                    "%.4s", (char*)&fmt->i_codec );
1590
1591     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1592                    "%s", es->psz_language );
1593
1594     /* Add information */
1595     switch( fmt->i_cat )
1596     {
1597     case AUDIO_ES:
1598         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1599                        _("Type"), _("Audio") );
1600
1601         if( fmt->audio.i_channels > 0 )
1602             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1603                            "%d", fmt->audio.i_channels );
1604
1605         if( fmt->audio.i_rate > 0 )
1606         {
1607             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
1608                            _("%d Hz"), fmt->audio.i_rate );
1609             var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
1610         }
1611
1612         if( fmt->audio.i_bitspersample > 0 )
1613             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1614                            _("Bits per sample"), "%d",
1615                            fmt->audio.i_bitspersample );
1616
1617         if( fmt->i_bitrate > 0 )
1618         {
1619             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
1620                            _("%d kb/s"), fmt->i_bitrate / 1000 );
1621             var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
1622         }
1623         break;
1624
1625     case VIDEO_ES:
1626         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1627                        _("Type"), _("Video") );
1628
1629         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
1630             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1631                            _("Resolution"), "%dx%d",
1632                            fmt->video.i_width, fmt->video.i_height );
1633
1634         if( fmt->video.i_visible_width > 0 &&
1635             fmt->video.i_visible_height > 0 )
1636             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1637                            _("Display resolution"), "%dx%d",
1638                            fmt->video.i_visible_width,
1639                            fmt->video.i_visible_height);
1640        if( fmt->video.i_frame_rate > 0 &&
1641            fmt->video.i_frame_rate_base > 0 )
1642        {
1643            div = lldiv( (float)fmt->video.i_frame_rate /
1644                                fmt->video.i_frame_rate_base * 1000000,
1645                                1000000 );
1646            input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1647                           _("Frame rate"), I64Fd".%06u",
1648                           div.quot, (unsigned int )div.rem );
1649        }
1650        break;
1651
1652     case SPU_ES:
1653         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1654                        _("Type"), _("Subtitle") );
1655         break;
1656
1657     default:
1658         break;
1659     }
1660
1661     free( psz_cat );
1662 }