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