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