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