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