]> git.sesse.net Git - vlc/blob - src/input/es_out.c
Clean up/Factorize.
[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         es->i_channel = p_sys->i_audio;
890         break;
891
892     case VIDEO_ES:
893         es->i_channel = p_sys->i_video;
894         if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
895             vlc_ureduce( &es->fmt.video.i_frame_rate,
896                          &es->fmt.video.i_frame_rate_base,
897                          fmt->video.i_frame_rate,
898                          fmt->video.i_frame_rate_base, 0 );
899         break;
900
901     case SPU_ES:
902         es->i_channel = p_sys->i_sub;
903         break;
904
905     default:
906         es->i_channel = 0;
907         break;
908     }
909     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
910     es->psz_language_code = LanguageGetCode( fmt->psz_language );
911     es->p_dec = NULL;
912
913     if( es->p_pgrm == p_sys->p_pgrm )
914         EsOutESVarUpdate( out, es, VLC_FALSE );
915
916     /* Select it if needed */
917     EsOutSelect( out, es, VLC_FALSE );
918
919
920     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
921     p_sys->i_id++;  /* always incremented */
922     switch( fmt->i_cat )
923     {
924         case AUDIO_ES:
925             p_sys->i_audio++;
926             break;
927         case SPU_ES:
928             p_sys->i_sub++;
929             break;
930         case VIDEO_ES:
931             p_sys->i_video++;
932             break;
933     }
934
935     EsOutAddInfo( out, es );
936
937     return es;
938 }
939
940 static void EsSelect( es_out_t *out, es_out_id_t *es )
941 {
942     es_out_sys_t   *p_sys = out->p_sys;
943     input_thread_t *p_input = p_sys->p_input;
944     vlc_value_t    val;
945     const char     *psz_var;
946
947     if( es->p_dec )
948     {
949         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
950         return;
951     }
952
953     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
954     {
955         if( !var_GetBool( p_input, "video" ) ||
956             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
957         {
958             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
959                      es->i_id );
960             return;
961         }
962     }
963     else if( es->fmt.i_cat == AUDIO_ES )
964     {
965         var_Get( p_input, "audio", &val );
966         if( !var_GetBool( p_input, "audio" ) ||
967             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
968         {
969             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
970                      es->i_id );
971             return;
972         }
973     }
974     if( es->fmt.i_cat == SPU_ES )
975     {
976         var_Get( p_input, "spu", &val );
977         if( !var_GetBool( p_input, "spu" ) ||
978             ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) )
979         {
980             msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
981                      es->i_id );
982             return;
983         }
984     }
985
986     es->i_preroll_end = -1;
987     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
988     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
989         return;
990
991     if( es->fmt.i_cat == VIDEO_ES )
992         psz_var = "video-es";
993     else if( es->fmt.i_cat == AUDIO_ES )
994         psz_var = "audio-es";
995     else if( es->fmt.i_cat == SPU_ES )
996         psz_var = "spu-es";
997     else
998         return;
999
1000     /* Mark it as selected */
1001     val.i_int = es->i_id;
1002     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1003
1004
1005     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1006 }
1007
1008 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
1009 {
1010     es_out_sys_t   *p_sys = out->p_sys;
1011     input_thread_t *p_input = p_sys->p_input;
1012     vlc_value_t    val;
1013     const char     *psz_var;
1014
1015     if( es->p_dec == NULL )
1016     {
1017         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1018         return;
1019     }
1020
1021     input_DecoderDelete( es->p_dec );
1022     es->p_dec = NULL;
1023
1024     if( !b_update )
1025         return;
1026
1027     /* Update var */
1028     if( es->p_dec == NULL )
1029         return;
1030     if( es->fmt.i_cat == VIDEO_ES )
1031         psz_var = "video-es";
1032     else if( es->fmt.i_cat == AUDIO_ES )
1033         psz_var = "audio-es";
1034     else if( es->fmt.i_cat == SPU_ES )
1035         psz_var = "spu-es";
1036     else
1037         return;
1038
1039     /* Mark it as selected */
1040     val.i_int = -1;
1041     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1042
1043     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1044 }
1045
1046 /**
1047  * Select an ES given the current mode
1048  * XXX: you need to take a the lock before (stream.stream_lock)
1049  *
1050  * \param out The es_out structure
1051  * \param es es_out_id structure
1052  * \param b_force ...
1053  * \return nothing
1054  */
1055 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
1056 {
1057     es_out_sys_t      *p_sys = out->p_sys;
1058
1059     int i_cat = es->fmt.i_cat;
1060
1061     if( !p_sys->b_active ||
1062         ( !b_force && es->fmt.i_priority < 0 ) )
1063     {
1064         return;
1065     }
1066
1067     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1068     {
1069         if( !es->p_dec )
1070             EsSelect( out, es );
1071     }
1072     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1073     {
1074         vlc_value_t val;
1075         int i;
1076         var_Get( p_sys->p_input, "programs", &val );
1077         for ( i = 0; i < val.p_list->i_count; i++ )
1078         {
1079             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1080             {
1081                 if( !es->p_dec )
1082                     EsSelect( out, es );
1083                 break;
1084             }
1085         }
1086         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1087     }
1088     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1089     {
1090         int i_wanted  = -1;
1091
1092         if( es->p_pgrm != p_sys->p_pgrm )
1093             return;
1094
1095         if( i_cat == AUDIO_ES )
1096         {
1097             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1098                                      es->psz_language_code );
1099
1100             if( p_sys->p_es_audio &&
1101                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1102             {
1103                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1104                                          p_sys->p_es_audio->psz_language_code );
1105
1106                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1107                     return;
1108                 i_wanted = es->i_channel;
1109             }
1110             else
1111             {
1112                 /* Select audio if (no audio selected yet)
1113                  * - no audio-language
1114                  * - no audio code for the ES
1115                  * - audio code in the requested list */
1116                 if( idx1 >= 0 ||
1117                     !strcmp( es->psz_language_code, "??" ) ||
1118                     !p_sys->ppsz_audio_language )
1119                     i_wanted = es->i_channel;
1120             }
1121
1122             if( p_sys->i_audio_last >= 0 )
1123                 i_wanted = p_sys->i_audio_last;
1124
1125             if( p_sys->i_audio_id >= 0 )
1126             {
1127                 if( es->i_id == p_sys->i_audio_id )
1128                     i_wanted = es->i_channel;
1129                 else
1130                     return;
1131             }
1132         }
1133         else if( i_cat == SPU_ES )
1134         {
1135             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1136                                      es->psz_language_code );
1137
1138             if( p_sys->p_es_sub &&
1139                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1140             {
1141                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1142                                          p_sys->p_es_sub->psz_language_code );
1143
1144                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1145                         idx1, es->psz_language_code, idx2,
1146                         p_sys->p_es_sub->psz_language_code );
1147
1148                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1149                     return;
1150                 /* We found a SPU that matches our language request */
1151                 i_wanted  = es->i_channel;
1152             }
1153             else if( idx1 >= 0 )
1154             {
1155                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1156                         idx1, es->psz_language_code );
1157
1158                 i_wanted  = es->i_channel;
1159             }
1160             else if( p_sys->i_default_sub_id >= 0 )
1161             {
1162                 if( es->i_id == p_sys->i_default_sub_id )
1163                     i_wanted = es->i_channel;
1164             }
1165
1166             if( p_sys->i_sub_last >= 0 )
1167                 i_wanted  = p_sys->i_sub_last;
1168
1169             if( p_sys->i_sub_id >= 0 )
1170             {
1171                 if( es->i_id == p_sys->i_sub_id )
1172                     i_wanted = es->i_channel;
1173                 else
1174                     return;
1175             }
1176         }
1177         else if( i_cat == VIDEO_ES )
1178         {
1179             i_wanted  = es->i_channel;
1180         }
1181
1182         if( i_wanted == es->i_channel && es->p_dec == NULL )
1183             EsSelect( out, es );
1184     }
1185
1186     /* FIXME TODO handle priority here */
1187     if( es->p_dec )
1188     {
1189         if( i_cat == AUDIO_ES )
1190         {
1191             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1192                 p_sys->p_es_audio &&
1193                 p_sys->p_es_audio != es &&
1194                 p_sys->p_es_audio->p_dec )
1195             {
1196                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
1197             }
1198             p_sys->p_es_audio = es;
1199         }
1200         else if( i_cat == SPU_ES )
1201         {
1202             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1203                 p_sys->p_es_sub &&
1204                 p_sys->p_es_sub != es &&
1205                 p_sys->p_es_sub->p_dec )
1206             {
1207                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
1208             }
1209             p_sys->p_es_sub = es;
1210         }
1211         else if( i_cat == VIDEO_ES )
1212         {
1213             p_sys->p_es_video = es;
1214         }
1215     }
1216 }
1217
1218 /**
1219  * Send a block for the given es_out
1220  *
1221  * \param out the es_out to send from
1222  * \param es the es_out_id
1223  * \param p_block the data block to send
1224  */
1225 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1226 {
1227     es_out_sys_t *p_sys = out->p_sys;
1228     input_thread_t    *p_input = p_sys->p_input;
1229     es_out_pgrm_t *p_pgrm = es->p_pgrm;
1230     int64_t i_delay;
1231     int i_total=0;
1232
1233     if( es->fmt.i_cat == AUDIO_ES )
1234         i_delay = p_sys->i_audio_delay;
1235     else if( es->fmt.i_cat == SPU_ES )
1236         i_delay = p_sys->i_spu_delay;
1237     else
1238         i_delay = 0;
1239
1240     if( p_input->p_libvlc->b_stats )
1241     {
1242         vlc_mutex_lock( &p_input->p->counters.counters_lock );
1243         stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1244                              p_block->i_buffer, &i_total );
1245         stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1246                            (float)i_total, NULL );
1247         vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1248     }
1249
1250     /* Mark preroll blocks */
1251     if( es->i_preroll_end >= 0 )
1252     {
1253         int64_t i_date = p_block->i_pts;
1254         if( i_date <= 0 )
1255             i_date = p_block->i_dts;
1256
1257         if( i_date < es->i_preroll_end )
1258             p_block->i_flags |= BLOCK_FLAG_PREROLL;
1259         else
1260             es->i_preroll_end = -1;
1261     }
1262
1263     if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1264     {
1265         p_block->i_dts += i_delay;
1266     }
1267     else if( p_block->i_dts > 0 )
1268     {
1269         p_block->i_dts =
1270             input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay;
1271     }
1272     if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1273     {
1274         p_block->i_pts += i_delay;
1275     }
1276     else if( p_block->i_pts > 0 )
1277     {
1278         p_block->i_pts =
1279             input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay;
1280     }
1281     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1282     {
1283         mtime_t current_date = mdate();
1284         if( !p_block->i_pts
1285                || p_block->i_pts > current_date + 10000000
1286                || current_date > p_block->i_pts )
1287         {
1288             /* ETSI EN 300 472 Annex A : do not take into account the PTS
1289              * for teletext streams. */
1290             p_block->i_pts = current_date + 400000
1291                                + p_input->i_pts_delay + i_delay;
1292         }
1293     }
1294
1295     p_block->i_rate = p_input->p->i_rate;
1296
1297     /* TODO handle mute */
1298     if( es->p_dec &&
1299         ( es->fmt.i_cat != AUDIO_ES ||
1300           ( p_input->p->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
1301             p_input->p->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
1302     {
1303         input_DecoderDecode( es->p_dec, p_block );
1304     }
1305     else
1306     {
1307         block_Release( p_block );
1308     }
1309
1310     return VLC_SUCCESS;
1311 }
1312
1313 /*****************************************************************************
1314  * EsOutDel:
1315  *****************************************************************************/
1316 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1317 {
1318     es_out_sys_t *p_sys = out->p_sys;
1319     vlc_bool_t b_reselect = VLC_FALSE;
1320     int i;
1321
1322     /* We don't try to reselect */
1323     if( es->p_dec )
1324     {
1325         while( !out->p_sys->p_input->b_die && es->p_dec )
1326         {
1327             if( input_DecoderEmpty( es->p_dec ) )
1328                 break;
1329             msleep( 20*1000 );
1330         }
1331         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1332     }
1333
1334     if( es->p_pgrm == p_sys->p_pgrm )
1335         EsOutESVarUpdate( out, es, VLC_TRUE );
1336
1337     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1338
1339     es->p_pgrm->i_es--;
1340     if( es->p_pgrm->i_es == 0 )
1341     {
1342         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1343     }
1344
1345     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1346         p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
1347
1348     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1349     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1350     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
1351
1352     switch( es->fmt.i_cat )
1353     {
1354         case AUDIO_ES:
1355             p_sys->i_audio--;
1356             break;
1357         case SPU_ES:
1358             p_sys->i_sub--;
1359             break;
1360         case VIDEO_ES:
1361             p_sys->i_video--;
1362             break;
1363     }
1364
1365     /* Re-select another track when needed */
1366     if( b_reselect )
1367         for( i = 0; i < p_sys->i_es; i++ )
1368         {
1369             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1370                 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1371         }
1372
1373     if( es->psz_language )
1374         free( es->psz_language );
1375     if( es->psz_language_code )
1376         free( es->psz_language_code );
1377
1378     es_format_Clean( &es->fmt );
1379
1380     free( es );
1381 }
1382
1383 /**
1384  * Control query handler
1385  *
1386  * \param out the es_out to control
1387  * \param i_query A es_out query as defined in include/ninput.h
1388  * \param args a variable list of arguments for the query
1389  * \return VLC_SUCCESS or an error code
1390  */
1391 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1392 {
1393     es_out_sys_t *p_sys = out->p_sys;
1394     vlc_bool_t  b, *pb;
1395     int         i, *pi;
1396
1397     es_out_id_t *es;
1398
1399     switch( i_query )
1400     {
1401         case ES_OUT_SET_ES_STATE:
1402             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1403             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1404             if( b && es->p_dec == NULL )
1405             {
1406                 EsSelect( out, es );
1407                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
1408             }
1409             else if( !b && es->p_dec )
1410             {
1411                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1412                 return VLC_SUCCESS;
1413             }
1414             return VLC_SUCCESS;
1415
1416         case ES_OUT_GET_ES_STATE:
1417             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1418             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1419
1420             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
1421             return VLC_SUCCESS;
1422
1423         case ES_OUT_SET_ACTIVE:
1424         {
1425             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1426             p_sys->b_active = b;
1427             /* Needed ? */
1428             if( b )
1429                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1430             return VLC_SUCCESS;
1431         }
1432
1433         case ES_OUT_GET_ACTIVE:
1434             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1435             *pb = p_sys->b_active;
1436             return VLC_SUCCESS;
1437
1438         case ES_OUT_SET_MODE:
1439             i = (int) va_arg( args, int );
1440             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1441                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1442             {
1443                 p_sys->i_mode = i;
1444
1445                 /* Reapply policy mode */
1446                 for( i = 0; i < p_sys->i_es; i++ )
1447                 {
1448                     if( p_sys->es[i]->p_dec )
1449                     {
1450                         EsUnselect( out, p_sys->es[i],
1451                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1452                     }
1453                 }
1454                 for( i = 0; i < p_sys->i_es; i++ )
1455                 {
1456                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1457                 }
1458                 return VLC_SUCCESS;
1459             }
1460             return VLC_EGENERIC;
1461
1462         case ES_OUT_GET_MODE:
1463             pi = (int*) va_arg( args, int* );
1464             *pi = p_sys->i_mode;
1465             return VLC_SUCCESS;
1466
1467         case ES_OUT_SET_ES:
1468             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1469             /* Special case NULL, NULL+i_cat */
1470             if( es == NULL )
1471             {
1472                 for( i = 0; i < p_sys->i_es; i++ )
1473                 {
1474                     if( p_sys->es[i]->p_dec )
1475                         EsUnselect( out, p_sys->es[i],
1476                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1477                 }
1478             }
1479             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1480             {
1481                 for( i = 0; i < p_sys->i_es; i++ )
1482                 {
1483                     if( p_sys->es[i]->p_dec &&
1484                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
1485                         EsUnselect( out, p_sys->es[i],
1486                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1487                 }
1488             }
1489             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1490             {
1491                 for( i = 0; i < p_sys->i_es; i++ )
1492                 {
1493                     if( p_sys->es[i]->p_dec &&
1494                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
1495                         EsUnselect( out, p_sys->es[i],
1496                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1497                 }
1498             }
1499             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1500             {
1501                 for( i = 0; i < p_sys->i_es; i++ )
1502                 {
1503                     if( p_sys->es[i]->p_dec &&
1504                         p_sys->es[i]->fmt.i_cat == SPU_ES )
1505                         EsUnselect( out, p_sys->es[i],
1506                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1507                 }
1508             }
1509             else
1510             {
1511                 for( i = 0; i < p_sys->i_es; i++ )
1512                 {
1513                     if( es == p_sys->es[i] )
1514                     {
1515                         EsOutSelect( out, es, VLC_TRUE );
1516                         break;
1517                     }
1518                 }
1519             }
1520             {
1521                 playlist_t * p_playlist = pl_Yield( p_sys->p_input );
1522                 PL_LOCK;
1523                 p_playlist->gc_date = mdate();
1524                 vlc_object_signal_unlocked( p_playlist );
1525                 PL_UNLOCK;
1526                 pl_Release( p_playlist );
1527             }
1528             return VLC_SUCCESS;
1529  
1530         case ES_OUT_SET_DEFAULT:
1531         {
1532             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1533
1534             if( es == NULL )
1535             {
1536                 /*p_sys->i_default_video_id = -1;*/
1537                 /*p_sys->i_default_audio_id = -1;*/
1538                 p_sys->i_default_sub_id = -1;
1539             }
1540             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1541             {
1542                 /*p_sys->i_default_video_id = -1;*/
1543             }
1544             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1545             {
1546                 /*p_sys->i_default_audio_id = -1;*/
1547             }
1548             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1549             {
1550                 p_sys->i_default_sub_id = -1;
1551             }
1552             else
1553             {
1554                 /*if( es->fmt.i_cat == VIDEO_ES )
1555                     p_sys->i_default_video_id = es->i_id;
1556                 else
1557                 if( es->fmt.i_cat == AUDIO_ES )
1558                     p_sys->i_default_audio_id = es->i_id;
1559                 else*/
1560                 if( es->fmt.i_cat == SPU_ES )
1561                     p_sys->i_default_sub_id = es->i_id;
1562             }
1563             return VLC_SUCCESS;
1564         }
1565
1566         case ES_OUT_SET_PCR:
1567         case ES_OUT_SET_GROUP_PCR:
1568         {
1569             es_out_pgrm_t *p_pgrm = NULL;
1570             int            i_group = 0;
1571             int64_t        i_pcr;
1572
1573             if( i_query == ES_OUT_SET_PCR )
1574             {
1575                 p_pgrm = p_sys->p_pgrm;
1576             }
1577             else
1578             {
1579                 int i;
1580                 i_group = (int)va_arg( args, int );
1581                 for( i = 0; i < p_sys->i_pgrm; i++ )
1582                 {
1583                     if( p_sys->pgrm[i]->i_id == i_group )
1584                     {
1585                         p_pgrm = p_sys->pgrm[i];
1586                         break;
1587                     }
1588                 }
1589             }
1590             if( p_pgrm == NULL )
1591                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
1592
1593             i_pcr = (int64_t)va_arg( args, int64_t );
1594             /* search program */
1595             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr );
1596             return VLC_SUCCESS;
1597         }
1598
1599         case ES_OUT_RESET_PCR:
1600             for( i = 0; i < p_sys->i_pgrm; i++ )
1601             {
1602                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
1603                 p_sys->pgrm[i]->clock.last_pts = 0;
1604             }
1605             return VLC_SUCCESS;
1606
1607         case ES_OUT_GET_TS:
1608             if( p_sys->p_pgrm )
1609             {
1610                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1611                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1612                 *pi_ts = input_ClockGetTS( p_sys->p_input,
1613                                            &p_sys->p_pgrm->clock, i_ts );
1614                 return VLC_SUCCESS;
1615             }
1616             return VLC_EGENERIC;
1617
1618         case ES_OUT_GET_GROUP:
1619             pi = (int*) va_arg( args, int* );
1620             if( p_sys->p_pgrm )
1621                 *pi = p_sys->p_pgrm->i_id;
1622             else
1623                 *pi = -1;    /* FIXME */
1624             return VLC_SUCCESS;
1625
1626         case ES_OUT_SET_GROUP:
1627         {
1628             int j;
1629             i = (int) va_arg( args, int );
1630             for( j = 0; j < p_sys->i_pgrm; j++ )
1631             {
1632                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1633                 if( p_pgrm->i_id == i )
1634                 {
1635                     EsOutProgramSelect( out, p_pgrm );
1636                     return VLC_SUCCESS;
1637                 }
1638             }
1639             return VLC_EGENERIC;
1640         }
1641
1642         case ES_OUT_SET_FMT:
1643         {
1644             /* This ain't pretty but is need by some demuxers (eg. Ogg )
1645              * to update the p_extra data */
1646             es_format_t *p_fmt;
1647             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1648             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1649             if( es == NULL ) return VLC_EGENERIC;
1650
1651             if( p_fmt->i_extra )
1652             {
1653                 es->fmt.i_extra = p_fmt->i_extra;
1654                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1655                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1656
1657                 if( !es->p_dec ) return VLC_SUCCESS;
1658
1659 #if 1
1660                 input_DecoderDelete( es->p_dec );
1661                 es->p_dec = input_DecoderNew( p_sys->p_input,
1662                                               &es->fmt, VLC_FALSE );
1663
1664 #else
1665                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1666                 es->p_dec->fmt_in.p_extra =
1667                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1668                 memcpy( es->p_dec->fmt_in.p_extra,
1669                         p_fmt->p_extra, p_fmt->i_extra );
1670 #endif
1671             }
1672
1673             return VLC_SUCCESS;
1674         }
1675
1676         case ES_OUT_SET_NEXT_DISPLAY_TIME:
1677         {
1678             int64_t i_date;
1679
1680             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1681             i_date = (int64_t)va_arg( args, int64_t );
1682
1683             if( !es || !es->p_dec )
1684                 return VLC_EGENERIC;
1685
1686             /* XXX We should call input_ClockGetTS but PCR has been reseted
1687              * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
1688              * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
1689             es->i_preroll_end = i_date;
1690
1691             return VLC_SUCCESS;
1692         }
1693         case ES_OUT_SET_GROUP_META:
1694         {
1695             int i_group = (int)va_arg( args, int );
1696             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1697
1698             EsOutProgramMeta( out, i_group, p_meta );
1699             return VLC_SUCCESS;
1700         }
1701         case ES_OUT_SET_GROUP_EPG:
1702         {
1703             int i_group = (int)va_arg( args, int );
1704             vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1705
1706             EsOutProgramEpg( out, i_group, p_epg );
1707             return VLC_SUCCESS;
1708         }
1709         case ES_OUT_DEL_GROUP:
1710         {
1711             int i_group = (int)va_arg( args, int );
1712
1713             return EsOutProgramDel( out, i_group );
1714         }
1715
1716         default:
1717             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1718             return VLC_EGENERIC;
1719     }
1720 }
1721
1722 /****************************************************************************
1723  * LanguageGetName: try to expend iso639 into plain name
1724  ****************************************************************************/
1725 static char *LanguageGetName( const char *psz_code )
1726 {
1727     const iso639_lang_t *pl;
1728
1729     if( psz_code == NULL )
1730     {
1731         return strdup( "" );
1732     }
1733
1734     if( strlen( psz_code ) == 2 )
1735     {
1736         pl = GetLang_1( psz_code );
1737     }
1738     else if( strlen( psz_code ) == 3 )
1739     {
1740         pl = GetLang_2B( psz_code );
1741         if( !strcmp( pl->psz_iso639_1, "??" ) )
1742         {
1743             pl = GetLang_2T( psz_code );
1744         }
1745     }
1746     else
1747     {
1748         return strdup( psz_code );
1749     }
1750
1751     if( !strcmp( pl->psz_iso639_1, "??" ) )
1752     {
1753        return strdup( psz_code );
1754     }
1755     else
1756     {
1757         if( *pl->psz_native_name )
1758         {
1759             return strdup( pl->psz_native_name );
1760         }
1761         return strdup( pl->psz_eng_name );
1762     }
1763 }
1764
1765 /* Get a 2 char code */
1766 static char *LanguageGetCode( const char *psz_lang )
1767 {
1768     const iso639_lang_t *pl;
1769
1770     if( psz_lang == NULL || *psz_lang == '\0' )
1771         return strdup("??");
1772
1773     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1774     {
1775         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1776             !strcasecmp( pl->psz_native_name, psz_lang ) ||
1777             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1778             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1779             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1780             break;
1781     }
1782
1783     if( pl->psz_iso639_1 != NULL )
1784         return strdup( pl->psz_iso639_1 );
1785
1786     return strdup("??");
1787 }
1788
1789 static char **LanguageSplit( const char *psz_langs )
1790 {
1791     char *psz_dup;
1792     char *psz_parser;
1793     char **ppsz = NULL;
1794     int i_psz = 0;
1795
1796     if( psz_langs == NULL ) return NULL;
1797
1798     psz_parser = psz_dup = strdup(psz_langs);
1799
1800     while( psz_parser && *psz_parser )
1801     {
1802         char *psz;
1803         char *psz_code;
1804
1805         psz = strchr(psz_parser, ',' );
1806         if( psz ) *psz++ = '\0';
1807
1808         psz_code = LanguageGetCode( psz_parser );
1809         if( strcmp( psz_code, "??" ) )
1810         {
1811             TAB_APPEND( i_psz, ppsz, psz_code );
1812         }
1813
1814         psz_parser = psz;
1815     }
1816
1817     if( i_psz )
1818     {
1819         TAB_APPEND( i_psz, ppsz, NULL );
1820     }
1821
1822     free( psz_dup );
1823     return ppsz;
1824 }
1825
1826 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1827 {
1828     int i;
1829
1830     if( !ppsz_langs || !psz_lang ) return -1;
1831
1832     for( i = 0; ppsz_langs[i]; i++ )
1833         if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i;
1834
1835     return -1;
1836 }
1837
1838 /****************************************************************************
1839  * EsOutAddInfo:
1840  * - add meta info to the playlist item
1841  ****************************************************************************/
1842 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1843 {
1844     es_out_sys_t   *p_sys = out->p_sys;
1845     input_thread_t *p_input = p_sys->p_input;
1846     es_format_t    *fmt = &es->fmt;
1847     char           *psz_cat;
1848     lldiv_t         div;
1849
1850     /* Add stream info */
1851     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1852
1853     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1854                    "%.4s", (char*)&fmt->i_codec );
1855
1856     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1857                    "%s", es->psz_language );
1858
1859     /* Add information */
1860     switch( fmt->i_cat )
1861     {
1862     case AUDIO_ES:
1863         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1864                        _("Type"), _("Audio") );
1865
1866         if( fmt->audio.i_channels > 0 )
1867             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1868                            "%u", fmt->audio.i_channels );
1869
1870         if( fmt->audio.i_rate > 0 )
1871         {
1872             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
1873                            _("%u Hz"), fmt->audio.i_rate );
1874             var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
1875         }
1876
1877         if( fmt->audio.i_bitspersample > 0 )
1878             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1879                            _("Bits per sample"), "%u",
1880                            fmt->audio.i_bitspersample );
1881
1882         if( fmt->i_bitrate > 0 )
1883         {
1884             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
1885                            _("%u kb/s"), fmt->i_bitrate / 1000 );
1886             var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
1887         }
1888         break;
1889
1890     case VIDEO_ES:
1891         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1892                        _("Type"), _("Video") );
1893
1894         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
1895             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1896                            _("Resolution"), "%ux%u",
1897                            fmt->video.i_width, fmt->video.i_height );
1898
1899         if( fmt->video.i_visible_width > 0 &&
1900             fmt->video.i_visible_height > 0 )
1901             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1902                            _("Display resolution"), "%ux%u",
1903                            fmt->video.i_visible_width,
1904                            fmt->video.i_visible_height);
1905        if( fmt->video.i_frame_rate > 0 &&
1906            fmt->video.i_frame_rate_base > 0 )
1907        {
1908            div = lldiv( (float)fmt->video.i_frame_rate /
1909                                fmt->video.i_frame_rate_base * 1000000,
1910                                1000000 );
1911            input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1912                           _("Frame rate"), I64Fd".%06u",
1913                           div.quot, (unsigned int )div.rem );
1914        }
1915        break;
1916
1917     case SPU_ES:
1918         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1919                        _("Type"), _("Subtitle") );
1920         break;
1921
1922     default:
1923         break;
1924     }
1925
1926     free( psz_cat );
1927 }