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