]> git.sesse.net Git - vlc/blob - src/input/es_out.c
* es_out: fix program change on the fly.
[vlc] / src / input / es_out.c
1
2 /*****************************************************************************
3  * es_out.c: Es Out handler for input.
4  *****************************************************************************
5  * Copyright (C) 2003-2004 VideoLAN
6  * $Id$
7  *
8  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/decoder.h>
33
34 #include "input_internal.h"
35
36 #include "vlc_playlist.h"
37 #include "iso_lang.h"
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 typedef struct
43 {
44     /* Program ID */
45     int i_id;
46
47     /* Number of es for this pgrm */
48     int i_es;
49
50     vlc_bool_t b_selected;
51
52     /* Clock for this program */
53     input_clock_t clock;
54
55 } es_out_pgrm_t;
56
57 struct es_out_id_t
58 {
59     /* ES ID */
60     int       i_id;
61     es_out_pgrm_t *p_pgrm;
62
63     /* Channel in the track type */
64     int         i_channel;
65     es_format_t fmt;
66     char        *psz_language;
67     decoder_t   *p_dec;
68 };
69
70 struct es_out_sys_t
71 {
72     input_thread_t *p_input;
73
74     /* all programs */
75     int           i_pgrm;
76     es_out_pgrm_t **pgrm;
77     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
78     es_out_pgrm_t *p_pgrm;  /* Master program */
79
80     /* all es */
81     int         i_id;
82     int         i_es;
83     es_out_id_t **es;
84
85     /* mode gestion */
86     vlc_bool_t  b_active;
87     int         i_mode;
88
89     /* es count */
90     int         i_audio;
91     int         i_video;
92     int         i_sub;
93
94     /* es to select */
95     int         i_audio_last;
96     int         i_sub_last;
97
98     /* current main es */
99     es_out_id_t *p_es_audio;
100     es_out_id_t *p_es_video;
101     es_out_id_t *p_es_sub;
102
103     /* delay */
104     int64_t i_audio_delay;
105     int64_t i_spu_delay;
106 };
107
108 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
109 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
110 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
111 static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
112 static int          EsOutControl( es_out_t *, int i_query, va_list );
113
114 static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
115
116 static void EsSelect( es_out_t *out, es_out_id_t *es );
117 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
118 static char *LanguageGetName( const char *psz_code );
119
120 /*****************************************************************************
121  * input_EsOutNew:
122  *****************************************************************************/
123 es_out_t *input_EsOutNew( input_thread_t *p_input )
124 {
125     es_out_t     *out = malloc( sizeof( es_out_t ) );
126     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
127     vlc_value_t  val;
128
129     out->pf_add     = EsOutAdd;
130     out->pf_send    = EsOutSend;
131     out->pf_del     = EsOutDel;
132     out->pf_control = EsOutControl;
133     out->p_sys      = p_sys;
134
135     p_sys->p_input = p_input;
136
137     p_sys->b_active = VLC_FALSE;
138     p_sys->i_mode   = ES_OUT_MODE_AUTO;
139
140
141     p_sys->i_pgrm   = 0;
142     p_sys->pgrm     = NULL;
143     p_sys->p_pgrm   = NULL;
144
145     p_sys->i_id    = 0;
146     p_sys->i_es    = 0;
147     p_sys->es      = NULL;
148
149     p_sys->i_audio = 0;
150     p_sys->i_video = 0;
151     p_sys->i_sub   = 0;
152
153     var_Get( p_input, "audio-channel", &val );
154     p_sys->i_audio_last = val.i_int;
155
156     var_Get( p_input, "spu-channel", &val );
157     p_sys->i_sub_last = val.i_int;
158
159     p_sys->p_es_audio = NULL;
160     p_sys->p_es_video = NULL;
161     p_sys->p_es_sub   = NULL;
162
163     p_sys->i_audio_delay= 0;
164     p_sys->i_spu_delay  = 0;
165
166     return out;
167 }
168
169 /*****************************************************************************
170  * input_EsOutDelete:
171  *****************************************************************************/
172 void input_EsOutDelete( es_out_t *out )
173 {
174     es_out_sys_t *p_sys = out->p_sys;
175     int i;
176
177     for( i = 0; i < p_sys->i_es; i++ )
178     {
179         if( p_sys->es[i]->p_dec )
180         {
181             input_DecoderDelete( p_sys->es[i]->p_dec );
182         }
183         if( p_sys->es[i]->psz_language )
184             free( p_sys->es[i]->psz_language );
185         es_format_Clean( &p_sys->es[i]->fmt );
186
187         free( p_sys->es[i] );
188     }
189     if( p_sys->es )
190         free( p_sys->es );
191
192     for( i = 0; i < p_sys->i_pgrm; i++ )
193     {
194         free( p_sys->pgrm[i] );
195     }
196     if( p_sys->pgrm )
197         free( p_sys->pgrm );
198
199     free( p_sys );
200     free( out );
201 }
202
203 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
204 {
205     int i;
206     if( i_id < 0 )
207     {
208         /* Special HACK, -i_id is tha cat of the stream */
209         return (es_out_id_t*)((uint8_t*)NULL-i_id);
210     }
211
212     for( i = 0; i < out->p_sys->i_es; i++ )
213     {
214         if( out->p_sys->es[i]->i_id == i_id )
215             return out->p_sys->es[i];
216     }
217     return NULL;
218 }
219
220 void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
221 {
222     es_out_sys_t      *p_sys = out->p_sys;
223     int i;
224
225     for( i = 0; i < p_sys->i_es; i++ )
226     {
227         es_out_id_t *es = p_sys->es[i];
228
229         /* Send a dummy block to let decoder know that
230          * there is a discontinuity */
231         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
232         {
233             input_DecoderDiscontinuity( es->p_dec );
234         }
235     }
236 }
237
238 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
239 {
240     es_out_sys_t *p_sys = out->p_sys;
241
242     if( i_cat == AUDIO_ES )
243         p_sys->i_audio_delay = i_delay;
244     else if( i_cat == SPU_ES )
245         p_sys->i_spu_delay = i_delay;
246 }
247
248 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
249 {
250     es_out_sys_t      *p_sys = out->p_sys;
251     int i;
252
253     for( i = 0; i < p_sys->i_es; i++ )
254     {
255         es_out_id_t *es = p_sys->es[i];
256
257         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
258             return VLC_FALSE;
259     }
260     return VLC_TRUE;
261 }
262
263 /*****************************************************************************
264  *
265  *****************************************************************************/
266 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
267                               vlc_bool_t b_delete )
268 {
269     es_out_sys_t      *p_sys = out->p_sys;
270     input_thread_t    *p_input = p_sys->p_input;
271     vlc_value_t       val, text;
272
273     char *psz_var;
274
275     if( es->fmt.i_cat == AUDIO_ES )
276         psz_var = "audio-es";
277     else if( es->fmt.i_cat == VIDEO_ES )
278         psz_var = "video-es";
279     else if( es->fmt.i_cat == SPU_ES )
280         psz_var = "spu-es";
281     else
282         return;
283
284     if( b_delete )
285     {
286         val.i_int = es->i_id;
287         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
288         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
289         return;
290     }
291
292     /* Get the number of ES already added */
293     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
294     if( val.i_int == 0 )
295     {
296         vlc_value_t val2;
297
298         /* First one, we need to add the "Disable" choice */
299         val2.i_int = -1; text.psz_string = _("Disable");
300         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
301         val.i_int++;
302     }
303
304     /* Take care of the ES description */
305     if( es->fmt.psz_description && *es->fmt.psz_description )
306     {
307         if( es->psz_language && *es->psz_language )
308         {
309             text.psz_string = malloc( strlen( es->fmt.psz_description) + strlen( es->psz_language ) + 10 );
310             sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, es->psz_language );
311         }
312         else text.psz_string = strdup( es->fmt.psz_description );
313     }
314     else
315     {
316         if( es->psz_language && *es->psz_language )
317         {
318             char *temp;
319             text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 );
320             asprintf( &temp,  _("Track %i"), val.i_int );
321             sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
322             free( temp );
323         }
324         else
325         {
326             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
327             sprintf( text.psz_string, _("Track %i"), val.i_int );
328         }
329     }
330
331     val.i_int = es->i_id;
332     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
333
334     free( text.psz_string );
335
336     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
337 }
338
339 /* EsOutProgramSelect:
340  *  Select a program and update the object variable
341  */
342 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
343 {
344     es_out_sys_t      *p_sys = out->p_sys;
345     input_thread_t    *p_input = p_sys->p_input;
346     vlc_value_t       val;
347     int               i;
348
349     if( p_sys->p_pgrm == p_pgrm )
350         return; /* Nothing to do */
351
352     if( p_sys->p_pgrm )
353     {
354         es_out_pgrm_t *old = p_sys->p_pgrm;
355         msg_Dbg( p_input, "Unselecting program id=%d", old->i_id );
356
357         for( i = 0; i < p_sys->i_es; i++ )
358         {
359             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
360                 p_sys->i_mode != ES_OUT_MODE_ALL )
361                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
362         }
363
364         p_sys->p_es_audio = NULL;
365         p_sys->p_es_sub = NULL;
366         p_sys->p_es_video = NULL;
367     }
368
369     msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id );
370
371     /* Mark it selected */
372     p_pgrm->b_selected = VLC_TRUE;
373
374     /* Switch master stream */
375     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
376     {
377         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
378     }
379     p_pgrm->clock.b_master = VLC_TRUE;
380     p_sys->p_pgrm = p_pgrm;
381
382     /* Update "program" */
383     val.i_int = p_pgrm->i_id;
384     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
385
386     /* Update "es-*" */
387     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
388     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
389     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
390     for( i = 0; i < p_sys->i_es; i++ )
391     {
392         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
393             EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
394         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
395     }
396
397     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
398 }
399
400 /* EsOutAddProgram:
401  *  Add a program
402  */
403 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
404 {
405     es_out_sys_t      *p_sys = out->p_sys;
406     input_thread_t    *p_input = p_sys->p_input;
407     vlc_value_t       val;
408
409     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
410
411     /* Init */
412     p_pgrm->i_id = i_group;
413     p_pgrm->i_es = 0;
414     p_pgrm->b_selected = VLC_FALSE;
415     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
416
417     /* Append it */
418     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
419
420     /* Update "program" variable */
421     val.i_int = i_group;
422     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
423
424     if( i_group == var_GetInteger( p_input, "program" ) )
425     {
426         EsOutProgramSelect( out, p_pgrm );
427     }
428     else
429     {
430         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
431     }
432     return p_pgrm;
433 }
434
435 /* EsOutAdd:
436  *  Add an es_out
437  */
438 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
439 {
440     es_out_sys_t      *p_sys = out->p_sys;
441     input_thread_t    *p_input = p_sys->p_input;
442
443     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
444     es_out_pgrm_t     *p_pgrm = NULL;
445     int i;
446
447     if( fmt->i_group < 0 )
448     {
449         msg_Err( p_input, "invalid group number" );
450         return NULL;
451     }
452
453     /* Search the program */
454     for( i = 0; i < p_sys->i_pgrm; i++ )
455     {
456         if( fmt->i_group == p_sys->pgrm[i]->i_id )
457         {
458             p_pgrm = p_sys->pgrm[i];
459             break;
460         }
461     }
462     if( p_pgrm == NULL )
463     {
464         /* Create a new one */
465         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
466     }
467
468     /* Increase ref count for program */
469     p_pgrm->i_es++;
470
471     /* Set up ES */
472     if( fmt->i_id < 0 )
473         fmt->i_id = out->p_sys->i_id;
474     es->i_id = fmt->i_id;
475     es->p_pgrm = p_pgrm;
476     es_format_Copy( &es->fmt, fmt );
477     switch( fmt->i_cat )
478     {
479     case AUDIO_ES:
480         es->i_channel = p_sys->i_audio;
481         break;
482
483     case VIDEO_ES:
484         es->i_channel = p_sys->i_video;
485         break;
486
487     case SPU_ES:
488         es->i_channel = p_sys->i_sub;
489         break;
490
491     default:
492         es->i_channel = 0;
493         break;
494     }
495     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
496     es->p_dec = NULL;
497
498     if( es->p_pgrm == p_sys->p_pgrm )
499         EsOutESVarUpdate( out, es, VLC_FALSE );
500
501     /* Select it if needed */
502     EsOutSelect( out, es, VLC_FALSE );
503
504
505     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
506     p_sys->i_id++;  /* always incremented */
507     switch( fmt->i_cat )
508     {
509         case AUDIO_ES:
510             p_sys->i_audio++;
511             break;
512         case SPU_ES:
513             p_sys->i_sub++;
514             break;
515         case VIDEO_ES:
516             p_sys->i_video++;
517             break;
518     }
519
520     EsOutAddInfo( out, es );
521
522     return es;
523 }
524
525 static void EsSelect( es_out_t *out, es_out_id_t *es )
526 {
527     es_out_sys_t   *p_sys = out->p_sys;
528     input_thread_t *p_input = p_sys->p_input;
529     vlc_value_t    val;
530     char           *psz_var;
531
532     if( es->p_dec )
533     {
534         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
535         return;
536     }
537
538     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
539     {
540         if( !var_GetBool( p_input, "video" ) ||
541             ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
542         {
543             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
544                      es->i_id );
545             return;
546         }
547     }
548     else if( es->fmt.i_cat == AUDIO_ES )
549     {
550         var_Get( p_input, "audio", &val );
551         if( !var_GetBool( p_input, "audio" ) ||
552             ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
553         {
554             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
555                      es->i_id );
556             return;
557         }
558     }
559
560     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
561     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
562         return;
563
564     if( es->fmt.i_cat == VIDEO_ES )
565         psz_var = "video-es";
566     else if( es->fmt.i_cat == AUDIO_ES )
567         psz_var = "audio-es";
568     else if( es->fmt.i_cat == SPU_ES )
569         psz_var = "spu-es";
570     else
571         return;
572
573     /* Mark it as selected */
574     val.i_int = es->i_id;
575     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
576
577
578     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
579 }
580
581 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
582 {
583     es_out_sys_t   *p_sys = out->p_sys;
584     input_thread_t *p_input = p_sys->p_input;
585     vlc_value_t    val;
586     char           *psz_var;
587
588     if( es->p_dec == NULL )
589     {
590         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
591         return;
592     }
593
594     input_DecoderDelete( es->p_dec );
595     es->p_dec = NULL;
596
597     if( !b_update )
598         return;
599
600     /* Update var */
601     if( es->p_dec == NULL )
602         return;
603     if( es->fmt.i_cat == VIDEO_ES )
604         psz_var = "video-es";
605     else if( es->fmt.i_cat == AUDIO_ES )
606         psz_var = "audio-es";
607     else if( es->fmt.i_cat == SPU_ES )
608         psz_var = "spu-es";
609     else
610         return;
611
612     /* Mark it as selected */
613     val.i_int = -1;
614     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
615
616     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
617 }
618
619 /**
620  * Select an ES given the current mode
621  * XXX: you need to take a the lock before (stream.stream_lock)
622  *
623  * \param out The es_out structure
624  * \param es es_out_id structure
625  * \param b_force ...
626  * \return nothing
627  */
628 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
629 {
630     es_out_sys_t      *p_sys = out->p_sys;
631
632     int i_cat = es->fmt.i_cat;
633
634     if( !p_sys->b_active ||
635         ( !b_force && es->fmt.i_priority < 0 ) )
636     {
637         return;
638     }
639
640     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
641     {
642         if( !es->p_dec )
643             EsSelect( out, es );
644     }
645     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
646     {
647         vlc_value_t val;
648         int i;
649         var_Get( p_sys->p_input, "programs", &val );
650         for ( i = 0; i < val.p_list->i_count; i++ )
651         {
652             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
653             {
654                 if( !es->p_dec )
655                     EsSelect( out, es );
656                 break;
657             }
658         }
659         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
660     }
661     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
662     {
663         int i_wanted  = -1;
664
665         if( es->p_pgrm != p_sys->p_pgrm )
666             return;
667
668         if( i_cat == AUDIO_ES )
669         {
670             if( p_sys->p_es_audio &&
671                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
672             {
673                 return;
674             }
675             i_wanted  = p_sys->i_audio_last >= 0 ?
676                             p_sys->i_audio_last : es->i_channel;
677         }
678         else if( i_cat == SPU_ES )
679         {
680             if( p_sys->p_es_sub &&
681                 p_sys->p_es_sub->fmt.i_priority >=
682                     es->fmt.i_priority )
683             {
684                 return;
685             }
686             i_wanted  = p_sys->i_sub_last;
687         }
688         else if( i_cat == VIDEO_ES )
689         {
690             i_wanted  = es->i_channel;
691         }
692
693         if( i_wanted == es->i_channel && es->p_dec == NULL )
694             EsSelect( out, es );
695     }
696
697     /* FIXME TODO handle priority here */
698     if( es->p_dec )
699     {
700         if( i_cat == AUDIO_ES )
701         {
702             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
703                 p_sys->p_es_audio &&
704                 p_sys->p_es_audio != es &&
705                 p_sys->p_es_audio->p_dec )
706             {
707                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
708             }
709             p_sys->p_es_audio = es;
710         }
711         else if( i_cat == SPU_ES )
712         {
713             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
714                 p_sys->p_es_sub &&
715                 p_sys->p_es_sub != es &&
716                 p_sys->p_es_sub->p_dec )
717             {
718                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
719             }
720             p_sys->p_es_sub = es;
721         }
722         else if( i_cat == VIDEO_ES )
723         {
724             p_sys->p_es_video = es;
725         }
726     }
727 }
728
729 /**
730  * Send a block for the given es_out
731  *
732  * \param out the es_out to send from
733  * \param es the es_out_id
734  * \param p_block the data block to send
735  */
736 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
737 {
738     es_out_sys_t *p_sys = out->p_sys;
739     input_thread_t    *p_input = p_sys->p_input;
740     es_out_pgrm_t *p_pgrm = es->p_pgrm;
741     int64_t i_delay;
742
743     if( es->fmt.i_cat == AUDIO_ES )
744         i_delay = p_sys->i_audio_delay;
745     else if( es->fmt.i_cat == SPU_ES )
746         i_delay = p_sys->i_spu_delay;
747     else
748         i_delay = 0;
749
750     /* +11 -> avoid null value with non null dts/pts */
751     if( p_block->i_dts > 0 )
752     {
753         p_block->i_dts =
754             input_ClockGetTS( p_input, &p_pgrm->clock,
755                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
756     }
757     if( p_block->i_pts > 0 )
758     {
759         p_block->i_pts =
760             input_ClockGetTS( p_input, &p_pgrm->clock,
761                               ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
762     }
763     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
764     {
765         mtime_t current_date = mdate();
766         if( !p_block->i_pts
767                || p_block->i_pts > current_date + 10000000
768                || current_date > p_block->i_pts )
769         {
770             /* ETSI EN 300 472 Annex A : do not take into account the PTS
771              * for teletext streams. */
772             p_block->i_pts = current_date + 400000
773                                + p_input->i_pts_delay + i_delay;
774         }
775     }
776
777     p_block->i_rate = p_input->i_rate;
778
779     /* TODO handle mute */
780     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
781         p_input->i_rate == INPUT_RATE_DEFAULT ) )
782     {
783         input_DecoderDecode( es->p_dec, p_block );
784     }
785     else
786     {
787         block_Release( p_block );
788     }
789
790     return VLC_SUCCESS;
791 }
792
793 /*****************************************************************************
794  * EsOutDel:
795  *****************************************************************************/
796 static void EsOutDel( es_out_t *out, es_out_id_t *es )
797 {
798     es_out_sys_t *p_sys = out->p_sys;
799
800     /* We don't try to reselect */
801     if( es->p_dec )
802         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
803
804     if( es->p_pgrm == p_sys->p_pgrm )
805         EsOutESVarUpdate( out, es, VLC_TRUE );
806
807     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
808
809     es->p_pgrm->i_es--;
810     if( es->p_pgrm->i_es == 0 )
811     {
812         msg_Warn( p_sys->p_input, "Program doesn't contain anymore ES, "
813                   "TODO cleaning ?" );
814     }
815
816     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
817     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
818     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
819
820     switch( es->fmt.i_cat )
821     {
822         case AUDIO_ES:
823             p_sys->i_audio--;
824             break;
825         case SPU_ES:
826             p_sys->i_sub--;
827             break;
828         case VIDEO_ES:
829             p_sys->i_video--;
830             break;
831     }
832
833     if( es->psz_language )
834         free( es->psz_language );
835
836     es_format_Clean( &es->fmt );
837
838     free( es );
839 }
840
841 /**
842  * Control query handler
843  *
844  * \param out the es_out to control
845  * \param i_query A es_out query as defined in include/ninput.h
846  * \param args a variable list of arguments for the query
847  * \return VLC_SUCCESS or an error code
848  */
849 static int EsOutControl( es_out_t *out, int i_query, va_list args )
850 {
851     es_out_sys_t *p_sys = out->p_sys;
852     vlc_bool_t  b, *pb;
853     int         i, *pi;
854
855     es_out_id_t *es;
856
857     switch( i_query )
858     {
859         case ES_OUT_SET_ES_STATE:
860             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
861             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
862             if( b && es->p_dec == NULL )
863             {
864                 EsSelect( out, es );
865                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
866             }
867             else if( !b && es->p_dec )
868             {
869                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
870                 return VLC_SUCCESS;
871             }
872             return VLC_SUCCESS;
873
874         case ES_OUT_GET_ES_STATE:
875             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
876             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
877
878             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
879             return VLC_SUCCESS;
880
881         case ES_OUT_SET_ACTIVE:
882         {
883             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
884             p_sys->b_active = b;
885             /* Needed ? */
886             if( b )
887                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
888             return VLC_SUCCESS;
889         }
890
891         case ES_OUT_GET_ACTIVE:
892             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
893             *pb = p_sys->b_active;
894             return VLC_SUCCESS;
895
896         case ES_OUT_SET_MODE:
897             i = (int) va_arg( args, int );
898             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
899                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
900             {
901                 p_sys->i_mode = i;
902
903                 /* Reapply policy mode */
904                 for( i = 0; i < p_sys->i_es; i++ )
905                 {
906                     if( p_sys->es[i]->p_dec )
907                     {
908                         EsUnselect( out, p_sys->es[i],
909                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
910                     }
911                 }
912                 for( i = 0; i < p_sys->i_es; i++ )
913                 {
914                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
915                 }
916                 return VLC_SUCCESS;
917             }
918             return VLC_EGENERIC;
919
920         case ES_OUT_GET_MODE:
921             pi = (int*) va_arg( args, int* );
922             *pi = p_sys->i_mode;
923             return VLC_SUCCESS;
924
925         case ES_OUT_SET_ES:
926             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
927             /* Special case NULL, NULL+i_cat */
928             if( es == NULL )
929             {
930                 for( i = 0; i < p_sys->i_es; i++ )
931                 {
932                     if( p_sys->es[i]->p_dec )
933                         EsUnselect( out, p_sys->es[i],
934                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
935                 }
936             }
937             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
938             {
939                 for( i = 0; i < p_sys->i_es; i++ )
940                 {
941                     if( p_sys->es[i]->p_dec &&
942                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
943                         EsUnselect( out, p_sys->es[i],
944                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
945                 }
946             }
947             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
948             {
949                 for( i = 0; i < p_sys->i_es; i++ )
950                 {
951                     if( p_sys->es[i]->p_dec &&
952                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
953                         EsUnselect( out, p_sys->es[i],
954                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
955                 }
956             }
957             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
958             {
959                 for( i = 0; i < p_sys->i_es; i++ )
960                 {
961                     if( p_sys->es[i]->p_dec &&
962                         p_sys->es[i]->fmt.i_cat == SPU_ES )
963                         EsUnselect( out, p_sys->es[i],
964                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
965                 }
966             }
967             else
968             {
969                 for( i = 0; i < p_sys->i_es; i++ )
970                 {
971                     if( es == p_sys->es[i] )
972                     {
973                         EsOutSelect( out, es, VLC_TRUE );
974                         break;
975                     }
976                 }
977             }
978             return VLC_SUCCESS;
979
980         case ES_OUT_SET_PCR:
981         case ES_OUT_SET_GROUP_PCR:
982         {
983             es_out_pgrm_t *p_pgrm = NULL;
984             int            i_group = 0;
985             int64_t        i_pcr;
986
987             if( i_query == ES_OUT_SET_PCR )
988             {
989                 p_pgrm = p_sys->p_pgrm;
990             }
991             else
992             {
993                 int i;
994                 i_group = (int)va_arg( args, int );
995                 for( i = 0; i < p_sys->i_pgrm; i++ )
996                 {
997                     if( p_sys->pgrm[i]->i_id == i_group )
998                     {
999                         p_pgrm = p_sys->pgrm[i];
1000                         break;
1001                     }
1002                 }
1003             }
1004             if( p_pgrm == NULL )
1005                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1006
1007             i_pcr = (int64_t)va_arg( args, int64_t );
1008             /* search program */
1009             /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
1010             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
1011                                (i_pcr + 11 ) * 9 / 100);
1012             return VLC_SUCCESS;
1013         }
1014
1015         case ES_OUT_RESET_PCR:
1016             for( i = 0; i < p_sys->i_pgrm; i++ )
1017             {
1018                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
1019                 p_sys->pgrm[i]->clock.last_pts = 0;
1020             }
1021             return VLC_SUCCESS;
1022
1023         case ES_OUT_GET_TS:
1024             if( p_sys->p_pgrm )
1025             {
1026                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1027                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1028                 *pi_ts = input_ClockGetTS( p_sys->p_input,
1029                                            &p_sys->p_pgrm->clock,
1030                                            ( i_ts + 11 ) * 9 / 100 );
1031                 return VLC_SUCCESS;
1032             }
1033             return VLC_EGENERIC;
1034
1035         case ES_OUT_GET_GROUP:
1036             pi = (int*) va_arg( args, int* );
1037             if( p_sys->p_pgrm )
1038                 *pi = p_sys->p_pgrm->i_id;
1039             else
1040                 *pi = -1;    /* FIXME */
1041             return VLC_SUCCESS;
1042
1043         case ES_OUT_SET_GROUP:
1044         {
1045             int j;
1046             i = (int) va_arg( args, int );
1047             for( j = 0; j < p_sys->i_pgrm; j++ )
1048             {
1049                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1050                 if( p_pgrm->i_id == i )
1051                 {
1052                     EsOutProgramSelect( out, p_pgrm );
1053                     return VLC_SUCCESS;
1054                 }
1055             }
1056             return VLC_EGENERIC;
1057         }
1058
1059         case ES_OUT_SET_FMT:
1060         {
1061             /* This ain't pretty but is need by some demuxers (eg. Ogg )
1062              * to update the p_extra data */
1063             es_format_t *p_fmt;
1064             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1065             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1066             if( es == NULL ) return VLC_EGENERIC;
1067
1068             if( p_fmt->i_extra )
1069             {
1070                 es->fmt.i_extra = p_fmt->i_extra;
1071                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1072                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1073
1074                 if( !es->p_dec ) return VLC_SUCCESS;
1075
1076                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1077                 es->p_dec->fmt_in.p_extra =
1078                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1079                 memcpy( es->p_dec->fmt_in.p_extra,
1080                         p_fmt->p_extra, p_fmt->i_extra );
1081             }
1082
1083             return VLC_SUCCESS;
1084         }
1085
1086         default:
1087             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1088             return VLC_EGENERIC;
1089     }
1090 }
1091
1092 /****************************************************************************
1093  * LanguageGetName: try to expend iso639 into plain name
1094  ****************************************************************************/
1095 static char *LanguageGetName( const char *psz_code )
1096 {
1097     const iso639_lang_t *pl;
1098
1099     if( psz_code == NULL )
1100     {
1101         return strdup( "" );
1102     }
1103
1104     if( strlen( psz_code ) == 2 )
1105     {
1106         pl = GetLang_1( psz_code );
1107     }
1108     else if( strlen( psz_code ) == 3 )
1109     {
1110         pl = GetLang_2B( psz_code );
1111         if( !strcmp( pl->psz_iso639_1, "??" ) )
1112         {
1113             pl = GetLang_2T( psz_code );
1114         }
1115     }
1116     else
1117     {
1118         return strdup( psz_code );
1119     }
1120
1121     if( !strcmp( pl->psz_iso639_1, "??" ) )
1122     {
1123        return strdup( psz_code );
1124     }
1125     else
1126     {
1127         if( *pl->psz_native_name )
1128         {
1129             return strdup( pl->psz_native_name );
1130         }
1131         return strdup( pl->psz_eng_name );
1132     }
1133 }
1134
1135 /****************************************************************************
1136  * EsOutAddInfo:
1137  * - add meta info to the playlist item
1138  ****************************************************************************/
1139 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1140 {
1141     es_out_sys_t   *p_sys = out->p_sys;
1142     input_thread_t *p_input = p_sys->p_input;
1143     es_format_t    *fmt = &es->fmt;
1144     char           *psz_cat;
1145
1146     /* Add stream info */
1147     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1148
1149     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1150                    "%.4s", (char*)&fmt->i_codec );
1151
1152     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1153                    "%s", es->psz_language );
1154
1155     /* Add information */
1156     switch( fmt->i_cat )
1157     {
1158     case AUDIO_ES:
1159         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1160                        _("Type"), _("Audio") );
1161
1162         if( fmt->audio.i_channels > 0 )
1163             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1164                            "%d", fmt->audio.i_channels );
1165
1166         if( fmt->audio.i_rate > 0 )
1167             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
1168                            _("%d Hz"), fmt->audio.i_rate );
1169
1170         if( fmt->audio.i_bitspersample > 0 )
1171             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1172                            _("Bits per sample"), "%d",
1173                            fmt->audio.i_bitspersample );
1174
1175         if( fmt->i_bitrate > 0 )
1176             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
1177                            _("%d kb/s"), fmt->i_bitrate / 1000 );
1178         break;
1179
1180     case VIDEO_ES:
1181         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1182                        _("Type"), _("Video") );
1183
1184         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
1185             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1186                            _("Resolution"), "%dx%d",
1187                            fmt->video.i_width, fmt->video.i_height );
1188
1189         if( fmt->video.i_visible_width > 0 &&
1190             fmt->video.i_visible_height > 0 )
1191             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1192                            _("Display resolution"), "%dx%d",
1193                            fmt->video.i_visible_width,
1194                            fmt->video.i_visible_height);
1195         break;
1196
1197     case SPU_ES:
1198         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1199                        _("Type"), _("Subtitle") );
1200         break;
1201
1202     default:
1203         break;
1204     }
1205
1206     free( psz_cat );
1207 }