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