* src/input: update ES object vars when an ES is removed + some coding style changes.
[vlc.git] / 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                               vlc_bool_t b_delete )
250 {
251     es_out_sys_t      *p_sys = out->p_sys;
252     input_thread_t    *p_input = p_sys->p_input;
253     vlc_value_t       val, text;
254
255     char *psz_var;
256
257     if( es->fmt.i_cat == AUDIO_ES )
258         psz_var = "audio-es";
259     else if( es->fmt.i_cat == VIDEO_ES )
260         psz_var = "video-es";
261     else if( es->fmt.i_cat == SPU_ES )
262         psz_var = "spu-es";
263     else
264         return;
265
266     if( b_delete )
267     {
268         val.i_int = es->i_id;
269         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
270         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
271         return;
272     }
273
274     /* Get the number of ES already added */
275     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
276     if( val.i_int == 0 )
277     {
278         vlc_value_t val2;
279
280         /* First one, we need to add the "Disable" choice */
281         val2.i_int = -1; text.psz_string = _("Disable");
282         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
283         val.i_int++;
284     }
285
286     /* Take care of the ES description */
287     if( es->psz_description && *es->psz_description )
288     {
289         text.psz_string = strdup( es->psz_description );
290     }
291     else
292     {
293         text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
294         sprintf( text.psz_string, _("Track %i"), val.i_int );
295     }
296
297     val.i_int = es->i_id;
298     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
299
300     free( text.psz_string );
301
302     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
303 }
304
305 /* EsOutProgramSelect:
306  *  Select a program and update the object variable
307  */
308 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
309 {
310     es_out_sys_t      *p_sys = out->p_sys;
311     input_thread_t    *p_input = p_sys->p_input;
312     vlc_value_t       val;
313     int               i;
314
315     if( p_sys->p_pgrm == p_pgrm )
316         return; /* Nothing to do */
317
318     if( p_sys->p_pgrm )
319     {
320         es_out_pgrm_t *old = p_sys->p_pgrm;
321         msg_Dbg( p_input, "Unselecting program id=%d", old->i_id );
322
323         for( i = 0; i < p_sys->i_es; i++ )
324         {
325             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
326                 p_sys->i_mode != ES_OUT_MODE_ALL )
327                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
328         }
329     }
330
331     msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id );
332
333     /* Mark it selected */
334     p_pgrm->b_selected = VLC_TRUE;
335
336     /* Switch master stream */
337     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
338     {
339         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
340     }
341     p_pgrm->clock.b_master = VLC_TRUE;
342     p_sys->p_pgrm = p_pgrm;
343
344     /* Update "program" */
345     val.i_int = p_pgrm->i_id;
346     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
347
348     /* Update "es-*" */
349     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
350     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
351     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
352     for( i = 0; i < p_sys->i_es; i++ )
353     {
354         EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
355         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
356     }
357
358     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
359 }
360
361 /* EsOutAddProgram:
362  *  Add a program
363  */
364 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
365 {
366     es_out_sys_t      *p_sys = out->p_sys;
367     input_thread_t    *p_input = p_sys->p_input;
368     vlc_value_t       val;
369
370     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
371
372     /* Init */
373     p_pgrm->i_id = i_group;
374     p_pgrm->i_es = 0;
375     p_pgrm->b_selected = VLC_FALSE;
376     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
377
378     /* Append it */
379     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
380
381     /* Update "program" variable */
382     val.i_int = i_group;
383     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
384
385     if( i_group == var_GetInteger( p_input, "program" ) )
386     {
387         EsOutProgramSelect( out, p_pgrm );
388     }
389     else
390     {
391         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
392     }
393     return p_pgrm;
394 }
395
396 /* EsOutAdd:
397  *  Add an es_out
398  */
399 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
400 {
401     es_out_sys_t      *p_sys = out->p_sys;
402     input_thread_t    *p_input = p_sys->p_input;
403
404     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
405     es_out_pgrm_t     *p_pgrm = NULL;
406     int i;
407
408     if( fmt->i_group < 0 )
409     {
410         msg_Err( p_input, "invakud group number" );
411         return NULL;
412     }
413
414     /* Search the program */
415     for( i = 0; i < p_sys->i_pgrm; i++ )
416     {
417         if( fmt->i_group == p_sys->pgrm[i]->i_id )
418         {
419             p_pgrm = p_sys->pgrm[i];
420             break;
421         }
422     }
423     if( p_pgrm == NULL )
424     {
425         /* Create a new one */
426         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
427     }
428
429     /* Increase ref count for program */
430     p_pgrm->i_es++;
431
432     /* Set up ES */
433     if( fmt->i_id < 0 )
434         fmt->i_id = out->p_sys->i_id;
435     es->i_id = fmt->i_id;
436     es->p_pgrm = p_pgrm;
437     es_format_Copy( &es->fmt, fmt );
438     switch( fmt->i_cat )
439     {
440     case AUDIO_ES:
441         es->i_channel = p_sys->i_audio;
442         break;
443
444     case VIDEO_ES:
445         es->i_channel = p_sys->i_video;
446         break;
447
448     case SPU_ES:
449         es->i_channel = p_sys->i_sub;
450         break;
451
452     default:
453         es->i_channel = 0;
454         break;
455     }
456     es->psz_description = LanguageGetName( fmt->psz_language );
457     es->p_dec = NULL;
458
459     if( es->p_pgrm == p_sys->p_pgrm )
460         EsOutESVarUpdate( out, es, VLC_FALSE );
461
462 #if 0
463     /* Add stream info */
464     sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
465
466     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
467                    "%.4s", (char*)&fmt->i_codec );
468
469     if( *psz_description )
470         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
471                        "%s", psz_description );
472
473     if( fmt->psz_description && *fmt->psz_description )
474         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Description"),
475                        "%s", fmt->psz_description );
476
477     /* Add information */
478     switch( fmt->i_cat )
479     {
480     case AUDIO_ES:
481         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
482                        _("Type"), _("Audio") );
483
484         if( fmt->audio.i_channels > 0 )
485             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
486                            "%d", fmt->audio.i_channels );
487
488         if( fmt->audio.i_rate > 0 )
489             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
490                            _("%d Hz"), fmt->audio.i_rate );
491
492         if( fmt->audio.i_bitspersample > 0 )
493             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
494                            _("Bits per sample"), "%d",
495                            fmt->audio.i_bitspersample );
496
497         if( fmt->i_bitrate > 0 )
498             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
499                            _("%d bps"), fmt->i_bitrate );
500         break;
501
502     case VIDEO_ES:
503         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
504                        _("Type"), _("Video") );
505
506         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
507             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
508                            _("Resolution"), "%dx%d",
509                            fmt->video.i_width, fmt->video.i_height );
510
511         if( fmt->video.i_visible_width > 0 &&
512             fmt->video.i_visible_height > 0 )
513             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
514                            _("Display resolution"), "%dx%d",
515                            fmt->video.i_visible_width,
516                            fmt->video.i_visible_height);
517         break;
518
519     case SPU_ES:
520         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
521                        _("Type"), _("Subtitle") );
522         break;
523
524     default:
525         break;
526     }
527     free( psz_description );
528 #endif
529
530     /* Select it if needed */
531     EsOutSelect( out, es, VLC_FALSE );
532
533
534     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
535     p_sys->i_id++;  /* always incremented */
536     switch( fmt->i_cat )
537     {
538         case AUDIO_ES:
539             p_sys->i_audio++;
540             break;
541         case SPU_ES:
542             p_sys->i_sub++;
543             break;
544         case VIDEO_ES:
545             p_sys->i_video++;
546             break;
547     }
548
549     return es;
550 }
551
552 static void EsSelect( es_out_t *out, es_out_id_t *es )
553 {
554     es_out_sys_t   *p_sys = out->p_sys;
555     input_thread_t *p_input = p_sys->p_input;
556     vlc_value_t    val;
557     char           *psz_var;
558
559     if( es->p_dec )
560     {
561         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
562         return;
563     }
564
565     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
566     {
567         if( !var_GetBool( p_input, "video" ) ||
568             ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
569         {
570             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
571                      es->i_id );
572             return;
573         }
574     }
575     else if( es->fmt.i_cat == AUDIO_ES )
576     {
577         var_Get( p_input, "audio", &val );
578         if( !var_GetBool( p_input, "audio" ) ||
579             ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
580         {
581             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
582                      es->i_id );
583             return;
584         }
585     }
586
587     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
588     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
589         return;
590
591     if( es->fmt.i_cat == VIDEO_ES )
592         psz_var = "video-es";
593     else if( es->fmt.i_cat == AUDIO_ES )
594         psz_var = "audio-es";
595     else if( es->fmt.i_cat == SPU_ES )
596         psz_var = "spu-es";
597     else
598         return;
599
600     /* Mark it as selected */
601     val.i_int = es->i_id;
602     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
603
604
605     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
606 }
607
608 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
609 {
610     es_out_sys_t   *p_sys = out->p_sys;
611     input_thread_t *p_input = p_sys->p_input;
612     vlc_value_t    val;
613     char           *psz_var;
614
615     if( es->p_dec == NULL )
616     {
617         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
618         return;
619     }
620
621     input_DecoderDelete( es->p_dec );
622     es->p_dec = NULL;
623
624     if( !b_update )
625         return;
626
627     /* Update var */
628     if( es->p_dec == NULL )
629         return;
630     if( es->fmt.i_cat == VIDEO_ES )
631         psz_var = "video-es";
632     else if( es->fmt.i_cat == AUDIO_ES )
633         psz_var = "audio-es";
634     else if( es->fmt.i_cat == SPU_ES )
635         psz_var = "spu-es";
636     else
637         return;
638
639     /* Mark it as selected */
640     val.i_int = -1;
641     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
642
643     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
644 }
645
646 /**
647  * Select an ES given the current mode
648  * XXX: you need to take a the lock before (stream.stream_lock)
649  *
650  * \param out The es_out structure
651  * \param es es_out_id structure
652  * \param b_force ...
653  * \return nothing
654  */
655 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
656 {
657     es_out_sys_t      *p_sys = out->p_sys;
658
659     int i_cat = es->fmt.i_cat;
660
661     if( !p_sys->b_active ||
662         ( !b_force && es->fmt.i_priority < 0 ) )
663     {
664         return;
665     }
666
667     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
668     {
669         if( !es->p_dec )
670             EsSelect( out, es );
671     }
672     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
673     {
674         int i_wanted  = -1;
675
676         if( es->p_pgrm != p_sys->p_pgrm )
677             return;
678
679         if( i_cat == AUDIO_ES )
680         {
681             if( p_sys->p_es_audio &&
682                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
683             {
684                 return;
685             }
686             i_wanted  = p_sys->i_audio_last >= 0 ?
687                             p_sys->i_audio_last : es->i_channel;
688         }
689         else if( i_cat == SPU_ES )
690         {
691             if( p_sys->p_es_sub &&
692                 p_sys->p_es_sub->fmt.i_priority >=
693                     es->fmt.i_priority )
694             {
695                 return;
696             }
697             i_wanted  = p_sys->i_sub_last;
698         }
699         else if( i_cat == VIDEO_ES )
700         {
701             i_wanted  = es->i_channel;
702         }
703
704         if( i_wanted == es->i_channel && es->p_dec == NULL )
705             EsSelect( out, es );
706     }
707
708     /* FIXME TODO handle priority here */
709     if( es->p_dec )
710     {
711         if( i_cat == AUDIO_ES )
712         {
713             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
714                 p_sys->p_es_audio &&
715                 p_sys->p_es_audio != es &&
716                 p_sys->p_es_audio->p_dec )
717             {
718                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
719             }
720             p_sys->p_es_audio = es;
721         }
722         else if( i_cat == SPU_ES )
723         {
724             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
725                 p_sys->p_es_sub &&
726                 p_sys->p_es_sub != es &&
727                 p_sys->p_es_sub->p_dec )
728             {
729                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
730             }
731             p_sys->p_es_sub = es;
732         }
733         else if( i_cat == VIDEO_ES )
734         {
735             p_sys->p_es_video = es;
736         }
737     }
738 }
739
740 /**
741  * Send a block for the given es_out
742  *
743  * \param out the es_out to send from
744  * \param es the es_out_id
745  * \param p_block the data block to send
746  */
747 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
748 {
749     es_out_sys_t *p_sys = out->p_sys;
750     input_thread_t    *p_input = p_sys->p_input;
751     es_out_pgrm_t *p_pgrm = es->p_pgrm;
752     int64_t i_delay;
753
754     if( es->fmt.i_cat == AUDIO_ES )
755         i_delay = p_sys->i_audio_delay;
756     else if( es->fmt.i_cat == SPU_ES )
757         i_delay = p_sys->i_spu_delay;
758     else
759         i_delay = 0;
760
761     /* +11 -> avoid null value with non null dts/pts */
762     if( p_block->i_dts > 0 )
763     {
764         p_block->i_dts =
765             input_ClockGetTS( p_input, &p_pgrm->clock,
766                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
767     }
768     if( p_block->i_pts > 0 )
769     {
770         p_block->i_pts =
771             input_ClockGetTS( p_input, &p_pgrm->clock,
772                               ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
773     }
774
775     p_block->i_rate = p_input->i_rate;
776
777     /* TODO handle mute */
778     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || p_input->i_rate == INPUT_RATE_DEFAULT ) )
779     {
780         input_DecoderDecode( es->p_dec, p_block );
781     }
782     else
783     {
784         block_Release( p_block );
785     }
786
787     return VLC_SUCCESS;
788 }
789
790 /*****************************************************************************
791  * EsOutDel:
792  *****************************************************************************/
793 static void EsOutDel( es_out_t *out, es_out_id_t *es )
794 {
795     es_out_sys_t *p_sys = out->p_sys;
796
797     /* We don't try to reselect */
798     if( es->p_dec )
799         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
800
801     if( es->p_pgrm == p_sys->p_pgrm )
802         EsOutESVarUpdate( out, es, VLC_TRUE );
803
804     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
805
806     es->p_pgrm->i_es--;
807     if( es->p_pgrm->i_es == 0 )
808     {
809         msg_Err( p_sys->p_input, "Program doesn't contain anymore ES, "
810                  "TODO cleaning ?" );
811     }
812
813     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
814     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
815     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
816
817     switch( es->fmt.i_cat )
818     {
819         case AUDIO_ES:
820             p_sys->i_audio--;
821             break;
822         case SPU_ES:
823             p_sys->i_sub--;
824             break;
825         case VIDEO_ES:
826             p_sys->i_video--;
827             break;
828     }
829
830     if( es->psz_description )
831         free( es->psz_description );
832
833     es_format_Clean( &es->fmt );
834
835     free( es );
836 }
837
838 /**
839  * Control query handler
840  *
841  * \param out the es_out to control
842  * \param i_query A es_out query as defined in include/ninput.h
843  * \param args a variable list of arguments for the query
844  * \return VLC_SUCCESS or an error code
845  */
846 static int EsOutControl( es_out_t *out, int i_query, va_list args )
847 {
848     es_out_sys_t *p_sys = out->p_sys;
849     vlc_bool_t  b, *pb;
850     int         i, *pi;
851
852     es_out_id_t *es;
853
854     switch( i_query )
855     {
856         case ES_OUT_SET_ES_STATE:
857             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
858             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
859             if( b && es->p_dec == NULL )
860             {
861                 EsSelect( out, es );
862                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
863             }
864             else if( !b && es->p_dec )
865             {
866                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
867                 return VLC_SUCCESS;
868             }
869             return VLC_SUCCESS;
870
871         case ES_OUT_GET_ES_STATE:
872             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
873             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
874
875             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
876             return VLC_SUCCESS;
877
878         case ES_OUT_SET_ACTIVE:
879         {
880             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
881             p_sys->b_active = b;
882             /* Needed ? */
883             if( b )
884                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
885             return VLC_SUCCESS;
886         }
887
888         case ES_OUT_GET_ACTIVE:
889             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
890             *pb = p_sys->b_active;
891             return VLC_SUCCESS;
892
893         case ES_OUT_SET_MODE:
894             i = (int) va_arg( args, int );
895             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
896                 i == ES_OUT_MODE_AUTO )
897             {
898                 p_sys->i_mode = i;
899
900                 /* Reapply policy mode */
901                 for( i = 0; i < p_sys->i_es; i++ )
902                 {
903                     if( p_sys->es[i]->p_dec )
904                     {
905                         EsUnselect( out, p_sys->es[i],
906                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
907                     }
908                 }
909                 for( i = 0; i < p_sys->i_es; i++ )
910                 {
911                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
912                 }
913                 return VLC_SUCCESS;
914             }
915             return VLC_EGENERIC;
916
917         case ES_OUT_GET_MODE:
918             pi = (int*) va_arg( args, int* );
919             *pi = p_sys->i_mode;
920             return VLC_SUCCESS;
921
922         case ES_OUT_SET_ES:
923             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
924             /* Special case NULL, NULL+i_cat */
925             if( es == NULL )
926             {
927                 for( i = 0; i < p_sys->i_es; i++ )
928                 {
929                     if( p_sys->es[i]->p_dec )
930                         EsUnselect( out, p_sys->es[i],
931                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
932                 }
933             }
934             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
935             {
936                 for( i = 0; i < p_sys->i_es; i++ )
937                 {
938                     if( p_sys->es[i]->p_dec &&
939                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
940                         EsUnselect( out, p_sys->es[i],
941                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
942                 }
943             }
944             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
945             {
946                 for( i = 0; i < p_sys->i_es; i++ )
947                 {
948                     if( p_sys->es[i]->p_dec &&
949                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
950                         EsUnselect( out, p_sys->es[i],
951                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
952                 }
953             }
954             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
955             {
956                 for( i = 0; i < p_sys->i_es; i++ )
957                 {
958                     if( p_sys->es[i]->p_dec &&
959                         p_sys->es[i]->fmt.i_cat == SPU_ES )
960                         EsUnselect( out, p_sys->es[i],
961                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
962                 }
963             }
964             else
965             {
966                 for( i = 0; i < p_sys->i_es; i++ )
967                 {
968                     if( es == p_sys->es[i] )
969                     {
970                         EsOutSelect( out, es, VLC_TRUE );
971                         break;
972                     }
973                 }
974             }
975             return VLC_SUCCESS;
976
977         case ES_OUT_SET_PCR:
978         case ES_OUT_SET_GROUP_PCR:
979         {
980             es_out_pgrm_t *p_pgrm = NULL;
981             int            i_group = 0;
982             int64_t        i_pcr;
983
984             if( i_query == ES_OUT_SET_PCR )
985             {
986                 p_pgrm = p_sys->p_pgrm;
987             }
988             else
989             {
990                 int i;
991                 i_group = (int)va_arg( args, int );
992                 for( i = 0; i < p_sys->i_pgrm; i++ )
993                 {
994                     if( p_sys->pgrm[i]->i_id == i_group )
995                     {
996                         p_pgrm = p_sys->pgrm[i];
997                         break;
998                     }
999                 }
1000             }
1001             if( p_pgrm == NULL )
1002                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1003
1004             i_pcr = (int64_t)va_arg( args, int64_t );
1005             /* search program */
1006             /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
1007             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
1008                                (i_pcr + 11 ) * 9 / 100);
1009             return VLC_SUCCESS;
1010         }
1011
1012         case ES_OUT_RESET_PCR:
1013             for( i = 0; i < p_sys->i_pgrm; i++ )
1014             {
1015                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
1016                 p_sys->pgrm[i]->clock.last_pts = 0;
1017             }
1018             return VLC_SUCCESS;
1019
1020         case ES_OUT_GET_GROUP:
1021             pi = (int*) va_arg( args, int* );
1022             if( p_sys->p_pgrm )
1023                 *pi = p_sys->p_pgrm->i_id;
1024             else
1025                 *pi = -1;    /* FIXME */
1026             return VLC_SUCCESS;
1027
1028         case ES_OUT_SET_GROUP:
1029         {
1030             int j;
1031             i = (int) va_arg( args, int );
1032             for( j = 0; j < p_sys->i_pgrm; j++ )
1033             {
1034                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1035                 if( p_pgrm->i_id == i )
1036                 {
1037                     EsOutProgramSelect( out, p_pgrm );
1038                     return VLC_SUCCESS;
1039                 }
1040             }
1041             return VLC_EGENERIC;
1042         }
1043
1044         default:
1045             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1046             return VLC_EGENERIC;
1047     }
1048 }
1049
1050 /****************************************************************************
1051  * LanguageGetName: try to expend iso639 into plain name
1052  ****************************************************************************/
1053 static char *LanguageGetName( const char *psz_code )
1054 {
1055     const iso639_lang_t *pl;
1056
1057     if( psz_code == NULL )
1058     {
1059         return strdup( "" );
1060     }
1061
1062     if( strlen( psz_code ) == 2 )
1063     {
1064         pl = GetLang_1( psz_code );
1065     }
1066     else if( strlen( psz_code ) == 3 )
1067     {
1068         pl = GetLang_2B( psz_code );
1069         if( !strcmp( pl->psz_iso639_1, "??" ) )
1070         {
1071             pl = GetLang_2T( psz_code );
1072         }
1073     }
1074     else
1075     {
1076         return strdup( psz_code );
1077     }
1078
1079     if( !strcmp( pl->psz_iso639_1, "??" ) )
1080     {
1081        return strdup( psz_code );
1082     }
1083     else
1084     {
1085         if( *pl->psz_native_name )
1086         {
1087             return strdup( pl->psz_native_name );
1088         }
1089         return strdup( pl->psz_eng_name );
1090     }
1091 }