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