1 /*****************************************************************************
2 * es_out.c: Es Out handler for input.
3 *****************************************************************************
4 * Copyright (C) 2003-2004 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_input.h>
33 #include <vlc_es_out.h>
34 #include <vlc_block.h>
37 #include "input_internal.h"
39 #include "vlc_playlist.h"
41 /* FIXME we should find a better way than including that */
42 #include "../text/iso-639_def.h"
44 /*****************************************************************************
46 *****************************************************************************/
52 /* Number of es for this pgrm */
55 vlc_bool_t b_selected;
57 /* Clock for this program */
61 char *psz_now_playing;
71 es_out_pgrm_t *p_pgrm;
74 int64_t i_preroll_end;
76 /* Channel in the track type */
80 char *psz_language_code;
84 /* Fields for Video with CC */
85 vlc_bool_t pb_cc_present[4];
86 es_out_id_t *pp_cc_es[4];
88 /* Field for CC track from a master video */
89 es_out_id_t *p_master;
94 input_thread_t *p_input;
99 es_out_pgrm_t **pp_selected_pgrm; /* --programs */
100 es_out_pgrm_t *p_pgrm; /* Master program */
117 int i_audio_last, i_audio_id;
118 int i_sub_last, i_sub_id;
119 int i_default_sub_id; /* As specified in container; if applicable */
120 char **ppsz_audio_language;
121 char **ppsz_sub_language;
123 /* current main es */
124 es_out_id_t *p_es_audio;
125 es_out_id_t *p_es_video;
126 es_out_id_t *p_es_sub;
129 int64_t i_audio_delay;
133 static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );
134 static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
135 static void EsOutDel ( es_out_t *, es_out_id_t * );
136 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
137 static int EsOutControl( es_out_t *, int i_query, va_list );
139 static void EsOutAddInfo( es_out_t *, es_out_id_t *es );
141 static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es );
142 static void EsSelect( es_out_t *out, es_out_id_t *es );
143 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
144 static char *LanguageGetName( const char *psz_code );
145 static char *LanguageGetCode( const char *psz_lang );
146 static char **LanguageSplit( const char *psz_langs );
147 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
149 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
151 /*****************************************************************************
153 *****************************************************************************/
154 es_out_t *input_EsOutNew( input_thread_t *p_input )
156 es_out_t *out = malloc( sizeof( es_out_t ) );
157 es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
161 out->pf_add = EsOutAdd;
162 out->pf_send = EsOutSend;
163 out->pf_del = EsOutDel;
164 out->pf_control = EsOutControl;
166 out->b_sout = (p_input->p->p_sout != NULL ? VLC_TRUE : VLC_FALSE);
168 p_sys->p_input = p_input;
170 p_sys->b_active = VLC_FALSE;
171 p_sys->i_mode = ES_OUT_MODE_AUTO;
174 TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
175 p_sys->p_pgrm = NULL;
179 TAB_INIT( p_sys->i_es, p_sys->es );
186 var_Get( p_input, "audio-track", &val );
187 p_sys->i_audio_last = val.i_int;
189 var_Get( p_input, "sub-track", &val );
190 p_sys->i_sub_last = val.i_int;
192 p_sys->i_default_sub_id = -1;
194 if( !p_input->b_preparsing )
196 var_Get( p_input, "audio-language", &val );
197 p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
198 if( p_sys->ppsz_audio_language )
200 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
201 msg_Dbg( p_input, "selected audio language[%d] %s",
202 i, p_sys->ppsz_audio_language[i] );
204 if( val.psz_string ) free( val.psz_string );
206 var_Get( p_input, "sub-language", &val );
207 p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
208 if( p_sys->ppsz_sub_language )
210 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
211 msg_Dbg( p_input, "selected subtitle language[%d] %s",
212 i, p_sys->ppsz_sub_language[i] );
214 if( val.psz_string ) free( val.psz_string );
218 p_sys->ppsz_sub_language = NULL;
219 p_sys->ppsz_audio_language = NULL;
222 var_Get( p_input, "audio-track-id", &val );
223 p_sys->i_audio_id = val.i_int;
225 var_Get( p_input, "sub-track-id", &val );
226 p_sys->i_sub_id = val.i_int;
228 p_sys->p_es_audio = NULL;
229 p_sys->p_es_video = NULL;
230 p_sys->p_es_sub = NULL;
232 p_sys->i_audio_delay= 0;
233 p_sys->i_spu_delay = 0;
238 /*****************************************************************************
240 *****************************************************************************/
241 void input_EsOutDelete( es_out_t *out )
243 es_out_sys_t *p_sys = out->p_sys;
246 for( i = 0; i < p_sys->i_es; i++ )
248 if( p_sys->es[i]->p_dec )
250 input_DecoderDelete( p_sys->es[i]->p_dec );
252 if( p_sys->es[i]->psz_language )
253 free( p_sys->es[i]->psz_language );
254 if( p_sys->es[i]->psz_language_code )
255 free( p_sys->es[i]->psz_language_code );
256 es_format_Clean( &p_sys->es[i]->fmt );
258 free( p_sys->es[i] );
260 if( p_sys->ppsz_audio_language )
262 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
263 free( p_sys->ppsz_audio_language[i] );
264 free( p_sys->ppsz_audio_language );
266 if( p_sys->ppsz_sub_language )
268 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
269 free( p_sys->ppsz_sub_language[i] );
270 free( p_sys->ppsz_sub_language );
276 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
277 for( i = 0; i < p_sys->i_pgrm; i++ )
279 es_out_pgrm_t *p_pgrm = p_sys->pgrm[i];
280 if( p_pgrm->psz_now_playing )
281 free( p_pgrm->psz_now_playing );
282 if( p_pgrm->psz_publisher )
283 free( p_pgrm->psz_publisher );
284 if( p_pgrm->psz_name )
285 free( p_pgrm->psz_name );
287 vlc_epg_Delete( p_pgrm->p_epg );
291 TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
297 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
302 /* Special HACK, -i_id is tha cat of the stream */
303 return (es_out_id_t*)((uint8_t*)NULL-i_id);
306 for( i = 0; i < out->p_sys->i_es; i++ )
308 if( out->p_sys->es[i]->i_id == i_id )
309 return out->p_sys->es[i];
314 static void EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio )
316 es_out_sys_t *p_sys = out->p_sys;
319 for( i = 0; i < p_sys->i_es; i++ )
321 es_out_id_t *es = p_sys->es[i];
323 /* Send a dummy block to let decoder know that
324 * there is a discontinuity */
325 if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
326 input_DecoderDiscontinuity( es->p_dec, b_flush );
329 void input_EsOutChangeRate( es_out_t *out )
331 es_out_sys_t *p_sys = out->p_sys;
334 EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE );
336 for( i = 0; i < p_sys->i_pgrm; i++ )
337 input_ClockSetRate( p_sys->p_input, &p_sys->pgrm[i]->clock );
340 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
342 es_out_sys_t *p_sys = out->p_sys;
344 if( i_cat == AUDIO_ES )
345 p_sys->i_audio_delay = i_delay;
346 else if( i_cat == SPU_ES )
347 p_sys->i_spu_delay = i_delay;
349 void input_EsOutChangeState( es_out_t *out )
351 es_out_sys_t *p_sys = out->p_sys;
352 input_thread_t *p_input = p_sys->p_input;
354 if( p_input->i_state == PAUSE_S )
356 /* Send discontinuity to decoders (it will allow them to flush
357 * * if implemented */
358 EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE );
362 /* Out of pause, reset pcr */
363 es_out_Control( out, ES_OUT_RESET_PCR );
366 void input_EsOutChangePosition( es_out_t *out )
368 //es_out_sys_t *p_sys = out->p_sys;
370 es_out_Control( out, ES_OUT_RESET_PCR );
371 EsOutDiscontinuity( out, VLC_TRUE, VLC_FALSE );
374 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
376 es_out_sys_t *p_sys = out->p_sys;
379 for( i = 0; i < p_sys->i_es; i++ )
381 es_out_id_t *es = p_sys->es[i];
383 if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
389 /*****************************************************************************
391 *****************************************************************************/
392 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
393 vlc_bool_t b_delete )
395 es_out_sys_t *p_sys = out->p_sys;
396 input_thread_t *p_input = p_sys->p_input;
397 vlc_value_t val, text;
401 if( fmt->i_cat == AUDIO_ES )
402 psz_var = "audio-es";
403 else if( fmt->i_cat == VIDEO_ES )
404 psz_var = "video-es";
405 else if( fmt->i_cat == SPU_ES )
413 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
414 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
418 /* Get the number of ES already added */
419 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
424 /* First one, we need to add the "Disable" choice */
425 val2.i_int = -1; text.psz_string = _("Disable");
426 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
430 /* Take care of the ES description */
431 if( fmt->psz_description && *fmt->psz_description )
433 if( psz_language && *psz_language )
435 text.psz_string = malloc( strlen( fmt->psz_description) +
436 strlen( psz_language ) + 10 );
437 sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
440 else text.psz_string = strdup( fmt->psz_description );
444 if( psz_language && *psz_language )
447 text.psz_string = malloc( strlen( _("Track %i") )+
448 strlen( psz_language ) + 30 );
449 asprintf( &temp, _("Track %i"), val.i_int );
450 sprintf( text.psz_string, "%s - [%s]", temp, psz_language );
455 text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
456 sprintf( text.psz_string, _("Track %i"), val.i_int );
461 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
463 free( text.psz_string );
465 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
468 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
469 vlc_bool_t b_delete )
471 EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
474 /* EsOutProgramSelect:
475 * Select a program and update the object variable
477 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
479 es_out_sys_t *p_sys = out->p_sys;
480 input_thread_t *p_input = p_sys->p_input;
484 if( p_sys->p_pgrm == p_pgrm )
485 return; /* Nothing to do */
489 es_out_pgrm_t *old = p_sys->p_pgrm;
490 msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
492 for( i = 0; i < p_sys->i_es; i++ )
494 if( p_sys->es[i]->p_pgrm == old && EsIsSelected( out, p_sys->es[i] ) &&
495 p_sys->i_mode != ES_OUT_MODE_ALL )
496 EsUnselect( out, p_sys->es[i], VLC_TRUE );
499 p_sys->p_es_audio = NULL;
500 p_sys->p_es_sub = NULL;
501 p_sys->p_es_video = NULL;
504 msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
506 /* Mark it selected */
507 p_pgrm->b_selected = VLC_TRUE;
509 /* Switch master stream */
510 if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
512 p_sys->p_pgrm->clock.b_master = VLC_FALSE;
514 p_pgrm->clock.b_master = VLC_TRUE;
515 p_sys->p_pgrm = p_pgrm;
517 /* Update "program" */
518 val.i_int = p_pgrm->i_id;
519 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
522 var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
523 var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
524 var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
525 for( i = 0; i < p_sys->i_es; i++ )
527 if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
528 EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
529 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
532 /* Update now playing */
533 input_item_SetNowPlaying( p_input->p->input.p_item,
534 p_pgrm->psz_now_playing );
535 input_item_SetPublisher( p_input->p->input.p_item,
536 p_pgrm->psz_publisher );
538 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
544 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
546 es_out_sys_t *p_sys = out->p_sys;
547 input_thread_t *p_input = p_sys->p_input;
550 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
553 p_pgrm->i_id = i_group;
555 p_pgrm->b_selected = VLC_FALSE;
556 p_pgrm->psz_name = NULL;
557 p_pgrm->psz_now_playing = NULL;
558 p_pgrm->psz_publisher = NULL;
559 p_pgrm->p_epg = NULL;
560 input_ClockInit( p_input, &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average );
563 TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
565 /* Update "program" variable */
567 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
569 if( i_group == var_GetInteger( p_input, "program" ) )
571 EsOutProgramSelect( out, p_pgrm );
575 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
583 static int EsOutProgramDel( es_out_t *out, int i_group )
585 es_out_sys_t *p_sys = out->p_sys;
586 input_thread_t *p_input = p_sys->p_input;
587 es_out_pgrm_t *p_pgrm = NULL;
591 for( i = 0; i < p_sys->i_pgrm; i++ )
593 if( p_sys->pgrm[i]->i_id == i_group )
595 p_pgrm = p_sys->pgrm[i];
605 msg_Dbg( p_input, "can't delete program %d which still has %i ES",
606 i_group, p_pgrm->i_es );
610 TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
612 /* If program is selected we need to unselect it */
613 if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL;
615 if( p_pgrm->psz_name ) free( p_pgrm->psz_name );
616 if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
617 if( p_pgrm->psz_publisher ) free( p_pgrm->psz_publisher );
619 vlc_epg_Delete( p_pgrm->p_epg );
622 /* Update "program" variable */
624 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
626 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
633 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
636 if( p_pgrm->psz_name )
637 asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id );
639 asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id );
643 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
645 es_out_sys_t *p_sys = out->p_sys;
646 es_out_pgrm_t *p_pgrm = NULL;
647 input_thread_t *p_input = p_sys->p_input;
649 const char *psz_title = NULL;
650 const char *psz_provider = NULL;
653 msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
655 /* Check against empty meta data (empty for what we handle) */
656 if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
657 !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
658 !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
659 vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
662 for( i = 0; i < p_sys->i_pgrm; i++ )
664 if( p_sys->pgrm[i]->i_id == i_group )
666 p_pgrm = p_sys->pgrm[i];
671 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
674 psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
675 psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
677 /* Update the description text of the program */
678 if( psz_title && *psz_title )
683 if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
685 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
687 /* Remove old entries */
688 input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
689 /* TODO update epg name */
692 if( p_pgrm->psz_name ) free( p_pgrm->psz_name );
693 p_pgrm->psz_name = strdup( psz_title );
695 /* ugly but it works */
697 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
699 if( psz_provider && *psz_provider )
701 asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider );
702 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
703 free( text.psz_string );
707 text.psz_string = (char *)psz_title;
708 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
712 psz_cat = EsOutProgramGetMetaName( p_pgrm );
715 if( p_sys->p_pgrm == p_pgrm )
716 input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
717 input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
719 char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
720 for( i = 0; ppsz_all_keys[i]; i++ )
722 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
723 vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
724 free( ppsz_all_keys[i] );
726 free( ppsz_all_keys );
731 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
736 for( i = 0; i < p_src->i_event; i++ )
738 vlc_epg_event_t *p_evt = p_src->pp_event[i];
739 vlc_bool_t b_add = VLC_TRUE;
742 for( j = 0; j < p_dst->i_event; j++ )
744 if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
749 if( p_dst->pp_event[j]->i_start > p_evt->i_start )
754 vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
757 memset( p_copy, 0, sizeof(vlc_epg_event_t) );
758 p_copy->i_start = p_evt->i_start;
759 p_copy->i_duration = p_evt->i_duration;
760 p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
761 p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
762 p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
763 TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
767 vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
769 /* Keep only 1 old event */
770 if( p_dst->p_current )
772 while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
773 TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
777 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
779 es_out_sys_t *p_sys = out->p_sys;
780 input_thread_t *p_input = p_sys->p_input;
781 es_out_pgrm_t *p_pgrm = NULL;
786 for( i = 0; i < p_sys->i_pgrm; i++ )
788 if( p_sys->pgrm[i]->i_id == i_group )
790 p_pgrm = p_sys->pgrm[i];
795 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
799 p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
800 vlc_epg_Merge( p_pgrm->p_epg, p_epg );
803 psz_cat = EsOutProgramGetMetaName( p_pgrm );
804 #ifdef HAVE_LOCALTIME_R
806 if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
808 input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
809 msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
810 for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
812 const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
813 time_t t_start = (time_t)p_evt->i_start;
817 localtime_r( &t_start, &tm_start );
819 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
820 if( p_evt->psz_short_description || p_evt->psz_description )
821 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
823 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
824 p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
826 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
828 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
832 /* Update now playing */
833 if( p_pgrm->psz_now_playing )
834 free( p_pgrm->psz_now_playing );
835 p_pgrm->psz_now_playing = NULL;
836 if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
837 p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
839 if( p_pgrm == p_sys->p_pgrm )
840 input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
842 if( p_pgrm->psz_now_playing )
844 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
845 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
846 p_pgrm->psz_now_playing );
850 input_Control( p_input, INPUT_DEL_INFO, psz_cat,
851 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
860 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
862 es_out_sys_t *p_sys = out->p_sys;
863 input_thread_t *p_input = p_sys->p_input;
865 es_out_id_t *es = malloc( sizeof( es_out_id_t ) );
866 es_out_pgrm_t *p_pgrm = NULL;
869 if( fmt->i_group < 0 )
871 msg_Err( p_input, "invalid group number" );
875 /* Search the program */
876 for( i = 0; i < p_sys->i_pgrm; i++ )
878 if( fmt->i_group == p_sys->pgrm[i]->i_id )
880 p_pgrm = p_sys->pgrm[i];
886 /* Create a new one */
887 p_pgrm = EsOutProgramAdd( out, fmt->i_group );
890 /* Increase ref count for program */
895 fmt->i_id = out->p_sys->i_id;
896 es->i_id = fmt->i_id;
898 es_format_Copy( &es->fmt, fmt );
899 es->i_preroll_end = -1;
905 audio_replay_gain_t rg;
907 es->i_channel = p_sys->i_audio;
909 vlc_mutex_lock( &p_input->p->input.p_item->lock );
910 memset( &rg, 0, sizeof(rg) );
911 vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
912 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
914 for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
916 if( !es->fmt.audio_replay_gain.pb_peak[i] )
918 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
919 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
921 if( !es->fmt.audio_replay_gain.pb_gain[i] )
923 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
924 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
931 es->i_channel = p_sys->i_video;
932 if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
933 vlc_ureduce( &es->fmt.video.i_frame_rate,
934 &es->fmt.video.i_frame_rate_base,
935 fmt->video.i_frame_rate,
936 fmt->video.i_frame_rate_base, 0 );
940 es->i_channel = p_sys->i_sub;
947 es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
948 es->psz_language_code = LanguageGetCode( fmt->psz_language );
950 for( i = 0; i < 4; i++ )
951 es->pb_cc_present[i] = VLC_FALSE;
952 es->p_master = VLC_FALSE;
954 if( es->p_pgrm == p_sys->p_pgrm )
955 EsOutESVarUpdate( out, es, VLC_FALSE );
957 /* Select it if needed */
958 EsOutSelect( out, es, VLC_FALSE );
961 TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
962 p_sys->i_id++; /* always incremented */
976 EsOutAddInfo( out, es );
981 static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es )
985 vlc_bool_t b_decode = VLC_FALSE;
986 if( es->p_master->p_dec )
987 input_DecoderGetCcState( es->p_master->p_dec, &b_decode,
988 es->fmt.i_codec == VLC_FOURCC('c','c','1',' ') ? 0 : 1 );
993 return es->p_dec != NULL;
996 static void EsSelect( es_out_t *out, es_out_id_t *es )
998 es_out_sys_t *p_sys = out->p_sys;
999 input_thread_t *p_input = p_sys->p_input;
1001 const char *psz_var;
1003 if( EsIsSelected( out, es ) )
1005 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1011 if( !es->p_master->p_dec )
1014 if( input_DecoderSetCcState( es->p_master->p_dec, VLC_TRUE,
1015 es->fmt.i_codec == VLC_FOURCC('c','c','1',' ') ? 0 : 1 ) )
1020 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1022 if( !var_GetBool( p_input, "video" ) ||
1023 ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
1025 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1030 else if( es->fmt.i_cat == AUDIO_ES )
1032 var_Get( p_input, "audio", &val );
1033 if( !var_GetBool( p_input, "audio" ) ||
1034 ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
1036 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1041 if( es->fmt.i_cat == SPU_ES )
1043 var_Get( p_input, "spu", &val );
1044 if( !var_GetBool( p_input, "spu" ) ||
1045 ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) )
1047 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1053 es->i_preroll_end = -1;
1054 es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
1055 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1059 if( es->fmt.i_cat == VIDEO_ES )
1060 psz_var = "video-es";
1061 else if( es->fmt.i_cat == AUDIO_ES )
1062 psz_var = "audio-es";
1063 else if( es->fmt.i_cat == SPU_ES )
1068 /* Mark it as selected */
1069 val.i_int = es->i_id;
1070 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1072 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1075 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
1077 es_out_sys_t *p_sys = out->p_sys;
1078 input_thread_t *p_input = p_sys->p_input;
1080 const char *psz_var;
1082 if( !EsIsSelected( out, es ) )
1084 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1090 if( es->p_master->p_dec )
1091 input_DecoderSetCcState( es->p_master->p_dec, VLC_FALSE, es->fmt.i_codec == VLC_FOURCC('c','c','1',' ') ? 0 : 1 );
1095 const int i_spu_id = var_GetInteger( p_input, "spu-es");
1097 for( i = 0; i < 4; i++ )
1099 if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1102 if( i_spu_id == es->pp_cc_es[i]->i_id )
1104 /* Force unselection of the CC */
1106 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1108 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1110 EsOutDel( out, es->pp_cc_es[i] );
1112 es->pb_cc_present[i] = VLC_FALSE;
1114 input_DecoderDelete( es->p_dec );
1122 if( es->p_dec == NULL )
1124 if( es->fmt.i_cat == VIDEO_ES )
1125 psz_var = "video-es";
1126 else if( es->fmt.i_cat == AUDIO_ES )
1127 psz_var = "audio-es";
1128 else if( es->fmt.i_cat == SPU_ES )
1133 /* Mark it as unselected */
1135 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1137 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1141 * Select an ES given the current mode
1142 * XXX: you need to take a the lock before (stream.stream_lock)
1144 * \param out The es_out structure
1145 * \param es es_out_id structure
1146 * \param b_force ...
1149 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
1151 es_out_sys_t *p_sys = out->p_sys;
1153 int i_cat = es->fmt.i_cat;
1155 if( !p_sys->b_active ||
1156 ( !b_force && es->fmt.i_priority < 0 ) )
1161 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1163 if( !EsIsSelected( out, es ) )
1164 EsSelect( out, es );
1166 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1170 var_Get( p_sys->p_input, "programs", &val );
1171 for ( i = 0; i < val.p_list->i_count; i++ )
1173 if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1175 if( !EsIsSelected( out, es ) )
1176 EsSelect( out, es );
1180 var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1182 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1186 if( es->p_pgrm != p_sys->p_pgrm )
1189 if( i_cat == AUDIO_ES )
1191 int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1192 es->psz_language_code );
1194 if( p_sys->p_es_audio &&
1195 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1197 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1198 p_sys->p_es_audio->psz_language_code );
1200 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1202 i_wanted = es->i_channel;
1206 /* Select audio if (no audio selected yet)
1207 * - no audio-language
1208 * - no audio code for the ES
1209 * - audio code in the requested list */
1211 !strcmp( es->psz_language_code, "??" ) ||
1212 !p_sys->ppsz_audio_language )
1213 i_wanted = es->i_channel;
1216 if( p_sys->i_audio_last >= 0 )
1217 i_wanted = p_sys->i_audio_last;
1219 if( p_sys->i_audio_id >= 0 )
1221 if( es->i_id == p_sys->i_audio_id )
1222 i_wanted = es->i_channel;
1227 else if( i_cat == SPU_ES )
1229 int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1230 es->psz_language_code );
1232 if( p_sys->p_es_sub &&
1233 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1235 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1236 p_sys->p_es_sub->psz_language_code );
1238 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1239 idx1, es->psz_language_code, idx2,
1240 p_sys->p_es_sub->psz_language_code );
1242 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1244 /* We found a SPU that matches our language request */
1245 i_wanted = es->i_channel;
1247 else if( idx1 >= 0 )
1249 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1250 idx1, es->psz_language_code );
1252 i_wanted = es->i_channel;
1254 else if( p_sys->i_default_sub_id >= 0 )
1256 if( es->i_id == p_sys->i_default_sub_id )
1257 i_wanted = es->i_channel;
1260 if( p_sys->i_sub_last >= 0 )
1261 i_wanted = p_sys->i_sub_last;
1263 if( p_sys->i_sub_id >= 0 )
1265 if( es->i_id == p_sys->i_sub_id )
1266 i_wanted = es->i_channel;
1271 else if( i_cat == VIDEO_ES )
1273 i_wanted = es->i_channel;
1276 if( i_wanted == es->i_channel && !EsIsSelected( out, es ) )
1277 EsSelect( out, es );
1280 /* FIXME TODO handle priority here */
1281 if( EsIsSelected( out, es ) )
1283 if( i_cat == AUDIO_ES )
1285 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1286 p_sys->p_es_audio &&
1287 p_sys->p_es_audio != es &&
1288 EsIsSelected( out, p_sys->p_es_audio ) )
1290 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
1292 p_sys->p_es_audio = es;
1294 else if( i_cat == SPU_ES )
1296 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1298 p_sys->p_es_sub != es &&
1299 EsIsSelected( out, p_sys->p_es_sub ) )
1301 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
1303 p_sys->p_es_sub = es;
1305 else if( i_cat == VIDEO_ES )
1307 p_sys->p_es_video = es;
1313 * Send a block for the given es_out
1315 * \param out the es_out to send from
1316 * \param es the es_out_id
1317 * \param p_block the data block to send
1319 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1321 es_out_sys_t *p_sys = out->p_sys;
1322 input_thread_t *p_input = p_sys->p_input;
1323 es_out_pgrm_t *p_pgrm = es->p_pgrm;
1327 if( es->fmt.i_cat == AUDIO_ES )
1328 i_delay = p_sys->i_audio_delay;
1329 else if( es->fmt.i_cat == SPU_ES )
1330 i_delay = p_sys->i_spu_delay;
1334 if( p_input->p_libvlc->b_stats )
1336 vlc_mutex_lock( &p_input->p->counters.counters_lock );
1337 stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1338 p_block->i_buffer, &i_total );
1339 stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1340 (float)i_total, NULL );
1341 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1344 /* Mark preroll blocks */
1345 if( es->i_preroll_end >= 0 )
1347 int64_t i_date = p_block->i_pts;
1349 i_date = p_block->i_dts;
1351 if( i_date < es->i_preroll_end )
1352 p_block->i_flags |= BLOCK_FLAG_PREROLL;
1354 es->i_preroll_end = -1;
1357 if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1359 p_block->i_dts += i_delay;
1361 else if( p_block->i_dts > 0 )
1364 input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay;
1366 if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1368 p_block->i_pts += i_delay;
1370 else if( p_block->i_pts > 0 )
1373 input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay;
1375 if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1377 mtime_t current_date = mdate();
1379 || p_block->i_pts > current_date + 10000000
1380 || current_date > p_block->i_pts )
1382 /* ETSI EN 300 472 Annex A : do not take into account the PTS
1383 * for teletext streams. */
1384 p_block->i_pts = current_date + 400000
1385 + p_input->i_pts_delay + i_delay;
1389 p_block->i_rate = p_input->p->i_rate;
1391 /* TODO handle mute */
1393 ( es->fmt.i_cat != AUDIO_ES ||
1394 ( p_input->p->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
1395 p_input->p->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
1397 vlc_bool_t pb_cc[4];
1398 vlc_bool_t b_cc_new = VLC_FALSE;
1400 input_DecoderDecode( es->p_dec, p_block );
1402 /* Check CC status */
1403 input_DecoderIsCcPresent( es->p_dec, pb_cc );
1404 for( i = 0; i < 4; i++ )
1406 static const vlc_fourcc_t fcc[4] = {
1407 VLC_FOURCC('c', 'c', '1', ' '),
1408 VLC_FOURCC('c', 'c', '2', ' '),
1409 VLC_FOURCC('c', 'c', '3', ' '),
1410 VLC_FOURCC('c', 'c', '4', ' '),
1412 static const char *ppsz_description[4] = {
1413 N_("Closed captions 1"),
1414 N_("Closed captions 2"),
1415 N_("Closed captions 3"),
1416 N_("Closed captions 4"),
1420 if( es->pb_cc_present[i] || !pb_cc[i] )
1422 msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
1424 es_format_Init( &fmt, SPU_ES, fcc[i] );
1425 fmt.i_group = es->fmt.i_group;
1426 fmt.psz_description = strdup( _(ppsz_description[i] ) );
1427 es->pp_cc_es[i] = EsOutAdd( out, &fmt );
1428 es->pp_cc_es[i]->p_master = es;
1429 es_format_Clean( &fmt );
1432 es->pb_cc_present[i] = VLC_TRUE;
1433 b_cc_new = VLC_TRUE;
1436 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1440 block_Release( p_block );
1446 /*****************************************************************************
1448 *****************************************************************************/
1449 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1451 es_out_sys_t *p_sys = out->p_sys;
1452 vlc_bool_t b_reselect = VLC_FALSE;
1455 /* We don't try to reselect */
1458 while( !out->p_sys->p_input->b_die && es->p_dec )
1460 if( input_DecoderEmpty( es->p_dec ) )
1464 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1467 if( es->p_pgrm == p_sys->p_pgrm )
1468 EsOutESVarUpdate( out, es, VLC_TRUE );
1470 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1473 if( es->p_pgrm->i_es == 0 )
1475 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1478 if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1479 p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
1481 if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1482 if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1483 if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
1485 switch( es->fmt.i_cat )
1498 /* Re-select another track when needed */
1500 for( i = 0; i < p_sys->i_es; i++ )
1502 if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1503 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1506 if( es->psz_language )
1507 free( es->psz_language );
1508 if( es->psz_language_code )
1509 free( es->psz_language_code );
1511 es_format_Clean( &es->fmt );
1517 * Control query handler
1519 * \param out the es_out to control
1520 * \param i_query A es_out query as defined in include/ninput.h
1521 * \param args a variable list of arguments for the query
1522 * \return VLC_SUCCESS or an error code
1524 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1526 es_out_sys_t *p_sys = out->p_sys;
1534 case ES_OUT_SET_ES_STATE:
1535 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1536 b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1537 if( b && !EsIsSelected( out, es ) )
1539 EsSelect( out, es );
1540 return EsIsSelected( out, es ) ? VLC_SUCCESS : VLC_EGENERIC;
1542 else if( !b && EsIsSelected( out, es ) )
1544 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1549 case ES_OUT_GET_ES_STATE:
1550 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1551 pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1553 *pb = EsIsSelected( out, es );
1556 case ES_OUT_SET_ACTIVE:
1558 b = (vlc_bool_t) va_arg( args, vlc_bool_t );
1559 p_sys->b_active = b;
1562 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
1566 case ES_OUT_GET_ACTIVE:
1567 pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
1568 *pb = p_sys->b_active;
1571 case ES_OUT_SET_MODE:
1572 i = (int) va_arg( args, int );
1573 if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1574 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1578 /* Reapply policy mode */
1579 for( i = 0; i < p_sys->i_es; i++ )
1581 if( EsIsSelected( out, p_sys->es[i] ) )
1583 EsUnselect( out, p_sys->es[i],
1584 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1587 for( i = 0; i < p_sys->i_es; i++ )
1589 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1593 return VLC_EGENERIC;
1595 case ES_OUT_GET_MODE:
1596 pi = (int*) va_arg( args, int* );
1597 *pi = p_sys->i_mode;
1601 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1602 /* Special case NULL, NULL+i_cat */
1605 for( i = 0; i < p_sys->i_es; i++ )
1607 if( EsIsSelected( out, p_sys->es[i] ) )
1608 EsUnselect( out, p_sys->es[i],
1609 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1612 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1614 for( i = 0; i < p_sys->i_es; i++ )
1616 if( p_sys->es[i]->fmt.i_cat == AUDIO_ES &&
1617 EsIsSelected( out, p_sys->es[i] ) )
1618 EsUnselect( out, p_sys->es[i],
1619 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1622 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1624 for( i = 0; i < p_sys->i_es; i++ )
1626 if( p_sys->es[i]->fmt.i_cat == VIDEO_ES &&
1627 EsIsSelected( out, p_sys->es[i] ) )
1628 EsUnselect( out, p_sys->es[i],
1629 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1632 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1634 for( i = 0; i < p_sys->i_es; i++ )
1636 if( p_sys->es[i]->fmt.i_cat == SPU_ES &&
1637 EsIsSelected( out, p_sys->es[i] ) )
1638 EsUnselect( out, p_sys->es[i],
1639 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1644 for( i = 0; i < p_sys->i_es; i++ )
1646 if( es == p_sys->es[i] )
1648 EsOutSelect( out, es, VLC_TRUE );
1654 playlist_t * p_playlist = pl_Yield( p_sys->p_input );
1656 p_playlist->gc_date = mdate();
1657 vlc_object_signal_unlocked( p_playlist );
1659 pl_Release( p_playlist );
1663 case ES_OUT_SET_DEFAULT:
1665 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1669 /*p_sys->i_default_video_id = -1;*/
1670 /*p_sys->i_default_audio_id = -1;*/
1671 p_sys->i_default_sub_id = -1;
1673 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1675 /*p_sys->i_default_video_id = -1;*/
1677 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1679 /*p_sys->i_default_audio_id = -1;*/
1681 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1683 p_sys->i_default_sub_id = -1;
1687 /*if( es->fmt.i_cat == VIDEO_ES )
1688 p_sys->i_default_video_id = es->i_id;
1690 if( es->fmt.i_cat == AUDIO_ES )
1691 p_sys->i_default_audio_id = es->i_id;
1693 if( es->fmt.i_cat == SPU_ES )
1694 p_sys->i_default_sub_id = es->i_id;
1699 case ES_OUT_SET_PCR:
1700 case ES_OUT_SET_GROUP_PCR:
1702 es_out_pgrm_t *p_pgrm = NULL;
1706 if( i_query == ES_OUT_SET_PCR )
1708 p_pgrm = p_sys->p_pgrm;
1713 i_group = (int)va_arg( args, int );
1714 for( i = 0; i < p_sys->i_pgrm; i++ )
1716 if( p_sys->pgrm[i]->i_id == i_group )
1718 p_pgrm = p_sys->pgrm[i];
1723 if( p_pgrm == NULL )
1724 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
1726 i_pcr = (int64_t)va_arg( args, int64_t );
1727 /* search program */
1728 input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr );
1732 case ES_OUT_RESET_PCR:
1733 for( i = 0; i < p_sys->i_pgrm; i++ )
1734 input_ClockResetPCR( p_sys->p_input, &p_sys->pgrm[i]->clock );
1740 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1741 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1742 *pi_ts = input_ClockGetTS( p_sys->p_input,
1743 &p_sys->p_pgrm->clock, i_ts );
1746 return VLC_EGENERIC;
1748 case ES_OUT_GET_GROUP:
1749 pi = (int*) va_arg( args, int* );
1751 *pi = p_sys->p_pgrm->i_id;
1753 *pi = -1; /* FIXME */
1756 case ES_OUT_SET_GROUP:
1759 i = (int) va_arg( args, int );
1760 for( j = 0; j < p_sys->i_pgrm; j++ )
1762 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1763 if( p_pgrm->i_id == i )
1765 EsOutProgramSelect( out, p_pgrm );
1769 return VLC_EGENERIC;
1772 case ES_OUT_SET_FMT:
1774 /* This ain't pretty but is need by some demuxers (eg. Ogg )
1775 * to update the p_extra data */
1777 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1778 p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1779 if( es == NULL ) return VLC_EGENERIC;
1781 if( p_fmt->i_extra )
1783 es->fmt.i_extra = p_fmt->i_extra;
1784 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1785 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1787 if( !es->p_dec ) return VLC_SUCCESS;
1790 input_DecoderDelete( es->p_dec );
1791 es->p_dec = input_DecoderNew( p_sys->p_input,
1792 &es->fmt, VLC_FALSE );
1795 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1796 es->p_dec->fmt_in.p_extra =
1797 realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1798 memcpy( es->p_dec->fmt_in.p_extra,
1799 p_fmt->p_extra, p_fmt->i_extra );
1806 case ES_OUT_SET_NEXT_DISPLAY_TIME:
1810 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1811 i_date = (int64_t)va_arg( args, int64_t );
1813 if( !es || !es->p_dec )
1814 return VLC_EGENERIC;
1816 /* XXX We should call input_ClockGetTS but PCR has been reseted
1817 * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
1818 * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
1819 es->i_preroll_end = i_date;
1823 case ES_OUT_SET_GROUP_META:
1825 int i_group = (int)va_arg( args, int );
1826 vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1828 EsOutProgramMeta( out, i_group, p_meta );
1831 case ES_OUT_SET_GROUP_EPG:
1833 int i_group = (int)va_arg( args, int );
1834 vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1836 EsOutProgramEpg( out, i_group, p_epg );
1839 case ES_OUT_DEL_GROUP:
1841 int i_group = (int)va_arg( args, int );
1843 return EsOutProgramDel( out, i_group );
1847 msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1848 return VLC_EGENERIC;
1852 /****************************************************************************
1853 * LanguageGetName: try to expend iso639 into plain name
1854 ****************************************************************************/
1855 static char *LanguageGetName( const char *psz_code )
1857 const iso639_lang_t *pl;
1859 if( psz_code == NULL )
1861 return strdup( "" );
1864 if( strlen( psz_code ) == 2 )
1866 pl = GetLang_1( psz_code );
1868 else if( strlen( psz_code ) == 3 )
1870 pl = GetLang_2B( psz_code );
1871 if( !strcmp( pl->psz_iso639_1, "??" ) )
1873 pl = GetLang_2T( psz_code );
1878 return strdup( psz_code );
1881 if( !strcmp( pl->psz_iso639_1, "??" ) )
1883 return strdup( psz_code );
1887 if( *pl->psz_native_name )
1889 return strdup( pl->psz_native_name );
1891 return strdup( pl->psz_eng_name );
1895 /* Get a 2 char code */
1896 static char *LanguageGetCode( const char *psz_lang )
1898 const iso639_lang_t *pl;
1900 if( psz_lang == NULL || *psz_lang == '\0' )
1901 return strdup("??");
1903 for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1905 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1906 !strcasecmp( pl->psz_native_name, psz_lang ) ||
1907 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1908 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1909 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1913 if( pl->psz_iso639_1 != NULL )
1914 return strdup( pl->psz_iso639_1 );
1916 return strdup("??");
1919 static char **LanguageSplit( const char *psz_langs )
1926 if( psz_langs == NULL ) return NULL;
1928 psz_parser = psz_dup = strdup(psz_langs);
1930 while( psz_parser && *psz_parser )
1935 psz = strchr(psz_parser, ',' );
1936 if( psz ) *psz++ = '\0';
1938 psz_code = LanguageGetCode( psz_parser );
1939 if( strcmp( psz_code, "??" ) )
1941 TAB_APPEND( i_psz, ppsz, psz_code );
1949 TAB_APPEND( i_psz, ppsz, NULL );
1956 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1960 if( !ppsz_langs || !psz_lang ) return -1;
1962 for( i = 0; ppsz_langs[i]; i++ )
1963 if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i;
1968 /****************************************************************************
1970 * - add meta info to the playlist item
1971 ****************************************************************************/
1972 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1974 es_out_sys_t *p_sys = out->p_sys;
1975 input_thread_t *p_input = p_sys->p_input;
1976 es_format_t *fmt = &es->fmt;
1980 /* Add stream info */
1981 asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1983 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1984 "%.4s", (char*)&fmt->i_codec );
1986 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1987 "%s", es->psz_language );
1989 /* Add information */
1990 switch( fmt->i_cat )
1993 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1994 _("Type"), _("Audio") );
1996 if( fmt->audio.i_channels > 0 )
1997 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1998 "%u", fmt->audio.i_channels );
2000 if( fmt->audio.i_rate > 0 )
2002 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
2003 _("%u Hz"), fmt->audio.i_rate );
2004 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
2007 if( fmt->audio.i_bitspersample > 0 )
2008 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2009 _("Bits per sample"), "%u",
2010 fmt->audio.i_bitspersample );
2012 if( fmt->i_bitrate > 0 )
2014 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
2015 _("%u kb/s"), fmt->i_bitrate / 1000 );
2016 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
2021 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2022 _("Type"), _("Video") );
2024 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
2025 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2026 _("Resolution"), "%ux%u",
2027 fmt->video.i_width, fmt->video.i_height );
2029 if( fmt->video.i_visible_width > 0 &&
2030 fmt->video.i_visible_height > 0 )
2031 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2032 _("Display resolution"), "%ux%u",
2033 fmt->video.i_visible_width,
2034 fmt->video.i_visible_height);
2035 if( fmt->video.i_frame_rate > 0 &&
2036 fmt->video.i_frame_rate_base > 0 )
2038 div = lldiv( (float)fmt->video.i_frame_rate /
2039 fmt->video.i_frame_rate_base * 1000000,
2041 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2042 _("Frame rate"), I64Fd".%06u",
2043 div.quot, (unsigned int )div.rem );
2048 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2049 _("Type"), _("Subtitle") );