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_common.h>
36 #include <vlc_input.h>
37 #include <vlc_es_out.h>
38 #include <vlc_block.h>
41 #include "input_internal.h"
43 #include "vlc_playlist.h"
44 #include <vlc_iso_lang.h>
45 /* FIXME we should find a better way than including that */
46 #include "../text/iso-639_def.h"
48 /*****************************************************************************
50 *****************************************************************************/
56 /* Number of es for this pgrm */
61 /* Clock for this program */
65 char *psz_now_playing;
75 es_out_pgrm_t *p_pgrm;
78 int64_t i_preroll_end;
80 /* Channel in the track type */
84 char *psz_language_code;
88 /* Fields for Video with CC */
89 bool pb_cc_present[4];
90 es_out_id_t *pp_cc_es[4];
92 /* Field for CC track from a master video */
93 es_out_id_t *p_master;
98 input_thread_t *p_input;
102 es_out_pgrm_t **pgrm;
103 es_out_pgrm_t **pp_selected_pgrm; /* --programs */
104 es_out_pgrm_t *p_pgrm; /* Master program */
121 int i_audio_last, i_audio_id;
122 int i_sub_last, i_sub_id;
123 int i_default_sub_id; /* As specified in container; if applicable */
124 char **ppsz_audio_language;
125 char **ppsz_sub_language;
127 /* current main es */
128 es_out_id_t *p_es_audio;
129 es_out_id_t *p_es_video;
130 es_out_id_t *p_es_sub;
133 int64_t i_audio_delay;
136 /* Rate used to rescale ES ts */
140 static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );
141 static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
142 static void EsOutDel ( es_out_t *, es_out_id_t * );
143 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force );
144 static int EsOutControl( es_out_t *, int i_query, va_list );
146 static void EsOutAddInfo( es_out_t *, es_out_id_t *es );
148 static bool EsIsSelected( es_out_id_t *es );
149 static void EsSelect( es_out_t *out, es_out_id_t *es );
150 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update );
151 static char *LanguageGetName( const char *psz_code );
152 static char *LanguageGetCode( const char *psz_lang );
153 static char **LanguageSplit( const char *psz_langs );
154 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
156 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
158 static const vlc_fourcc_t EsOutFourccClosedCaptions[4] = {
159 VLC_FOURCC('c', 'c', '1', ' '),
160 VLC_FOURCC('c', 'c', '2', ' '),
161 VLC_FOURCC('c', 'c', '3', ' '),
162 VLC_FOURCC('c', 'c', '4', ' '),
164 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc )
167 for( i = 0; i < 4; i++ )
169 if( fcc == EsOutFourccClosedCaptions[i] )
176 /*****************************************************************************
178 *****************************************************************************/
179 es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
181 es_out_t *out = malloc( sizeof( es_out_t ) );
182 es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
186 if( !out ) return NULL;
193 out->pf_add = EsOutAdd;
194 out->pf_send = EsOutSend;
195 out->pf_del = EsOutDel;
196 out->pf_control = EsOutControl;
198 out->b_sout = p_input->p->p_sout != NULL;
200 p_sys->p_input = p_input;
202 p_sys->b_active = false;
203 p_sys->i_mode = ES_OUT_MODE_AUTO;
206 TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
207 p_sys->p_pgrm = NULL;
211 TAB_INIT( p_sys->i_es, p_sys->es );
218 var_Get( p_input, "audio-track", &val );
219 p_sys->i_audio_last = val.i_int;
221 var_Get( p_input, "sub-track", &val );
222 p_sys->i_sub_last = val.i_int;
224 p_sys->i_default_sub_id = -1;
226 if( !p_input->b_preparsing )
228 var_Get( p_input, "audio-language", &val );
229 p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
230 if( p_sys->ppsz_audio_language )
232 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
233 msg_Dbg( p_input, "selected audio language[%d] %s",
234 i, p_sys->ppsz_audio_language[i] );
236 free( val.psz_string );
238 var_Get( p_input, "sub-language", &val );
239 p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
240 if( p_sys->ppsz_sub_language )
242 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
243 msg_Dbg( p_input, "selected subtitle language[%d] %s",
244 i, p_sys->ppsz_sub_language[i] );
246 free( val.psz_string );
250 p_sys->ppsz_sub_language = NULL;
251 p_sys->ppsz_audio_language = NULL;
254 var_Get( p_input, "audio-track-id", &val );
255 p_sys->i_audio_id = val.i_int;
257 var_Get( p_input, "sub-track-id", &val );
258 p_sys->i_sub_id = val.i_int;
260 p_sys->p_es_audio = NULL;
261 p_sys->p_es_video = NULL;
262 p_sys->p_es_sub = NULL;
264 p_sys->i_audio_delay= 0;
265 p_sys->i_spu_delay = 0;
267 p_sys->i_rate = i_rate;
272 /*****************************************************************************
274 *****************************************************************************/
275 void input_EsOutDelete( es_out_t *out )
277 es_out_sys_t *p_sys = out->p_sys;
280 for( i = 0; i < p_sys->i_es; i++ )
282 if( p_sys->es[i]->p_dec )
284 input_DecoderDelete( p_sys->es[i]->p_dec );
286 free( p_sys->es[i]->psz_language );
287 free( p_sys->es[i]->psz_language_code );
288 es_format_Clean( &p_sys->es[i]->fmt );
290 free( p_sys->es[i] );
292 if( p_sys->ppsz_audio_language )
294 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
295 free( p_sys->ppsz_audio_language[i] );
296 free( p_sys->ppsz_audio_language );
298 if( p_sys->ppsz_sub_language )
300 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
301 free( p_sys->ppsz_sub_language[i] );
302 free( p_sys->ppsz_sub_language );
307 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
308 for( i = 0; i < p_sys->i_pgrm; i++ )
310 es_out_pgrm_t *p_pgrm = p_sys->pgrm[i];
311 free( p_pgrm->psz_now_playing );
312 free( p_pgrm->psz_publisher );
313 free( p_pgrm->psz_name );
315 vlc_epg_Delete( p_pgrm->p_epg );
319 TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
325 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
330 /* Special HACK, -i_id is tha cat of the stream */
331 return (es_out_id_t*)((uint8_t*)NULL-i_id);
334 for( i = 0; i < out->p_sys->i_es; i++ )
336 if( out->p_sys->es[i]->i_id == i_id )
337 return out->p_sys->es[i];
342 static void EsOutDiscontinuity( es_out_t *out, bool b_flush, bool b_audio )
344 es_out_sys_t *p_sys = out->p_sys;
347 for( i = 0; i < p_sys->i_es; i++ )
349 es_out_id_t *es = p_sys->es[i];
351 /* Send a dummy block to let decoder know that
352 * there is a discontinuity */
353 if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
354 input_DecoderDiscontinuity( es->p_dec, b_flush );
357 void input_EsOutChangeRate( es_out_t *out, int i_rate )
359 es_out_sys_t *p_sys = out->p_sys;
362 p_sys->i_rate = i_rate;
363 EsOutDiscontinuity( out, false, false );
365 for( i = 0; i < p_sys->i_pgrm; i++ )
366 input_ClockSetRate( &p_sys->pgrm[i]->clock, i_rate );
369 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
371 es_out_sys_t *p_sys = out->p_sys;
373 if( i_cat == AUDIO_ES )
374 p_sys->i_audio_delay = i_delay;
375 else if( i_cat == SPU_ES )
376 p_sys->i_spu_delay = i_delay;
378 void input_EsOutChangeState( es_out_t *out )
380 es_out_sys_t *p_sys = out->p_sys;
381 input_thread_t *p_input = p_sys->p_input;
383 if( p_input->i_state == PAUSE_S )
385 /* Send discontinuity to decoders (it will allow them to flush
386 * * if implemented */
387 EsOutDiscontinuity( out, false, false );
391 /* Out of pause, reset pcr */
392 es_out_Control( out, ES_OUT_RESET_PCR );
395 void input_EsOutChangePosition( es_out_t *out )
397 //es_out_sys_t *p_sys = out->p_sys;
399 es_out_Control( out, ES_OUT_RESET_PCR );
400 EsOutDiscontinuity( out, true, false );
403 bool input_EsOutDecodersEmpty( es_out_t *out )
405 es_out_sys_t *p_sys = out->p_sys;
408 for( i = 0; i < p_sys->i_es; i++ )
410 es_out_id_t *es = p_sys->es[i];
412 if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
418 /*****************************************************************************
420 *****************************************************************************/
421 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
424 es_out_sys_t *p_sys = out->p_sys;
425 input_thread_t *p_input = p_sys->p_input;
426 vlc_value_t val, text;
430 if( fmt->i_cat == AUDIO_ES )
431 psz_var = "audio-es";
432 else if( fmt->i_cat == VIDEO_ES )
433 psz_var = "video-es";
434 else if( fmt->i_cat == SPU_ES )
442 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
443 var_SetBool( p_sys->p_input, "intf-change", true );
447 /* Get the number of ES already added */
448 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
453 /* First one, we need to add the "Disable" choice */
454 val2.i_int = -1; text.psz_string = _("Disable");
455 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
459 /* Take care of the ES description */
460 if( fmt->psz_description && *fmt->psz_description )
462 if( psz_language && *psz_language )
464 text.psz_string = malloc( strlen( fmt->psz_description) +
465 strlen( psz_language ) + 10 );
466 sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
469 else text.psz_string = strdup( fmt->psz_description );
473 if( psz_language && *psz_language )
476 text.psz_string = malloc( strlen( _("Track %i") )+
477 strlen( psz_language ) + 30 );
478 asprintf( &temp, _("Track %i"), val.i_int );
479 sprintf( text.psz_string, "%s - [%s]", temp, psz_language );
484 text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
485 sprintf( text.psz_string, _("Track %i"), val.i_int );
490 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
492 free( text.psz_string );
494 var_SetBool( p_sys->p_input, "intf-change", true );
497 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
500 EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
503 /* EsOutProgramSelect:
504 * Select a program and update the object variable
506 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
508 es_out_sys_t *p_sys = out->p_sys;
509 input_thread_t *p_input = p_sys->p_input;
513 if( p_sys->p_pgrm == p_pgrm )
514 return; /* Nothing to do */
518 es_out_pgrm_t *old = p_sys->p_pgrm;
519 msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
521 for( i = 0; i < p_sys->i_es; i++ )
523 if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
524 p_sys->i_mode != ES_OUT_MODE_ALL )
525 EsUnselect( out, p_sys->es[i], true );
528 p_sys->p_es_audio = NULL;
529 p_sys->p_es_sub = NULL;
530 p_sys->p_es_video = NULL;
533 msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
535 /* Mark it selected */
536 p_pgrm->b_selected = true;
538 /* Switch master stream */
539 if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
541 p_sys->p_pgrm->clock.b_master = false;
543 p_pgrm->clock.b_master = true;
544 p_sys->p_pgrm = p_pgrm;
546 /* Update "program" */
547 val.i_int = p_pgrm->i_id;
548 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
551 var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
552 var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
553 var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
554 for( i = 0; i < p_sys->i_es; i++ )
556 if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
557 EsOutESVarUpdate( out, p_sys->es[i], false );
558 EsOutSelect( out, p_sys->es[i], false );
561 /* Update now playing */
562 input_item_SetNowPlaying( p_input->p->input.p_item,
563 p_pgrm->psz_now_playing );
564 input_item_SetPublisher( p_input->p->input.p_item,
565 p_pgrm->psz_publisher );
567 var_SetBool( p_sys->p_input, "intf-change", true );
573 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
575 es_out_sys_t *p_sys = out->p_sys;
576 input_thread_t *p_input = p_sys->p_input;
579 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
580 if( !p_pgrm ) return NULL;
583 p_pgrm->i_id = i_group;
585 p_pgrm->b_selected = false;
586 p_pgrm->psz_name = NULL;
587 p_pgrm->psz_now_playing = NULL;
588 p_pgrm->psz_publisher = NULL;
589 p_pgrm->p_epg = NULL;
590 input_ClockInit( &p_pgrm->clock, false, p_input->p->input.i_cr_average, p_sys->i_rate );
593 TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
595 /* Update "program" variable */
597 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
599 if( i_group == var_GetInteger( p_input, "program" ) )
601 EsOutProgramSelect( out, p_pgrm );
605 var_SetBool( p_sys->p_input, "intf-change", true );
613 static int EsOutProgramDel( es_out_t *out, int i_group )
615 es_out_sys_t *p_sys = out->p_sys;
616 input_thread_t *p_input = p_sys->p_input;
617 es_out_pgrm_t *p_pgrm = NULL;
621 for( i = 0; i < p_sys->i_pgrm; i++ )
623 if( p_sys->pgrm[i]->i_id == i_group )
625 p_pgrm = p_sys->pgrm[i];
635 msg_Dbg( p_input, "can't delete program %d which still has %i ES",
636 i_group, p_pgrm->i_es );
640 TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
642 /* If program is selected we need to unselect it */
643 if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL;
645 free( p_pgrm->psz_name );
646 free( p_pgrm->psz_now_playing );
647 free( p_pgrm->psz_publisher );
649 vlc_epg_Delete( p_pgrm->p_epg );
652 /* Update "program" variable */
654 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
656 var_SetBool( p_sys->p_input, "intf-change", true );
663 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
666 if( p_pgrm->psz_name )
667 asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id );
669 asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id );
673 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
675 es_out_sys_t *p_sys = out->p_sys;
676 es_out_pgrm_t *p_pgrm = NULL;
677 input_thread_t *p_input = p_sys->p_input;
679 const char *psz_title = NULL;
680 const char *psz_provider = NULL;
683 msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
685 /* Check against empty meta data (empty for what we handle) */
686 if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
687 !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
688 !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
689 vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
694 for( i = 0; i < p_sys->i_pgrm; i++ )
696 if( p_sys->pgrm[i]->i_id == i_group )
698 p_pgrm = p_sys->pgrm[i];
703 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
706 psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
707 psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
709 /* Update the description text of the program */
710 if( psz_title && *psz_title )
715 if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
717 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
719 /* Remove old entries */
720 input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
721 /* TODO update epg name */
724 free( p_pgrm->psz_name );
725 p_pgrm->psz_name = strdup( psz_title );
727 /* ugly but it works */
729 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
731 if( psz_provider && *psz_provider )
733 asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider );
734 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
735 free( text.psz_string );
739 text.psz_string = (char *)psz_title;
740 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
744 psz_cat = EsOutProgramGetMetaName( p_pgrm );
747 if( p_sys->p_pgrm == p_pgrm )
748 input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
749 input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
751 char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
752 for( i = 0; ppsz_all_keys[i]; i++ )
754 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
755 vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
756 free( ppsz_all_keys[i] );
758 free( ppsz_all_keys );
763 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
768 for( i = 0; i < p_src->i_event; i++ )
770 vlc_epg_event_t *p_evt = p_src->pp_event[i];
774 for( j = 0; j < p_dst->i_event; j++ )
776 if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
781 if( p_dst->pp_event[j]->i_start > p_evt->i_start )
786 vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
789 memset( p_copy, 0, sizeof(vlc_epg_event_t) );
790 p_copy->i_start = p_evt->i_start;
791 p_copy->i_duration = p_evt->i_duration;
792 p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
793 p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
794 p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
795 TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
799 vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
801 /* Keep only 1 old event */
802 if( p_dst->p_current )
804 while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
805 TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
809 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
811 es_out_sys_t *p_sys = out->p_sys;
812 input_thread_t *p_input = p_sys->p_input;
813 es_out_pgrm_t *p_pgrm = NULL;
818 for( i = 0; i < p_sys->i_pgrm; i++ )
820 if( p_sys->pgrm[i]->i_id == i_group )
822 p_pgrm = p_sys->pgrm[i];
827 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
831 p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
832 vlc_epg_Merge( p_pgrm->p_epg, p_epg );
835 psz_cat = EsOutProgramGetMetaName( p_pgrm );
836 #ifdef HAVE_LOCALTIME_R
838 if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
840 input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
841 msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
842 for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
844 const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
845 time_t t_start = (time_t)p_evt->i_start;
849 localtime_r( &t_start, &tm_start );
851 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
852 if( p_evt->psz_short_description || p_evt->psz_description )
853 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
855 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
856 p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
858 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
860 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
864 /* Update now playing */
865 free( p_pgrm->psz_now_playing );
866 p_pgrm->psz_now_playing = NULL;
867 if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
868 p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
870 if( p_pgrm == p_sys->p_pgrm )
871 input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
873 if( p_pgrm->psz_now_playing )
875 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
876 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
877 p_pgrm->psz_now_playing );
881 input_Control( p_input, INPUT_DEL_INFO, psz_cat,
882 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
891 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
893 es_out_sys_t *p_sys = out->p_sys;
894 input_thread_t *p_input = p_sys->p_input;
896 es_out_id_t *es = malloc( sizeof( es_out_id_t ) );
897 es_out_pgrm_t *p_pgrm = NULL;
900 if( !es ) return NULL;
902 if( fmt->i_group < 0 )
904 msg_Err( p_input, "invalid group number" );
909 /* Search the program */
910 for( i = 0; i < p_sys->i_pgrm; i++ )
912 if( fmt->i_group == p_sys->pgrm[i]->i_id )
914 p_pgrm = p_sys->pgrm[i];
920 /* Create a new one */
921 p_pgrm = EsOutProgramAdd( out, fmt->i_group );
924 /* Increase ref count for program */
929 fmt->i_id = out->p_sys->i_id;
930 es->i_id = fmt->i_id;
932 es_format_Copy( &es->fmt, fmt );
933 es->i_preroll_end = -1;
939 audio_replay_gain_t rg;
941 es->i_channel = p_sys->i_audio;
943 vlc_mutex_lock( &p_input->p->input.p_item->lock );
944 memset( &rg, 0, sizeof(rg) );
945 vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
946 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
948 for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
950 if( !es->fmt.audio_replay_gain.pb_peak[i] )
952 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
953 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
955 if( !es->fmt.audio_replay_gain.pb_gain[i] )
957 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
958 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
965 es->i_channel = p_sys->i_video;
966 if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
967 vlc_ureduce( &es->fmt.video.i_frame_rate,
968 &es->fmt.video.i_frame_rate_base,
969 fmt->video.i_frame_rate,
970 fmt->video.i_frame_rate_base, 0 );
974 es->i_channel = p_sys->i_sub;
981 es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
982 es->psz_language_code = LanguageGetCode( fmt->psz_language );
984 for( i = 0; i < 4; i++ )
985 es->pb_cc_present[i] = false;
986 es->p_master = false;
988 if( es->p_pgrm == p_sys->p_pgrm )
989 EsOutESVarUpdate( out, es, false );
991 /* Select it if needed */
992 EsOutSelect( out, es, false );
995 TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
996 p_sys->i_id++; /* always incremented */
1010 EsOutAddInfo( out, es );
1015 static bool EsIsSelected( es_out_id_t *es )
1019 bool b_decode = false;
1020 if( es->p_master->p_dec )
1022 int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1023 if( i_channel != -1 )
1024 input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
1030 return es->p_dec != NULL;
1033 static void EsSelect( es_out_t *out, es_out_id_t *es )
1035 es_out_sys_t *p_sys = out->p_sys;
1036 input_thread_t *p_input = p_sys->p_input;
1038 const char *psz_var;
1040 if( EsIsSelected( es ) )
1042 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1049 if( !es->p_master->p_dec )
1052 i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1053 if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) )
1058 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1060 if( !var_GetBool( p_input, out->b_sout ? "sout-video" : "video" ) )
1062 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1067 else if( es->fmt.i_cat == AUDIO_ES )
1069 var_Get( p_input, "audio", &val );
1070 if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) )
1072 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1077 if( es->fmt.i_cat == SPU_ES )
1079 var_Get( p_input, "spu", &val );
1080 if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) )
1082 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1088 es->i_preroll_end = -1;
1089 es->p_dec = input_DecoderNew( p_input, &es->fmt, false );
1090 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1094 if( es->fmt.i_cat == VIDEO_ES )
1095 psz_var = "video-es";
1096 else if( es->fmt.i_cat == AUDIO_ES )
1097 psz_var = "audio-es";
1098 else if( es->fmt.i_cat == SPU_ES )
1103 /* Mark it as selected */
1104 val.i_int = es->i_id;
1105 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1107 var_SetBool( p_sys->p_input, "intf-change", true );
1110 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1112 es_out_sys_t *p_sys = out->p_sys;
1113 input_thread_t *p_input = p_sys->p_input;
1115 const char *psz_var;
1117 if( !EsIsSelected( es ) )
1119 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1125 if( es->p_master->p_dec )
1127 int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1128 if( i_channel != -1 )
1129 input_DecoderSetCcState( es->p_master->p_dec, false, i_channel );
1134 const int i_spu_id = var_GetInteger( p_input, "spu-es");
1136 for( i = 0; i < 4; i++ )
1138 if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1141 if( i_spu_id == es->pp_cc_es[i]->i_id )
1143 /* Force unselection of the CC */
1145 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1147 var_SetBool( p_sys->p_input, "intf-change", true );
1149 EsOutDel( out, es->pp_cc_es[i] );
1151 es->pb_cc_present[i] = false;
1153 input_DecoderDelete( es->p_dec );
1161 if( es->p_dec == NULL )
1163 if( es->fmt.i_cat == VIDEO_ES )
1164 psz_var = "video-es";
1165 else if( es->fmt.i_cat == AUDIO_ES )
1166 psz_var = "audio-es";
1167 else if( es->fmt.i_cat == SPU_ES )
1172 /* Mark it as unselected */
1174 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1176 var_SetBool( p_sys->p_input, "intf-change", true );
1180 * Select an ES given the current mode
1181 * XXX: you need to take a the lock before (stream.stream_lock)
1183 * \param out The es_out structure
1184 * \param es es_out_id structure
1185 * \param b_force ...
1188 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1190 es_out_sys_t *p_sys = out->p_sys;
1192 int i_cat = es->fmt.i_cat;
1194 if( !p_sys->b_active ||
1195 ( !b_force && es->fmt.i_priority < 0 ) )
1200 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1202 if( !EsIsSelected( es ) )
1203 EsSelect( out, es );
1205 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1209 var_Get( p_sys->p_input, "programs", &val );
1210 for ( i = 0; i < val.p_list->i_count; i++ )
1212 if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1214 if( !EsIsSelected( es ) )
1215 EsSelect( out, es );
1219 var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1221 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1225 if( es->p_pgrm != p_sys->p_pgrm )
1228 if( i_cat == AUDIO_ES )
1230 int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1231 es->psz_language_code );
1233 if( p_sys->p_es_audio &&
1234 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1236 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1237 p_sys->p_es_audio->psz_language_code );
1239 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1241 i_wanted = es->i_channel;
1245 /* Select audio if (no audio selected yet)
1246 * - no audio-language
1247 * - no audio code for the ES
1248 * - audio code in the requested list */
1250 !strcmp( es->psz_language_code, "??" ) ||
1251 !p_sys->ppsz_audio_language )
1252 i_wanted = es->i_channel;
1255 if( p_sys->i_audio_last >= 0 )
1256 i_wanted = p_sys->i_audio_last;
1258 if( p_sys->i_audio_id >= 0 )
1260 if( es->i_id == p_sys->i_audio_id )
1261 i_wanted = es->i_channel;
1266 else if( i_cat == SPU_ES )
1268 int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1269 es->psz_language_code );
1271 if( p_sys->p_es_sub &&
1272 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1274 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1275 p_sys->p_es_sub->psz_language_code );
1277 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1278 idx1, es->psz_language_code, idx2,
1279 p_sys->p_es_sub->psz_language_code );
1281 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1283 /* We found a SPU that matches our language request */
1284 i_wanted = es->i_channel;
1286 else if( idx1 >= 0 )
1288 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1289 idx1, es->psz_language_code );
1291 i_wanted = es->i_channel;
1293 else if( p_sys->i_default_sub_id >= 0 )
1295 if( es->i_id == p_sys->i_default_sub_id )
1296 i_wanted = es->i_channel;
1299 if( p_sys->i_sub_last >= 0 )
1300 i_wanted = p_sys->i_sub_last;
1302 if( p_sys->i_sub_id >= 0 )
1304 if( es->i_id == p_sys->i_sub_id )
1305 i_wanted = es->i_channel;
1310 else if( i_cat == VIDEO_ES )
1312 i_wanted = es->i_channel;
1315 if( i_wanted == es->i_channel && !EsIsSelected( es ) )
1316 EsSelect( out, es );
1319 /* FIXME TODO handle priority here */
1320 if( EsIsSelected( es ) )
1322 if( i_cat == AUDIO_ES )
1324 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1325 p_sys->p_es_audio &&
1326 p_sys->p_es_audio != es &&
1327 EsIsSelected( p_sys->p_es_audio ) )
1329 EsUnselect( out, p_sys->p_es_audio, false );
1331 p_sys->p_es_audio = es;
1333 else if( i_cat == SPU_ES )
1335 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1337 p_sys->p_es_sub != es &&
1338 EsIsSelected( p_sys->p_es_sub ) )
1340 EsUnselect( out, p_sys->p_es_sub, false );
1342 p_sys->p_es_sub = es;
1344 else if( i_cat == VIDEO_ES )
1346 p_sys->p_es_video = es;
1352 * Send a block for the given es_out
1354 * \param out the es_out to send from
1355 * \param es the es_out_id
1356 * \param p_block the data block to send
1358 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1360 es_out_sys_t *p_sys = out->p_sys;
1361 input_thread_t *p_input = p_sys->p_input;
1362 es_out_pgrm_t *p_pgrm = es->p_pgrm;
1366 if( es->fmt.i_cat == AUDIO_ES )
1367 i_delay = p_sys->i_audio_delay;
1368 else if( es->fmt.i_cat == SPU_ES )
1369 i_delay = p_sys->i_spu_delay;
1373 if( libvlc_stats (p_input) )
1375 vlc_mutex_lock( &p_input->p->counters.counters_lock );
1376 stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1377 p_block->i_buffer, &i_total );
1378 stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1379 (float)i_total, NULL );
1380 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1383 /* Mark preroll blocks */
1384 if( es->i_preroll_end >= 0 )
1386 int64_t i_date = p_block->i_pts;
1388 i_date = p_block->i_dts;
1390 if( i_date < es->i_preroll_end )
1391 p_block->i_flags |= BLOCK_FLAG_PREROLL;
1393 es->i_preroll_end = -1;
1396 if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1398 p_block->i_dts += i_delay;
1400 else if( p_block->i_dts > 0 )
1403 input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay;
1405 if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1407 p_block->i_pts += i_delay;
1409 else if( p_block->i_pts > 0 )
1412 input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay;
1414 if ( p_block->i_rate == INPUT_RATE_DEFAULT &&
1415 es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1417 mtime_t current_date = mdate();
1419 || p_block->i_pts > current_date + 10000000
1420 || current_date > p_block->i_pts )
1422 /* ETSI EN 300 472 Annex A : do not take into account the PTS
1423 * for teletext streams. */
1424 p_block->i_pts = current_date + 400000
1425 + p_input->i_pts_delay + i_delay;
1429 p_block->i_rate = p_sys->i_rate;
1431 /* TODO handle mute */
1433 ( es->fmt.i_cat != AUDIO_ES ||
1434 ( p_sys->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
1435 p_sys->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
1438 bool b_cc_new = false;
1440 input_DecoderDecode( es->p_dec, p_block );
1442 /* Check CC status */
1443 input_DecoderIsCcPresent( es->p_dec, pb_cc );
1444 for( i = 0; i < 4; i++ )
1446 static const vlc_fourcc_t fcc[4] = {
1447 VLC_FOURCC('c', 'c', '1', ' '),
1448 VLC_FOURCC('c', 'c', '2', ' '),
1449 VLC_FOURCC('c', 'c', '3', ' '),
1450 VLC_FOURCC('c', 'c', '4', ' '),
1452 static const char ppsz_description[4][18] = {
1453 N_("Closed captions 1"),
1454 N_("Closed captions 2"),
1455 N_("Closed captions 3"),
1456 N_("Closed captions 4"),
1460 if( es->pb_cc_present[i] || !pb_cc[i] )
1462 msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
1464 es_format_Init( &fmt, SPU_ES, fcc[i] );
1465 fmt.i_group = es->fmt.i_group;
1466 fmt.psz_description = strdup( _(ppsz_description[i] ) );
1467 es->pp_cc_es[i] = EsOutAdd( out, &fmt );
1468 es->pp_cc_es[i]->p_master = es;
1469 es_format_Clean( &fmt );
1472 es->pb_cc_present[i] = true;
1476 var_SetBool( p_sys->p_input, "intf-change", true );
1480 block_Release( p_block );
1486 /*****************************************************************************
1488 *****************************************************************************/
1489 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1491 es_out_sys_t *p_sys = out->p_sys;
1492 bool b_reselect = false;
1495 /* We don't try to reselect */
1498 while( !out->p_sys->p_input->b_die && es->p_dec )
1500 if( input_DecoderEmpty( es->p_dec ) )
1504 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1507 if( es->p_pgrm == p_sys->p_pgrm )
1508 EsOutESVarUpdate( out, es, true );
1510 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1513 if( es->p_pgrm->i_es == 0 )
1515 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1518 if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1519 p_sys->p_es_sub == es ) b_reselect = true;
1521 if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1522 if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1523 if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
1525 switch( es->fmt.i_cat )
1538 /* Re-select another track when needed */
1540 for( i = 0; i < p_sys->i_es; i++ )
1542 if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1543 EsOutSelect( out, p_sys->es[i], false );
1546 free( es->psz_language );
1547 free( es->psz_language_code );
1549 es_format_Clean( &es->fmt );
1555 * Control query handler
1557 * \param out the es_out to control
1558 * \param i_query A es_out query as defined in include/ninput.h
1559 * \param args a variable list of arguments for the query
1560 * \return VLC_SUCCESS or an error code
1562 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1564 es_out_sys_t *p_sys = out->p_sys;
1572 case ES_OUT_SET_ES_STATE:
1573 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1574 b = (bool) va_arg( args, int );
1575 if( b && !EsIsSelected( es ) )
1577 EsSelect( out, es );
1578 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
1580 else if( !b && EsIsSelected( es ) )
1582 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1587 case ES_OUT_GET_ES_STATE:
1588 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1589 pb = (bool*) va_arg( args, bool * );
1591 *pb = EsIsSelected( es );
1594 case ES_OUT_SET_ACTIVE:
1596 b = (bool) va_arg( args, int );
1597 p_sys->b_active = b;
1600 var_SetBool( p_sys->p_input, "intf-change", true );
1604 case ES_OUT_GET_ACTIVE:
1605 pb = (bool*) va_arg( args, bool * );
1606 *pb = p_sys->b_active;
1609 case ES_OUT_SET_MODE:
1610 i = (int) va_arg( args, int );
1611 if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1612 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1616 /* Reapply policy mode */
1617 for( i = 0; i < p_sys->i_es; i++ )
1619 if( EsIsSelected( p_sys->es[i] ) )
1621 EsUnselect( out, p_sys->es[i],
1622 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1625 for( i = 0; i < p_sys->i_es; i++ )
1627 EsOutSelect( out, p_sys->es[i], false );
1631 return VLC_EGENERIC;
1633 case ES_OUT_GET_MODE:
1634 pi = (int*) va_arg( args, int* );
1635 *pi = p_sys->i_mode;
1639 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1640 /* Special case NULL, NULL+i_cat */
1643 for( i = 0; i < p_sys->i_es; i++ )
1645 if( EsIsSelected( p_sys->es[i] ) )
1646 EsUnselect( out, p_sys->es[i],
1647 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1650 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1652 for( i = 0; i < p_sys->i_es; i++ )
1654 if( p_sys->es[i]->fmt.i_cat == AUDIO_ES &&
1655 EsIsSelected( p_sys->es[i] ) )
1656 EsUnselect( out, p_sys->es[i],
1657 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1660 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1662 for( i = 0; i < p_sys->i_es; i++ )
1664 if( p_sys->es[i]->fmt.i_cat == VIDEO_ES &&
1665 EsIsSelected( p_sys->es[i] ) )
1666 EsUnselect( out, p_sys->es[i],
1667 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1670 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1672 for( i = 0; i < p_sys->i_es; i++ )
1674 if( p_sys->es[i]->fmt.i_cat == SPU_ES &&
1675 EsIsSelected( p_sys->es[i] ) )
1676 EsUnselect( out, p_sys->es[i],
1677 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1682 for( i = 0; i < p_sys->i_es; i++ )
1684 if( es == p_sys->es[i] )
1686 EsOutSelect( out, es, true );
1692 /* FIXME: we don't want to depend on the playlist */
1693 playlist_t * p_playlist = pl_Yield( p_sys->p_input );
1694 if( VLC_OBJECT(p_playlist) == p_sys->p_input )
1697 p_playlist->gc_date = mdate();
1698 vlc_object_signal_unlocked( p_playlist );
1701 pl_Release( p_sys->p_input );
1703 event.type = vlc_InputSelectedStreamChanged;
1704 vlc_event_send( &p_sys->p_input->p->event_manager, &event );
1708 case ES_OUT_SET_DEFAULT:
1710 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1714 /*p_sys->i_default_video_id = -1;*/
1715 /*p_sys->i_default_audio_id = -1;*/
1716 p_sys->i_default_sub_id = -1;
1718 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1720 /*p_sys->i_default_video_id = -1;*/
1722 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1724 /*p_sys->i_default_audio_id = -1;*/
1726 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1728 p_sys->i_default_sub_id = -1;
1732 /*if( es->fmt.i_cat == VIDEO_ES )
1733 p_sys->i_default_video_id = es->i_id;
1735 if( es->fmt.i_cat == AUDIO_ES )
1736 p_sys->i_default_audio_id = es->i_id;
1738 if( es->fmt.i_cat == SPU_ES )
1739 p_sys->i_default_sub_id = es->i_id;
1744 case ES_OUT_SET_PCR:
1745 case ES_OUT_SET_GROUP_PCR:
1747 es_out_pgrm_t *p_pgrm = NULL;
1751 if( i_query == ES_OUT_SET_PCR )
1753 p_pgrm = p_sys->p_pgrm;
1758 i_group = (int)va_arg( args, int );
1759 for( i = 0; i < p_sys->i_pgrm; i++ )
1761 if( p_sys->pgrm[i]->i_id == i_group )
1763 p_pgrm = p_sys->pgrm[i];
1768 if( p_pgrm == NULL )
1769 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
1771 i_pcr = (int64_t)va_arg( args, int64_t );
1772 /* search program */
1773 input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr );
1777 case ES_OUT_RESET_PCR:
1778 for( i = 0; i < p_sys->i_pgrm; i++ )
1779 input_ClockResetPCR( &p_sys->pgrm[i]->clock );
1785 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1786 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1787 *pi_ts = input_ClockGetTS( p_sys->p_input,
1788 &p_sys->p_pgrm->clock, i_ts );
1791 return VLC_EGENERIC;
1793 case ES_OUT_GET_GROUP:
1794 pi = (int*) va_arg( args, int* );
1796 *pi = p_sys->p_pgrm->i_id;
1798 *pi = -1; /* FIXME */
1801 case ES_OUT_SET_GROUP:
1804 i = (int) va_arg( args, int );
1805 for( j = 0; j < p_sys->i_pgrm; j++ )
1807 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1808 if( p_pgrm->i_id == i )
1810 EsOutProgramSelect( out, p_pgrm );
1814 return VLC_EGENERIC;
1817 case ES_OUT_SET_FMT:
1819 /* This ain't pretty but is need by some demuxers (eg. Ogg )
1820 * to update the p_extra data */
1822 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1823 p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1824 if( es == NULL ) return VLC_EGENERIC;
1826 if( p_fmt->i_extra )
1828 es->fmt.i_extra = p_fmt->i_extra;
1829 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1830 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1832 if( !es->p_dec ) return VLC_SUCCESS;
1835 input_DecoderDelete( es->p_dec );
1836 es->p_dec = input_DecoderNew( p_sys->p_input,
1840 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1841 es->p_dec->fmt_in.p_extra =
1842 realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1843 memcpy( es->p_dec->fmt_in.p_extra,
1844 p_fmt->p_extra, p_fmt->i_extra );
1851 case ES_OUT_SET_NEXT_DISPLAY_TIME:
1855 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1856 i_date = (int64_t)va_arg( args, int64_t );
1858 if( !es || !es->p_dec )
1859 return VLC_EGENERIC;
1861 /* XXX We should call input_ClockGetTS but PCR has been reseted
1862 * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
1863 * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
1864 es->i_preroll_end = i_date;
1868 case ES_OUT_SET_GROUP_META:
1870 int i_group = (int)va_arg( args, int );
1871 vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1873 EsOutProgramMeta( out, i_group, p_meta );
1876 case ES_OUT_SET_GROUP_EPG:
1878 int i_group = (int)va_arg( args, int );
1879 vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1881 EsOutProgramEpg( out, i_group, p_epg );
1884 case ES_OUT_DEL_GROUP:
1886 int i_group = (int)va_arg( args, int );
1888 return EsOutProgramDel( out, i_group );
1892 msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1893 return VLC_EGENERIC;
1897 /****************************************************************************
1898 * LanguageGetName: try to expend iso639 into plain name
1899 ****************************************************************************/
1900 static char *LanguageGetName( const char *psz_code )
1902 const iso639_lang_t *pl;
1904 if( psz_code == NULL )
1906 return strdup( "" );
1909 if( strlen( psz_code ) == 2 )
1911 pl = GetLang_1( psz_code );
1913 else if( strlen( psz_code ) == 3 )
1915 pl = GetLang_2B( psz_code );
1916 if( !strcmp( pl->psz_iso639_1, "??" ) )
1918 pl = GetLang_2T( psz_code );
1923 return strdup( psz_code );
1926 if( !strcmp( pl->psz_iso639_1, "??" ) )
1928 return strdup( psz_code );
1932 if( *pl->psz_native_name )
1934 return strdup( pl->psz_native_name );
1936 return strdup( pl->psz_eng_name );
1940 /* Get a 2 char code */
1941 static char *LanguageGetCode( const char *psz_lang )
1943 const iso639_lang_t *pl;
1945 if( psz_lang == NULL || *psz_lang == '\0' )
1946 return strdup("??");
1948 for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1950 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1951 !strcasecmp( pl->psz_native_name, psz_lang ) ||
1952 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1953 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1954 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1958 if( pl->psz_iso639_1 != NULL )
1959 return strdup( pl->psz_iso639_1 );
1961 return strdup("??");
1964 static char **LanguageSplit( const char *psz_langs )
1971 if( psz_langs == NULL ) return NULL;
1973 psz_parser = psz_dup = strdup(psz_langs);
1975 while( psz_parser && *psz_parser )
1980 psz = strchr(psz_parser, ',' );
1981 if( psz ) *psz++ = '\0';
1983 if( !strcmp( psz_parser, "any" ) )
1985 TAB_APPEND( i_psz, ppsz, strdup("any") );
1989 psz_code = LanguageGetCode( psz_parser );
1990 if( strcmp( psz_code, "??" ) )
1992 TAB_APPEND( i_psz, ppsz, psz_code );
2005 TAB_APPEND( i_psz, ppsz, NULL );
2012 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
2016 if( !ppsz_langs || !psz_lang ) return -1;
2018 for( i = 0; ppsz_langs[i]; i++ )
2020 if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2021 !strcasecmp( ppsz_langs[i], "any" ) )
2030 /****************************************************************************
2032 * - add meta info to the playlist item
2033 ****************************************************************************/
2034 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
2036 es_out_sys_t *p_sys = out->p_sys;
2037 input_thread_t *p_input = p_sys->p_input;
2038 es_format_t *fmt = &es->fmt;
2042 /* Add stream info */
2043 asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
2045 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
2046 "%.4s", (char*)&fmt->i_codec );
2048 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
2049 "%s", es->psz_language );
2051 /* Add information */
2052 switch( fmt->i_cat )
2055 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2056 _("Type"), _("Audio") );
2058 if( fmt->audio.i_channels > 0 )
2059 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
2060 "%u", fmt->audio.i_channels );
2062 if( fmt->audio.i_rate > 0 )
2064 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
2065 _("%u Hz"), fmt->audio.i_rate );
2066 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
2069 if( fmt->audio.i_bitspersample > 0 )
2070 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2071 _("Bits per sample"), "%u",
2072 fmt->audio.i_bitspersample );
2074 if( fmt->i_bitrate > 0 )
2076 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
2077 _("%u kb/s"), fmt->i_bitrate / 1000 );
2078 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
2083 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2084 _("Type"), _("Video") );
2086 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
2087 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2088 _("Resolution"), "%ux%u",
2089 fmt->video.i_width, fmt->video.i_height );
2091 if( fmt->video.i_visible_width > 0 &&
2092 fmt->video.i_visible_height > 0 )
2093 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2094 _("Display resolution"), "%ux%u",
2095 fmt->video.i_visible_width,
2096 fmt->video.i_visible_height);
2097 if( fmt->video.i_frame_rate > 0 &&
2098 fmt->video.i_frame_rate_base > 0 )
2100 div = lldiv( (float)fmt->video.i_frame_rate /
2101 fmt->video.i_frame_rate_base * 1000000,
2103 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2104 _("Frame rate"), "%"PRId64".%06u",
2105 div.quot, (unsigned int )div.rem );
2110 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2111 _("Type"), _("Subtitle") );