]> git.sesse.net Git - vlc/blob - src/input/es_out.c
All: preliminary support for audio while playing faster/slower (1/4 -> 4).
[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 #include <vlc_aout.h>
37
38 #include "input_internal.h"
39
40 #include "vlc_playlist.h"
41 #include "iso_lang.h"
42 /* FIXME we should find a better way than including that */
43 #include "../text/iso-639_def.h"
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 typedef struct
49 {
50     /* Program ID */
51     int i_id;
52
53     /* Number of es for this pgrm */
54     int i_es;
55
56     vlc_bool_t b_selected;
57
58     /* Clock for this program */
59     input_clock_t clock;
60
61     char    *psz_name;
62     char    *psz_now_playing;
63     char    *psz_publisher;
64
65     vlc_epg_t *p_epg;
66 } es_out_pgrm_t;
67
68 struct es_out_id_t
69 {
70     /* ES ID */
71     int       i_id;
72     es_out_pgrm_t *p_pgrm;
73
74     /* Misc. */
75     int64_t i_preroll_end;
76
77     /* Channel in the track type */
78     int         i_channel;
79     es_format_t fmt;
80     char        *psz_language;
81     char        *psz_language_code;
82     decoder_t   *p_dec;
83 };
84
85 struct es_out_sys_t
86 {
87     input_thread_t *p_input;
88
89     /* all programs */
90     int           i_pgrm;
91     es_out_pgrm_t **pgrm;
92     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
93     es_out_pgrm_t *p_pgrm;  /* Master program */
94
95     /* all es */
96     int         i_id;
97     int         i_es;
98     es_out_id_t **es;
99
100     /* mode gestion */
101     vlc_bool_t  b_active;
102     int         i_mode;
103
104     /* es count */
105     int         i_audio;
106     int         i_video;
107     int         i_sub;
108
109     /* es to select */
110     int         i_audio_last, i_audio_id;
111     int         i_sub_last, i_sub_id;
112     char        **ppsz_audio_language;
113     char        **ppsz_sub_language;
114
115     /* current main es */
116     es_out_id_t *p_es_audio;
117     es_out_id_t *p_es_video;
118     es_out_id_t *p_es_sub;
119
120     /* delay */
121     int64_t i_audio_delay;
122     int64_t i_spu_delay;
123 };
124
125 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
126 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
127 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
128 static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
129 static int          EsOutControl( es_out_t *, int i_query, va_list );
130
131 static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
132
133 static void EsSelect( es_out_t *out, es_out_id_t *es );
134 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
135 static char *LanguageGetName( const char *psz_code );
136 static char *LanguageGetCode( const char *psz_lang );
137 static char **LanguageSplit( const char *psz_langs );
138 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
139
140 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
141
142 /*****************************************************************************
143  * input_EsOutNew:
144  *****************************************************************************/
145 es_out_t *input_EsOutNew( input_thread_t *p_input )
146 {
147     es_out_t     *out = malloc( sizeof( es_out_t ) );
148     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
149     vlc_value_t  val;
150     int i;
151
152     out->pf_add     = EsOutAdd;
153     out->pf_send    = EsOutSend;
154     out->pf_del     = EsOutDel;
155     out->pf_control = EsOutControl;
156     out->p_sys      = p_sys;
157     out->b_sout     = (p_input->p->p_sout != NULL ? VLC_TRUE : VLC_FALSE);
158
159     p_sys->p_input = p_input;
160
161     p_sys->b_active = VLC_FALSE;
162     p_sys->i_mode   = ES_OUT_MODE_AUTO;
163
164
165     TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
166     p_sys->p_pgrm   = NULL;
167
168     p_sys->i_id    = 0;
169
170     TAB_INIT( p_sys->i_es, p_sys->es );
171
172     p_sys->i_audio = 0;
173     p_sys->i_video = 0;
174     p_sys->i_sub   = 0;
175
176     /* */
177     var_Get( p_input, "audio-track", &val );
178     p_sys->i_audio_last = val.i_int;
179
180     var_Get( p_input, "sub-track", &val );
181     p_sys->i_sub_last = val.i_int;
182
183     if( !p_input->b_preparsing )
184     {
185         var_Get( p_input, "audio-language", &val );
186         p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
187         if( p_sys->ppsz_audio_language )
188         {
189             for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
190                 msg_Dbg( p_input, "selected audio language[%d] %s",
191                          i, p_sys->ppsz_audio_language[i] );
192         }
193         if( val.psz_string ) free( val.psz_string );
194
195         var_Get( p_input, "sub-language", &val );
196         p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
197         if( p_sys->ppsz_sub_language )
198         {
199             for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
200                 msg_Dbg( p_input, "selected subtitle language[%d] %s",
201                          i, p_sys->ppsz_sub_language[i] );
202         }
203         if( val.psz_string ) free( val.psz_string );
204     }
205     else
206     {
207         p_sys->ppsz_sub_language = NULL;
208         p_sys->ppsz_audio_language = NULL;
209     }
210
211     var_Get( p_input, "audio-track-id", &val );
212     p_sys->i_audio_id = val.i_int;
213
214     var_Get( p_input, "sub-track-id", &val );
215     p_sys->i_sub_id = val.i_int;
216
217     p_sys->p_es_audio = NULL;
218     p_sys->p_es_video = NULL;
219     p_sys->p_es_sub   = NULL;
220
221     p_sys->i_audio_delay= 0;
222     p_sys->i_spu_delay  = 0;
223
224     return out;
225 }
226
227 /*****************************************************************************
228  * input_EsOutDelete:
229  *****************************************************************************/
230 void input_EsOutDelete( es_out_t *out )
231 {
232     es_out_sys_t *p_sys = out->p_sys;
233     int i;
234
235     for( i = 0; i < p_sys->i_es; i++ )
236     {
237         if( p_sys->es[i]->p_dec )
238         {
239             input_DecoderDelete( p_sys->es[i]->p_dec );
240         }
241         if( p_sys->es[i]->psz_language )
242             free( p_sys->es[i]->psz_language );
243         if( p_sys->es[i]->psz_language_code )
244             free( p_sys->es[i]->psz_language_code );
245         es_format_Clean( &p_sys->es[i]->fmt );
246
247         free( p_sys->es[i] );
248     }
249     if( p_sys->ppsz_audio_language )
250     {
251         for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
252             free( p_sys->ppsz_audio_language[i] );
253         free( p_sys->ppsz_audio_language );
254     }
255     if( p_sys->ppsz_sub_language )
256     {
257         for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
258             free( p_sys->ppsz_sub_language[i] );
259         free( p_sys->ppsz_sub_language );
260     }
261
262     if( p_sys->es )
263         free( p_sys->es );
264
265     /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
266     for( i = 0; i < p_sys->i_pgrm; i++ )
267     {
268         es_out_pgrm_t *p_pgrm = p_sys->pgrm[i];
269         if( p_pgrm->psz_now_playing )
270             free( p_pgrm->psz_now_playing );
271         if( p_pgrm->psz_publisher )
272             free( p_pgrm->psz_publisher );
273         if( p_pgrm->psz_name )
274             free( p_pgrm->psz_name );
275         if( p_pgrm->p_epg )
276             vlc_epg_Delete( p_pgrm->p_epg );
277
278         free( p_pgrm );
279     }
280     TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
281
282     free( p_sys );
283     free( out );
284 }
285
286 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
287 {
288     int i;
289     if( i_id < 0 )
290     {
291         /* Special HACK, -i_id is tha cat of the stream */
292         return (es_out_id_t*)((uint8_t*)NULL-i_id);
293     }
294
295     for( i = 0; i < out->p_sys->i_es; i++ )
296     {
297         if( out->p_sys->es[i]->i_id == i_id )
298             return out->p_sys->es[i];
299     }
300     return NULL;
301 }
302
303 void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio )
304 {
305     es_out_sys_t      *p_sys = out->p_sys;
306     int i;
307
308     for( i = 0; i < p_sys->i_es; i++ )
309     {
310         es_out_id_t *es = p_sys->es[i];
311
312         /* Send a dummy block to let decoder know that
313          * there is a discontinuity */
314         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
315             input_DecoderDiscontinuity( es->p_dec, b_flush );
316     }
317 }
318 void input_EsOutSetRate( es_out_t *out )
319 {
320     es_out_sys_t      *p_sys = out->p_sys;
321     int i;
322
323     for( i = 0; i < p_sys->i_pgrm; i++ )
324         input_ClockSetRate( p_sys->p_input, &p_sys->pgrm[i]->clock );
325 }
326
327 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
328 {
329     es_out_sys_t *p_sys = out->p_sys;
330
331     if( i_cat == AUDIO_ES )
332         p_sys->i_audio_delay = i_delay;
333     else if( i_cat == SPU_ES )
334         p_sys->i_spu_delay = i_delay;
335 }
336
337 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
338 {
339     es_out_sys_t      *p_sys = out->p_sys;
340     int i;
341
342     for( i = 0; i < p_sys->i_es; i++ )
343     {
344         es_out_id_t *es = p_sys->es[i];
345
346         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
347             return VLC_FALSE;
348     }
349     return VLC_TRUE;
350 }
351
352 /*****************************************************************************
353  *
354  *****************************************************************************/
355 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
356                               vlc_bool_t b_delete )
357 {
358     es_out_sys_t      *p_sys = out->p_sys;
359     input_thread_t    *p_input = p_sys->p_input;
360     vlc_value_t       val, text;
361
362     const char *psz_var;
363
364     if( es->fmt.i_cat == AUDIO_ES )
365         psz_var = "audio-es";
366     else if( es->fmt.i_cat == VIDEO_ES )
367         psz_var = "video-es";
368     else if( es->fmt.i_cat == SPU_ES )
369         psz_var = "spu-es";
370     else
371         return;
372
373     if( b_delete )
374     {
375         val.i_int = es->i_id;
376         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
377         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
378         return;
379     }
380
381     /* Get the number of ES already added */
382     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
383     if( val.i_int == 0 )
384     {
385         vlc_value_t val2;
386
387         /* First one, we need to add the "Disable" choice */
388         val2.i_int = -1; text.psz_string = _("Disable");
389         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
390         val.i_int++;
391     }
392
393     /* Take care of the ES description */
394     if( es->fmt.psz_description && *es->fmt.psz_description )
395     {
396         if( es->psz_language && *es->psz_language )
397         {
398             text.psz_string = malloc( strlen( es->fmt.psz_description) +
399                                       strlen( es->psz_language ) + 10 );
400             sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description,
401                                                    es->psz_language );
402         }
403         else text.psz_string = strdup( es->fmt.psz_description );
404     }
405     else
406     {
407         if( es->psz_language && *es->psz_language )
408         {
409             char *temp;
410             text.psz_string = malloc( strlen( _("Track %i") )+
411                                       strlen( es->psz_language ) + 30 );
412             asprintf( &temp,  _("Track %i"), val.i_int );
413             sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
414             free( temp );
415         }
416         else
417         {
418             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
419             sprintf( text.psz_string, _("Track %i"), val.i_int );
420         }
421     }
422
423     val.i_int = es->i_id;
424     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
425
426     free( text.psz_string );
427
428     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
429 }
430
431 /* EsOutProgramSelect:
432  *  Select a program and update the object variable
433  */
434 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
435 {
436     es_out_sys_t      *p_sys = out->p_sys;
437     input_thread_t    *p_input = p_sys->p_input;
438     vlc_value_t       val;
439     int               i;
440
441     if( p_sys->p_pgrm == p_pgrm )
442         return; /* Nothing to do */
443
444     if( p_sys->p_pgrm )
445     {
446         es_out_pgrm_t *old = p_sys->p_pgrm;
447         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
448
449         for( i = 0; i < p_sys->i_es; i++ )
450         {
451             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
452                 p_sys->i_mode != ES_OUT_MODE_ALL )
453                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
454         }
455
456         p_sys->p_es_audio = NULL;
457         p_sys->p_es_sub = NULL;
458         p_sys->p_es_video = NULL;
459     }
460
461     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
462
463     /* Mark it selected */
464     p_pgrm->b_selected = VLC_TRUE;
465
466     /* Switch master stream */
467     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
468     {
469         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
470     }
471     p_pgrm->clock.b_master = VLC_TRUE;
472     p_sys->p_pgrm = p_pgrm;
473
474     /* Update "program" */
475     val.i_int = p_pgrm->i_id;
476     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
477
478     /* Update "es-*" */
479     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
480     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
481     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
482     for( i = 0; i < p_sys->i_es; i++ )
483     {
484         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
485             EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
486         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
487     }
488
489     /* Update now playing */
490     vlc_mutex_lock( &p_input->p->input.p_item->lock );
491     vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta,
492                             p_pgrm->psz_now_playing );
493     vlc_meta_SetPublisher( p_input->p->input.p_item->p_meta,
494                            p_pgrm->psz_publisher );
495     vlc_mutex_unlock( &p_input->p->input.p_item->lock );
496
497     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
498 }
499
500 /* EsOutAddProgram:
501  *  Add a program
502  */
503 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
504 {
505     es_out_sys_t      *p_sys = out->p_sys;
506     input_thread_t    *p_input = p_sys->p_input;
507     vlc_value_t       val;
508
509     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
510
511     /* Init */
512     p_pgrm->i_id = i_group;
513     p_pgrm->i_es = 0;
514     p_pgrm->b_selected = VLC_FALSE;
515     p_pgrm->psz_name = NULL;
516     p_pgrm->psz_now_playing = NULL;
517     p_pgrm->psz_publisher = NULL;
518     p_pgrm->p_epg = NULL;
519     input_ClockInit( p_input, &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average );
520
521     /* Append it */
522     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
523
524     /* Update "program" variable */
525     val.i_int = i_group;
526     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
527
528     if( i_group == var_GetInteger( p_input, "program" ) )
529     {
530         EsOutProgramSelect( out, p_pgrm );
531     }
532     else
533     {
534         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
535     }
536     return p_pgrm;
537 }
538
539 /* EsOutDelProgram:
540  *  Delete a program
541  */
542 static int EsOutProgramDel( es_out_t *out, int i_group )
543 {
544     es_out_sys_t      *p_sys = out->p_sys;
545     input_thread_t    *p_input = p_sys->p_input;
546     es_out_pgrm_t     *p_pgrm = NULL;
547     vlc_value_t       val;
548     int               i;
549
550     for( i = 0; i < p_sys->i_pgrm; i++ )
551     {
552         if( p_sys->pgrm[i]->i_id == i_group )
553         {
554             p_pgrm = p_sys->pgrm[i];
555             break;
556         }
557     }
558
559     if( p_pgrm == NULL )
560         return VLC_EGENERIC;
561
562     if( p_pgrm->i_es )
563     {
564         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
565                  i_group, p_pgrm->i_es );
566         return VLC_EGENERIC;
567     }
568
569     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
570
571     /* If program is selected we need to unselect it */
572     if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL;
573
574     if( p_pgrm->psz_name ) free( p_pgrm->psz_name );
575     if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
576     if( p_pgrm->psz_publisher ) free( p_pgrm->psz_publisher );
577     if( p_pgrm->p_epg )
578         vlc_epg_Delete( p_pgrm->p_epg );
579     free( p_pgrm );
580
581     /* Update "program" variable */
582     val.i_int = i_group;
583     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
584
585     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
586
587     return VLC_SUCCESS;
588 }
589
590 /* EsOutProgramMeta:
591  */
592 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
593 {
594     char *psz = NULL;
595     if( p_pgrm->psz_name )
596         asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id );
597     else
598         asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id );
599     return psz;
600 }
601
602 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
603 {
604     es_out_sys_t      *p_sys = out->p_sys;
605     es_out_pgrm_t     *p_pgrm = NULL;
606     input_thread_t    *p_input = p_sys->p_input;
607     char              *psz_cat;
608     char              *psz_title = NULL;
609     char              *psz_provider = NULL;
610     int i;
611
612     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
613
614     /* Check against empty meta data (empty for what we handle) */
615     if( !p_meta->psz_title && !p_meta->psz_nowplaying && !p_meta->psz_publisher && p_meta->i_extra <= 0 )
616         return;
617     /* Find program */
618     for( i = 0; i < p_sys->i_pgrm; i++ )
619     {
620         if( p_sys->pgrm[i]->i_id == i_group )
621         {
622             p_pgrm = p_sys->pgrm[i];
623             break;
624         }
625     }
626     if( p_pgrm == NULL )
627         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
628
629     /* */
630     psz_title = p_meta->psz_title;
631     psz_provider = p_meta->psz_publisher;
632
633     /* Update the description text of the program */
634     if( psz_title && *psz_title )
635     {
636         vlc_value_t val;
637         vlc_value_t text;
638
639         if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
640         {
641             char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
642
643             /* Remove old entries */
644             input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
645             /* TODO update epg name */
646             free( psz_cat );
647         }
648         if( p_pgrm->psz_name ) free( p_pgrm->psz_name );
649         p_pgrm->psz_name = strdup( psz_title );
650
651         /* ugly but it works */
652         val.i_int = i_group;
653         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
654
655         if( psz_provider && *psz_provider )
656         {
657             asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider );
658             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
659             free( text.psz_string );
660         }
661         else
662         {
663             text.psz_string = psz_title;
664             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
665         }
666     }
667
668     psz_cat = EsOutProgramGetMetaName( p_pgrm );
669     if( psz_provider )
670     {
671         if( p_sys->p_pgrm == p_pgrm )
672         {
673             vlc_mutex_lock( &p_input->p->input.p_item->lock );
674             vlc_meta_SetPublisher( p_input->p->input.p_item->p_meta, psz_provider );
675             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
676         }
677         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(VLC_META_PUBLISHER), psz_provider );
678     }
679     for( i = 0; i < p_meta->i_extra; i++ )
680         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(p_meta->ppsz_extra_name[i]), p_meta->ppsz_extra_value[i] );
681
682     free( psz_cat );
683 }
684
685 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
686 {
687     int i;
688
689     /* Add new event */
690     for( i = 0; i < p_src->i_event; i++ )
691     {
692         vlc_epg_event_t *p_evt = p_src->pp_event[i];
693         vlc_bool_t b_add = VLC_TRUE;
694         int j;
695
696         for( j = 0; j < p_dst->i_event; j++ )
697         {
698             if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
699             {
700                 b_add = VLC_FALSE;
701                 break;
702             }
703             if( p_dst->pp_event[j]->i_start > p_evt->i_start )
704                 break;
705         }
706         if( b_add )
707         {
708             vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
709             if( !p_copy )
710                 break;
711             memset( p_copy, 0, sizeof(vlc_epg_event_t) );
712             p_copy->i_start = p_evt->i_start;
713             p_copy->i_duration = p_evt->i_duration;
714             p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
715             p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
716             p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
717             TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
718         }
719     }
720     /* Update current */
721     vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
722
723     /* Keep only 1 old event  */
724     if( p_dst->p_current )
725     {
726         while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
727             TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
728     }
729 }
730
731 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
732 {
733     es_out_sys_t      *p_sys = out->p_sys;
734     input_thread_t    *p_input = p_sys->p_input;
735     es_out_pgrm_t     *p_pgrm = NULL;
736     char *psz_cat;
737     char *psz_epg;
738     int i;
739
740     /* Find program */
741     for( i = 0; i < p_sys->i_pgrm; i++ )
742     {
743         if( p_sys->pgrm[i]->i_id == i_group )
744         {
745             p_pgrm = p_sys->pgrm[i];
746             break;
747         }
748     }
749     if( p_pgrm == NULL )
750         p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
751
752     /* Merge EPG */
753     if( !p_pgrm->p_epg )
754         p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
755     vlc_epg_Merge( p_pgrm->p_epg, p_epg );
756
757     /* Update info */
758     psz_cat = EsOutProgramGetMetaName( p_pgrm );
759 #ifdef HAVE_LOCALTIME_R
760     asprintf( &psz_epg, "EPG %s", psz_cat );
761     input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
762     msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
763     for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
764     {
765         const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
766         time_t t_start = (time_t)p_evt->i_start;
767         struct tm tm_start;
768         char psz_start[128];
769
770         localtime_r( &t_start, &tm_start );
771
772         snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
773         if( p_evt->psz_short_description || p_evt->psz_description )
774             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
775                            p_evt->psz_name,
776                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
777                            p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
778         else
779             input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
780                            p_evt->psz_name,
781                            p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
782     }
783     free( psz_epg );
784 #endif
785     /* Update now playing */
786     if( p_pgrm->psz_now_playing )
787         free( p_pgrm->psz_now_playing );
788     p_pgrm->psz_now_playing = NULL;
789     if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
790         p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
791
792     vlc_mutex_lock( &p_input->p->input.p_item->lock );
793     if( p_pgrm == p_sys->p_pgrm )
794         vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, p_pgrm->psz_now_playing );
795     vlc_mutex_unlock( &p_input->p->input.p_item->lock );
796
797     if( p_pgrm->psz_now_playing )
798         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(VLC_META_NOW_PLAYING), p_pgrm->psz_now_playing );
799     else
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     if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1221     {
1222         p_block->i_dts += i_delay;
1223     }
1224     else if( p_block->i_dts > 0 )
1225     {
1226         p_block->i_dts =
1227             input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay;
1228     }
1229     if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1230     {
1231         p_block->i_pts += i_delay;
1232     }
1233     else if( p_block->i_pts > 0 )
1234     {
1235         p_block->i_pts =
1236             input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay;
1237     }
1238     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1239     {
1240         mtime_t current_date = mdate();
1241         if( !p_block->i_pts
1242                || p_block->i_pts > current_date + 10000000
1243                || current_date > p_block->i_pts )
1244         {
1245             /* ETSI EN 300 472 Annex A : do not take into account the PTS
1246              * for teletext streams. */
1247             p_block->i_pts = current_date + 400000
1248                                + p_input->i_pts_delay + i_delay;
1249         }
1250     }
1251
1252     p_block->i_rate = p_input->p->i_rate;
1253
1254     /* TODO handle mute */
1255     if( es->p_dec &&
1256         ( es->fmt.i_cat != AUDIO_ES ||
1257           ( p_input->p->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
1258             p_input->p->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
1259     {
1260         input_DecoderDecode( es->p_dec, p_block );
1261     }
1262     else
1263     {
1264         block_Release( p_block );
1265     }
1266
1267     return VLC_SUCCESS;
1268 }
1269
1270 /*****************************************************************************
1271  * EsOutDel:
1272  *****************************************************************************/
1273 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1274 {
1275     es_out_sys_t *p_sys = out->p_sys;
1276     vlc_bool_t b_reselect = VLC_FALSE;
1277     int i;
1278
1279     /* We don't try to reselect */
1280     if( es->p_dec )
1281     {
1282         while( !out->p_sys->p_input->b_die && es->p_dec )
1283         {
1284             if( input_DecoderEmpty( es->p_dec ) )
1285                 break;
1286             msleep( 20*1000 );
1287         }
1288         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1289     }
1290
1291     if( es->p_pgrm == p_sys->p_pgrm )
1292         EsOutESVarUpdate( out, es, VLC_TRUE );
1293
1294     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1295
1296     es->p_pgrm->i_es--;
1297     if( es->p_pgrm->i_es == 0 )
1298     {
1299         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1300     }
1301
1302     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1303         p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
1304
1305     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1306     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1307     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
1308
1309     switch( es->fmt.i_cat )
1310     {
1311         case AUDIO_ES:
1312             p_sys->i_audio--;
1313             break;
1314         case SPU_ES:
1315             p_sys->i_sub--;
1316             break;
1317         case VIDEO_ES:
1318             p_sys->i_video--;
1319             break;
1320     }
1321
1322     /* Re-select another track when needed */
1323     if( b_reselect )
1324         for( i = 0; i < p_sys->i_es; i++ )
1325         {
1326             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1327                 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1328         }
1329
1330     if( es->psz_language )
1331         free( es->psz_language );
1332     if( es->psz_language_code )
1333         free( es->psz_language_code );
1334
1335     es_format_Clean( &es->fmt );
1336
1337     free( es );
1338 }
1339
1340 /**
1341  * Control query handler
1342  *
1343  * \param out the es_out to control
1344  * \param i_query A es_out query as defined in include/ninput.h
1345  * \param args a variable list of arguments for the query
1346  * \return VLC_SUCCESS or an error code
1347  */
1348 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1349 {
1350     es_out_sys_t *p_sys = out->p_sys;
1351     vlc_bool_t  b, *pb;
1352     int         i, *pi;
1353
1354     es_out_id_t *es;
1355
1356     switch( i_query )
1357     {
1358         case ES_OUT_SET_ES_STATE:
1359             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1360             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1361             if( b && es->p_dec == NULL )
1362             {
1363                 EsSelect( out, es );
1364                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
1365             }
1366             else if( !b && es->p_dec )
1367             {
1368                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1369                 return VLC_SUCCESS;
1370             }
1371             return VLC_SUCCESS;
1372
1373         case ES_OUT_GET_ES_STATE:
1374             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1375             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1376
1377             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
1378             return VLC_SUCCESS;
1379
1380         case ES_OUT_SET_ACTIVE:
1381         {
1382             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1383             p_sys->b_active = b;
1384             /* Needed ? */
1385             if( b )
1386                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1387             return VLC_SUCCESS;
1388         }
1389
1390         case ES_OUT_GET_ACTIVE:
1391             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1392             *pb = p_sys->b_active;
1393             return VLC_SUCCESS;
1394
1395         case ES_OUT_SET_MODE:
1396             i = (int) va_arg( args, int );
1397             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1398                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1399             {
1400                 p_sys->i_mode = i;
1401
1402                 /* Reapply policy mode */
1403                 for( i = 0; i < p_sys->i_es; i++ )
1404                 {
1405                     if( p_sys->es[i]->p_dec )
1406                     {
1407                         EsUnselect( out, p_sys->es[i],
1408                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1409                     }
1410                 }
1411                 for( i = 0; i < p_sys->i_es; i++ )
1412                 {
1413                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1414                 }
1415                 return VLC_SUCCESS;
1416             }
1417             return VLC_EGENERIC;
1418
1419         case ES_OUT_GET_MODE:
1420             pi = (int*) va_arg( args, int* );
1421             *pi = p_sys->i_mode;
1422             return VLC_SUCCESS;
1423
1424         case ES_OUT_SET_ES:
1425             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1426             /* Special case NULL, NULL+i_cat */
1427             if( es == NULL )
1428             {
1429                 for( i = 0; i < p_sys->i_es; i++ )
1430                 {
1431                     if( p_sys->es[i]->p_dec )
1432                         EsUnselect( out, p_sys->es[i],
1433                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1434                 }
1435             }
1436             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1437             {
1438                 for( i = 0; i < p_sys->i_es; i++ )
1439                 {
1440                     if( p_sys->es[i]->p_dec &&
1441                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
1442                         EsUnselect( out, p_sys->es[i],
1443                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1444                 }
1445             }
1446             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1447             {
1448                 for( i = 0; i < p_sys->i_es; i++ )
1449                 {
1450                     if( p_sys->es[i]->p_dec &&
1451                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
1452                         EsUnselect( out, p_sys->es[i],
1453                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1454                 }
1455             }
1456             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1457             {
1458                 for( i = 0; i < p_sys->i_es; i++ )
1459                 {
1460                     if( p_sys->es[i]->p_dec &&
1461                         p_sys->es[i]->fmt.i_cat == SPU_ES )
1462                         EsUnselect( out, p_sys->es[i],
1463                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1464                 }
1465             }
1466             else
1467             {
1468                 for( i = 0; i < p_sys->i_es; i++ )
1469                 {
1470                     if( es == p_sys->es[i] )
1471                     {
1472                         EsOutSelect( out, es, VLC_TRUE );
1473                         break;
1474                     }
1475                 }
1476             }
1477             {
1478                 playlist_t * p_playlist = pl_Yield( p_sys->p_input );
1479                 PL_LOCK;
1480                 p_playlist->gc_date = mdate();
1481                 vlc_cond_signal( &p_playlist->object_wait );
1482                 PL_UNLOCK;
1483                 pl_Release( p_playlist );
1484             }
1485             return VLC_SUCCESS;
1486
1487         case ES_OUT_SET_PCR:
1488         case ES_OUT_SET_GROUP_PCR:
1489         {
1490             es_out_pgrm_t *p_pgrm = NULL;
1491             int            i_group = 0;
1492             int64_t        i_pcr;
1493
1494             if( i_query == ES_OUT_SET_PCR )
1495             {
1496                 p_pgrm = p_sys->p_pgrm;
1497             }
1498             else
1499             {
1500                 int i;
1501                 i_group = (int)va_arg( args, int );
1502                 for( i = 0; i < p_sys->i_pgrm; i++ )
1503                 {
1504                     if( p_sys->pgrm[i]->i_id == i_group )
1505                     {
1506                         p_pgrm = p_sys->pgrm[i];
1507                         break;
1508                     }
1509                 }
1510             }
1511             if( p_pgrm == NULL )
1512                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1513
1514             i_pcr = (int64_t)va_arg( args, int64_t );
1515             /* search program */
1516             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr );
1517             return VLC_SUCCESS;
1518         }
1519
1520         case ES_OUT_RESET_PCR:
1521             for( i = 0; i < p_sys->i_pgrm; i++ )
1522             {
1523                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
1524                 p_sys->pgrm[i]->clock.last_pts = 0;
1525             }
1526             return VLC_SUCCESS;
1527
1528         case ES_OUT_GET_TS:
1529             if( p_sys->p_pgrm )
1530             {
1531                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1532                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1533                 *pi_ts = input_ClockGetTS( p_sys->p_input,
1534                                            &p_sys->p_pgrm->clock, i_ts );
1535                 return VLC_SUCCESS;
1536             }
1537             return VLC_EGENERIC;
1538
1539         case ES_OUT_GET_GROUP:
1540             pi = (int*) va_arg( args, int* );
1541             if( p_sys->p_pgrm )
1542                 *pi = p_sys->p_pgrm->i_id;
1543             else
1544                 *pi = -1;    /* FIXME */
1545             return VLC_SUCCESS;
1546
1547         case ES_OUT_SET_GROUP:
1548         {
1549             int j;
1550             i = (int) va_arg( args, int );
1551             for( j = 0; j < p_sys->i_pgrm; j++ )
1552             {
1553                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1554                 if( p_pgrm->i_id == i )
1555                 {
1556                     EsOutProgramSelect( out, p_pgrm );
1557                     return VLC_SUCCESS;
1558                 }
1559             }
1560             return VLC_EGENERIC;
1561         }
1562
1563         case ES_OUT_SET_FMT:
1564         {
1565             /* This ain't pretty but is need by some demuxers (eg. Ogg )
1566              * to update the p_extra data */
1567             es_format_t *p_fmt;
1568             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1569             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1570             if( es == NULL ) return VLC_EGENERIC;
1571
1572             if( p_fmt->i_extra )
1573             {
1574                 es->fmt.i_extra = p_fmt->i_extra;
1575                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1576                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1577
1578                 if( !es->p_dec ) return VLC_SUCCESS;
1579
1580 #if 1
1581                 input_DecoderDelete( es->p_dec );
1582                 es->p_dec = input_DecoderNew( p_sys->p_input,
1583                                               &es->fmt, VLC_FALSE );
1584
1585 #else
1586                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1587                 es->p_dec->fmt_in.p_extra =
1588                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1589                 memcpy( es->p_dec->fmt_in.p_extra,
1590                         p_fmt->p_extra, p_fmt->i_extra );
1591 #endif
1592             }
1593
1594             return VLC_SUCCESS;
1595         }
1596
1597         case ES_OUT_SET_NEXT_DISPLAY_TIME:
1598         {
1599             int64_t i_date;
1600
1601             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1602             i_date = (int64_t)va_arg( args, int64_t );
1603
1604             if( !es || !es->p_dec )
1605                 return VLC_EGENERIC;
1606
1607             /* XXX We should call input_ClockGetTS but PCR has been reseted
1608              * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
1609              * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
1610             es->i_preroll_end = i_date;
1611
1612             return VLC_SUCCESS;
1613         }
1614         case ES_OUT_SET_GROUP_META:
1615         {
1616             int i_group = (int)va_arg( args, int );
1617             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1618
1619             EsOutProgramMeta( out, i_group, p_meta );
1620             return VLC_SUCCESS;
1621         }
1622         case ES_OUT_SET_GROUP_EPG:
1623         {
1624             int i_group = (int)va_arg( args, int );
1625             vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1626
1627             EsOutProgramEpg( out, i_group, p_epg );
1628             return VLC_SUCCESS;
1629         }
1630         case ES_OUT_DEL_GROUP:
1631         {
1632             int i_group = (int)va_arg( args, int );
1633
1634             return EsOutProgramDel( out, i_group );
1635         }
1636
1637         default:
1638             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1639             return VLC_EGENERIC;
1640     }
1641 }
1642
1643 /****************************************************************************
1644  * LanguageGetName: try to expend iso639 into plain name
1645  ****************************************************************************/
1646 static char *LanguageGetName( const char *psz_code )
1647 {
1648     const iso639_lang_t *pl;
1649
1650     if( psz_code == NULL )
1651     {
1652         return strdup( "" );
1653     }
1654
1655     if( strlen( psz_code ) == 2 )
1656     {
1657         pl = GetLang_1( psz_code );
1658     }
1659     else if( strlen( psz_code ) == 3 )
1660     {
1661         pl = GetLang_2B( psz_code );
1662         if( !strcmp( pl->psz_iso639_1, "??" ) )
1663         {
1664             pl = GetLang_2T( psz_code );
1665         }
1666     }
1667     else
1668     {
1669         return strdup( psz_code );
1670     }
1671
1672     if( !strcmp( pl->psz_iso639_1, "??" ) )
1673     {
1674        return strdup( psz_code );
1675     }
1676     else
1677     {
1678         if( *pl->psz_native_name )
1679         {
1680             return strdup( pl->psz_native_name );
1681         }
1682         return strdup( pl->psz_eng_name );
1683     }
1684 }
1685
1686 /* Get a 2 char code */
1687 static char *LanguageGetCode( const char *psz_lang )
1688 {
1689     const iso639_lang_t *pl;
1690
1691     if( psz_lang == NULL || *psz_lang == '\0' )
1692         return strdup("??");
1693
1694     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1695     {
1696         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1697             !strcasecmp( pl->psz_native_name, psz_lang ) ||
1698             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1699             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1700             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1701             break;
1702     }
1703
1704     if( pl->psz_iso639_1 != NULL )
1705         return strdup( pl->psz_iso639_1 );
1706
1707     return strdup("??");
1708 }
1709
1710 static char **LanguageSplit( const char *psz_langs )
1711 {
1712     char *psz_dup;
1713     char *psz_parser;
1714     char **ppsz = NULL;
1715     int i_psz = 0;
1716
1717     if( psz_langs == NULL ) return NULL;
1718
1719     psz_parser = psz_dup = strdup(psz_langs);
1720
1721     while( psz_parser && *psz_parser )
1722     {
1723         char *psz;
1724         char *psz_code;
1725
1726         psz = strchr(psz_parser, ',' );
1727         if( psz ) *psz++ = '\0';
1728
1729         psz_code = LanguageGetCode( psz_parser );
1730         if( strcmp( psz_code, "??" ) )
1731         {
1732             TAB_APPEND( i_psz, ppsz, psz_code );
1733         }
1734
1735         psz_parser = psz;
1736     }
1737
1738     if( i_psz )
1739     {
1740         TAB_APPEND( i_psz, ppsz, NULL );
1741     }
1742
1743     free( psz_dup );
1744     return ppsz;
1745 }
1746
1747 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1748 {
1749     int i;
1750
1751     if( !ppsz_langs || !psz_lang ) return -1;
1752
1753     for( i = 0; ppsz_langs[i]; i++ )
1754         if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i;
1755
1756     return -1;
1757 }
1758
1759 /****************************************************************************
1760  * EsOutAddInfo:
1761  * - add meta info to the playlist item
1762  ****************************************************************************/
1763 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1764 {
1765     es_out_sys_t   *p_sys = out->p_sys;
1766     input_thread_t *p_input = p_sys->p_input;
1767     es_format_t    *fmt = &es->fmt;
1768     char           *psz_cat;
1769     lldiv_t         div;
1770
1771     /* Add stream info */
1772     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1773
1774     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1775                    "%.4s", (char*)&fmt->i_codec );
1776
1777     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1778                    "%s", es->psz_language );
1779
1780     /* Add information */
1781     switch( fmt->i_cat )
1782     {
1783     case AUDIO_ES:
1784         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1785                        _("Type"), _("Audio") );
1786
1787         if( fmt->audio.i_channels > 0 )
1788             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1789                            "%u", fmt->audio.i_channels );
1790
1791         if( fmt->audio.i_rate > 0 )
1792         {
1793             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
1794                            _("%u Hz"), fmt->audio.i_rate );
1795             var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
1796         }
1797
1798         if( fmt->audio.i_bitspersample > 0 )
1799             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1800                            _("Bits per sample"), "%u",
1801                            fmt->audio.i_bitspersample );
1802
1803         if( fmt->i_bitrate > 0 )
1804         {
1805             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
1806                            _("%u kb/s"), fmt->i_bitrate / 1000 );
1807             var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
1808         }
1809         break;
1810
1811     case VIDEO_ES:
1812         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1813                        _("Type"), _("Video") );
1814
1815         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
1816             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1817                            _("Resolution"), "%ux%u",
1818                            fmt->video.i_width, fmt->video.i_height );
1819
1820         if( fmt->video.i_visible_width > 0 &&
1821             fmt->video.i_visible_height > 0 )
1822             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1823                            _("Display resolution"), "%ux%u",
1824                            fmt->video.i_visible_width,
1825                            fmt->video.i_visible_height);
1826        if( fmt->video.i_frame_rate > 0 &&
1827            fmt->video.i_frame_rate_base > 0 )
1828        {
1829            div = lldiv( (float)fmt->video.i_frame_rate /
1830                                fmt->video.i_frame_rate_base * 1000000,
1831                                1000000 );
1832            input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1833                           _("Frame rate"), I64Fd".%06u",
1834                           div.quot, (unsigned int )div.rem );
1835        }
1836        break;
1837
1838     case SPU_ES:
1839         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1840                        _("Type"), _("Subtitle") );
1841         break;
1842
1843     default:
1844         break;
1845     }
1846
1847     free( psz_cat );
1848 }