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_iso_lang.h>
44 /* FIXME we should find a better way than including that */
45 #include "../text/iso-639_def.h"
47 /*****************************************************************************
49 *****************************************************************************/
55 /* Number of es for this pgrm */
60 /* Clock for this program */
64 char *psz_now_playing;
74 es_out_pgrm_t *p_pgrm;
77 int64_t i_preroll_end;
79 /* Channel in the track type */
83 char *psz_language_code;
87 /* Fields for Video with CC */
88 bool pb_cc_present[4];
89 es_out_id_t *pp_cc_es[4];
91 /* Field for CC track from a master video */
92 es_out_id_t *p_master;
97 input_thread_t *p_input;
101 es_out_pgrm_t **pgrm;
102 es_out_pgrm_t **pp_selected_pgrm; /* --programs */
103 es_out_pgrm_t *p_pgrm; /* Master program */
120 int i_audio_last, i_audio_id;
121 int i_sub_last, i_sub_id;
122 int i_default_sub_id; /* As specified in container; if applicable */
123 char **ppsz_audio_language;
124 char **ppsz_sub_language;
126 /* current main es */
127 es_out_id_t *p_es_audio;
128 es_out_id_t *p_es_video;
129 es_out_id_t *p_es_sub;
132 int64_t i_audio_delay;
135 /* Rate used to rescale ES ts */
139 static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );
140 static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
141 static void EsOutDel ( es_out_t *, es_out_id_t * );
142 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force );
143 static int EsOutControl( es_out_t *, int i_query, va_list );
145 static void EsOutAddInfo( es_out_t *, es_out_id_t *es );
147 static bool EsIsSelected( es_out_id_t *es );
148 static void EsSelect( es_out_t *out, es_out_id_t *es );
149 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update );
150 static char *LanguageGetName( const char *psz_code );
151 static char *LanguageGetCode( const char *psz_lang );
152 static char **LanguageSplit( const char *psz_langs );
153 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
155 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
157 static const vlc_fourcc_t EsOutFourccClosedCaptions[4] = {
158 VLC_FOURCC('c', 'c', '1', ' '),
159 VLC_FOURCC('c', 'c', '2', ' '),
160 VLC_FOURCC('c', 'c', '3', ' '),
161 VLC_FOURCC('c', 'c', '4', ' '),
163 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc )
166 for( i = 0; i < 4; i++ )
168 if( fcc == EsOutFourccClosedCaptions[i] )
175 /*****************************************************************************
177 *****************************************************************************/
178 es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
183 es_out_t *out = malloc( sizeof( es_out_t ) );
184 if( !out ) return NULL;
186 es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
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 const bool b_teletext = fmt->i_cat == SPU_ES && fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' );
427 vlc_value_t val, text;
431 if( fmt->i_cat == AUDIO_ES )
432 psz_var = "audio-es";
433 else if( fmt->i_cat == VIDEO_ES )
434 psz_var = "video-es";
435 else if( fmt->i_cat == SPU_ES )
443 var_SetInteger( p_sys->p_input, "teletext-es", -1 );
446 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
448 var_SetBool( p_sys->p_input, "intf-change", true );
452 /* Get the number of ES already added */
453 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
458 /* First one, we need to add the "Disable" choice */
459 val2.i_int = -1; text.psz_string = _("Disable");
460 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
464 /* Take care of the ES description */
465 if( fmt->psz_description && *fmt->psz_description )
467 if( psz_language && *psz_language )
469 text.psz_string = malloc( strlen( fmt->psz_description) +
470 strlen( psz_language ) + 10 );
471 sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
474 else text.psz_string = strdup( fmt->psz_description );
478 if( psz_language && *psz_language )
480 if( asprintf( &text.psz_string, "%s %i - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
481 text.psz_string = NULL;
485 if( asprintf( &text.psz_string, "%s %i", _( "Track" ), val.i_int ) == -1 )
486 text.psz_string = NULL;
491 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
493 free( text.psz_string );
496 var_SetInteger( p_sys->p_input, "teletext-es", i_id );
498 var_SetBool( p_sys->p_input, "intf-change", true );
501 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
504 EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
507 /* EsOutProgramSelect:
508 * Select a program and update the object variable
510 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
512 es_out_sys_t *p_sys = out->p_sys;
513 input_thread_t *p_input = p_sys->p_input;
517 if( p_sys->p_pgrm == p_pgrm )
518 return; /* Nothing to do */
522 es_out_pgrm_t *old = p_sys->p_pgrm;
523 msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
525 for( i = 0; i < p_sys->i_es; i++ )
527 if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
528 p_sys->i_mode != ES_OUT_MODE_ALL )
529 EsUnselect( out, p_sys->es[i], true );
532 p_sys->p_es_audio = NULL;
533 p_sys->p_es_sub = NULL;
534 p_sys->p_es_video = NULL;
537 msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
539 /* Mark it selected */
540 p_pgrm->b_selected = true;
542 /* Switch master stream */
543 if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
545 p_sys->p_pgrm->clock.b_master = false;
547 p_pgrm->clock.b_master = true;
548 p_sys->p_pgrm = p_pgrm;
550 /* Update "program" */
551 val.i_int = p_pgrm->i_id;
552 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
555 var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
556 var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
557 var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
558 var_SetInteger( p_input, "teletext-es", -1 );
559 for( i = 0; i < p_sys->i_es; i++ )
561 if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
562 EsOutESVarUpdate( out, p_sys->es[i], false );
563 EsOutSelect( out, p_sys->es[i], false );
566 /* Update now playing */
567 input_item_SetNowPlaying( p_input->p->input.p_item,
568 p_pgrm->psz_now_playing );
569 input_item_SetPublisher( p_input->p->input.p_item,
570 p_pgrm->psz_publisher );
572 var_SetBool( p_sys->p_input, "intf-change", true );
578 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
580 es_out_sys_t *p_sys = out->p_sys;
581 input_thread_t *p_input = p_sys->p_input;
584 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
585 if( !p_pgrm ) return NULL;
588 p_pgrm->i_id = i_group;
590 p_pgrm->b_selected = false;
591 p_pgrm->psz_name = NULL;
592 p_pgrm->psz_now_playing = NULL;
593 p_pgrm->psz_publisher = NULL;
594 p_pgrm->p_epg = NULL;
595 input_ClockInit( &p_pgrm->clock, false, p_input->p->input.i_cr_average, p_sys->i_rate );
598 TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
600 /* Update "program" variable */
602 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
604 if( i_group == var_GetInteger( p_input, "program" ) )
606 EsOutProgramSelect( out, p_pgrm );
610 var_SetBool( p_sys->p_input, "intf-change", true );
618 static int EsOutProgramDel( es_out_t *out, int i_group )
620 es_out_sys_t *p_sys = out->p_sys;
621 input_thread_t *p_input = p_sys->p_input;
622 es_out_pgrm_t *p_pgrm = NULL;
626 for( i = 0; i < p_sys->i_pgrm; i++ )
628 if( p_sys->pgrm[i]->i_id == i_group )
630 p_pgrm = p_sys->pgrm[i];
640 msg_Dbg( p_input, "can't delete program %d which still has %i ES",
641 i_group, p_pgrm->i_es );
645 TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
647 /* If program is selected we need to unselect it */
648 if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL;
650 free( p_pgrm->psz_name );
651 free( p_pgrm->psz_now_playing );
652 free( p_pgrm->psz_publisher );
654 vlc_epg_Delete( p_pgrm->p_epg );
657 /* Update "program" variable */
659 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
661 var_SetBool( p_sys->p_input, "intf-change", true );
668 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
671 if( p_pgrm->psz_name )
673 if( asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ) == -1 )
678 if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
684 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
686 es_out_sys_t *p_sys = out->p_sys;
687 es_out_pgrm_t *p_pgrm = NULL;
688 input_thread_t *p_input = p_sys->p_input;
690 const char *psz_title = NULL;
691 const char *psz_provider = NULL;
694 msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
696 /* Check against empty meta data (empty for what we handle) */
697 if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
698 !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
699 !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
700 vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
705 for( i = 0; i < p_sys->i_pgrm; i++ )
707 if( p_sys->pgrm[i]->i_id == i_group )
709 p_pgrm = p_sys->pgrm[i];
714 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
717 psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
718 psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
720 /* Update the description text of the program */
721 if( psz_title && *psz_title )
726 if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
728 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
730 /* Remove old entries */
731 input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
732 /* TODO update epg name */
735 free( p_pgrm->psz_name );
736 p_pgrm->psz_name = strdup( psz_title );
738 /* ugly but it works */
740 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
742 if( psz_provider && *psz_provider )
744 if( asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ) != -1 )
746 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
747 free( text.psz_string );
752 text.psz_string = (char *)psz_title;
753 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
757 psz_cat = EsOutProgramGetMetaName( p_pgrm );
760 if( p_sys->p_pgrm == p_pgrm )
761 input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
762 input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
764 char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
765 for( i = 0; ppsz_all_keys[i]; i++ )
767 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
768 vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
769 free( ppsz_all_keys[i] );
771 free( ppsz_all_keys );
776 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
781 for( i = 0; i < p_src->i_event; i++ )
783 vlc_epg_event_t *p_evt = p_src->pp_event[i];
787 for( j = 0; j < p_dst->i_event; j++ )
789 if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
794 if( p_dst->pp_event[j]->i_start > p_evt->i_start )
799 vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
802 memset( p_copy, 0, sizeof(vlc_epg_event_t) );
803 p_copy->i_start = p_evt->i_start;
804 p_copy->i_duration = p_evt->i_duration;
805 p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
806 p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
807 p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
808 TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
812 vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
814 /* Keep only 1 old event */
815 if( p_dst->p_current )
817 while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
818 TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
822 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
824 es_out_sys_t *p_sys = out->p_sys;
825 input_thread_t *p_input = p_sys->p_input;
826 es_out_pgrm_t *p_pgrm = NULL;
831 for( i = 0; i < p_sys->i_pgrm; i++ )
833 if( p_sys->pgrm[i]->i_id == i_group )
835 p_pgrm = p_sys->pgrm[i];
840 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
844 p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
845 vlc_epg_Merge( p_pgrm->p_epg, p_epg );
848 psz_cat = EsOutProgramGetMetaName( p_pgrm );
849 #ifdef HAVE_LOCALTIME_R
851 if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
853 input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
854 msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
855 for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
857 const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
858 time_t t_start = (time_t)p_evt->i_start;
862 localtime_r( &t_start, &tm_start );
864 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
865 if( p_evt->psz_short_description || p_evt->psz_description )
866 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
868 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
869 p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
871 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
873 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
877 /* Update now playing */
878 free( p_pgrm->psz_now_playing );
879 p_pgrm->psz_now_playing = NULL;
880 if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
881 p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
883 if( p_pgrm == p_sys->p_pgrm )
884 input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
886 if( p_pgrm->psz_now_playing )
888 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
889 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
890 p_pgrm->psz_now_playing );
894 input_Control( p_input, INPUT_DEL_INFO, psz_cat,
895 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
904 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
906 es_out_sys_t *p_sys = out->p_sys;
907 input_thread_t *p_input = p_sys->p_input;
909 es_out_id_t *es = malloc( sizeof( es_out_id_t ) );
910 es_out_pgrm_t *p_pgrm = NULL;
913 if( !es ) return NULL;
915 if( fmt->i_group < 0 )
917 msg_Err( p_input, "invalid group number" );
922 /* Search the program */
923 for( i = 0; i < p_sys->i_pgrm; i++ )
925 if( fmt->i_group == p_sys->pgrm[i]->i_id )
927 p_pgrm = p_sys->pgrm[i];
933 /* Create a new one */
934 p_pgrm = EsOutProgramAdd( out, fmt->i_group );
937 /* Increase ref count for program */
942 fmt->i_id = out->p_sys->i_id;
943 es->i_id = fmt->i_id;
945 es_format_Copy( &es->fmt, fmt );
946 es->i_preroll_end = -1;
952 audio_replay_gain_t rg;
954 es->i_channel = p_sys->i_audio;
956 vlc_mutex_lock( &p_input->p->input.p_item->lock );
957 memset( &rg, 0, sizeof(rg) );
958 vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
959 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
961 for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
963 if( !es->fmt.audio_replay_gain.pb_peak[i] )
965 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
966 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
968 if( !es->fmt.audio_replay_gain.pb_gain[i] )
970 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
971 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
978 es->i_channel = p_sys->i_video;
979 if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
980 vlc_ureduce( &es->fmt.video.i_frame_rate,
981 &es->fmt.video.i_frame_rate_base,
982 fmt->video.i_frame_rate,
983 fmt->video.i_frame_rate_base, 0 );
987 es->i_channel = p_sys->i_sub;
994 es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
995 es->psz_language_code = LanguageGetCode( fmt->psz_language );
997 for( i = 0; i < 4; i++ )
998 es->pb_cc_present[i] = false;
999 es->p_master = false;
1001 if( es->p_pgrm == p_sys->p_pgrm )
1002 EsOutESVarUpdate( out, es, false );
1004 /* Select it if needed */
1005 EsOutSelect( out, es, false );
1008 TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
1009 p_sys->i_id++; /* always incremented */
1010 switch( fmt->i_cat )
1023 EsOutAddInfo( out, es );
1028 static bool EsIsSelected( es_out_id_t *es )
1032 bool b_decode = false;
1033 if( es->p_master->p_dec )
1035 int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1036 if( i_channel != -1 )
1037 input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
1043 return es->p_dec != NULL;
1046 static void EsSelect( es_out_t *out, es_out_id_t *es )
1048 es_out_sys_t *p_sys = out->p_sys;
1049 input_thread_t *p_input = p_sys->p_input;
1051 const char *psz_var;
1053 if( EsIsSelected( es ) )
1055 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1062 if( !es->p_master->p_dec )
1065 i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1066 if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) )
1071 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1073 if( !var_GetBool( p_input, out->b_sout ? "sout-video" : "video" ) )
1075 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1080 else if( es->fmt.i_cat == AUDIO_ES )
1082 var_Get( p_input, "audio", &val );
1083 if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) )
1085 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1090 if( es->fmt.i_cat == SPU_ES )
1092 var_Get( p_input, "spu", &val );
1093 if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) )
1095 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1101 es->i_preroll_end = -1;
1102 es->p_dec = input_DecoderNew( p_input, &es->fmt, false );
1103 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1107 if( es->fmt.i_cat == VIDEO_ES )
1108 psz_var = "video-es";
1109 else if( es->fmt.i_cat == AUDIO_ES )
1110 psz_var = "audio-es";
1111 else if( es->fmt.i_cat == SPU_ES )
1116 /* Mark it as selected */
1117 val.i_int = es->i_id;
1118 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1120 var_SetBool( p_sys->p_input, "intf-change", true );
1123 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1125 es_out_sys_t *p_sys = out->p_sys;
1126 input_thread_t *p_input = p_sys->p_input;
1128 const char *psz_var;
1130 if( !EsIsSelected( es ) )
1132 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1138 if( es->p_master->p_dec )
1140 int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1141 if( i_channel != -1 )
1142 input_DecoderSetCcState( es->p_master->p_dec, false, i_channel );
1147 const int i_spu_id = var_GetInteger( p_input, "spu-es");
1149 for( i = 0; i < 4; i++ )
1151 if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1154 if( i_spu_id == es->pp_cc_es[i]->i_id )
1156 /* Force unselection of the CC */
1158 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1160 var_SetBool( p_sys->p_input, "intf-change", true );
1162 EsOutDel( out, es->pp_cc_es[i] );
1164 es->pb_cc_present[i] = false;
1166 input_DecoderDelete( es->p_dec );
1174 if( es->p_dec == NULL )
1176 if( es->fmt.i_cat == VIDEO_ES )
1177 psz_var = "video-es";
1178 else if( es->fmt.i_cat == AUDIO_ES )
1179 psz_var = "audio-es";
1180 else if( es->fmt.i_cat == SPU_ES )
1185 /* Mark it as unselected */
1187 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1189 var_SetBool( p_sys->p_input, "intf-change", true );
1193 * Select an ES given the current mode
1194 * XXX: you need to take a the lock before (stream.stream_lock)
1196 * \param out The es_out structure
1197 * \param es es_out_id structure
1198 * \param b_force ...
1201 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1203 es_out_sys_t *p_sys = out->p_sys;
1205 int i_cat = es->fmt.i_cat;
1207 if( !p_sys->b_active ||
1208 ( !b_force && es->fmt.i_priority < 0 ) )
1213 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1215 if( !EsIsSelected( es ) )
1216 EsSelect( out, es );
1218 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1222 var_Get( p_sys->p_input, "programs", &val );
1223 for ( i = 0; i < val.p_list->i_count; i++ )
1225 if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1227 if( !EsIsSelected( es ) )
1228 EsSelect( out, es );
1232 var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1234 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1238 if( es->p_pgrm != p_sys->p_pgrm )
1241 if( i_cat == AUDIO_ES )
1243 int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1244 es->psz_language_code );
1246 if( p_sys->p_es_audio &&
1247 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1249 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1250 p_sys->p_es_audio->psz_language_code );
1252 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1254 i_wanted = es->i_channel;
1258 /* Select audio if (no audio selected yet)
1259 * - no audio-language
1260 * - no audio code for the ES
1261 * - audio code in the requested list */
1263 !strcmp( es->psz_language_code, "??" ) ||
1264 !p_sys->ppsz_audio_language )
1265 i_wanted = es->i_channel;
1268 if( p_sys->i_audio_last >= 0 )
1269 i_wanted = p_sys->i_audio_last;
1271 if( p_sys->i_audio_id >= 0 )
1273 if( es->i_id == p_sys->i_audio_id )
1274 i_wanted = es->i_channel;
1279 else if( i_cat == SPU_ES )
1281 int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1282 es->psz_language_code );
1284 if( p_sys->p_es_sub &&
1285 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1287 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1288 p_sys->p_es_sub->psz_language_code );
1290 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1291 idx1, es->psz_language_code, idx2,
1292 p_sys->p_es_sub->psz_language_code );
1294 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1296 /* We found a SPU that matches our language request */
1297 i_wanted = es->i_channel;
1299 else if( idx1 >= 0 )
1301 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1302 idx1, es->psz_language_code );
1304 i_wanted = es->i_channel;
1306 else if( p_sys->i_default_sub_id >= 0 )
1308 if( es->i_id == p_sys->i_default_sub_id )
1309 i_wanted = es->i_channel;
1312 if( p_sys->i_sub_last >= 0 )
1313 i_wanted = p_sys->i_sub_last;
1315 if( p_sys->i_sub_id >= 0 )
1317 if( es->i_id == p_sys->i_sub_id )
1318 i_wanted = es->i_channel;
1323 else if( i_cat == VIDEO_ES )
1325 i_wanted = es->i_channel;
1328 if( i_wanted == es->i_channel && !EsIsSelected( es ) )
1329 EsSelect( out, es );
1332 /* FIXME TODO handle priority here */
1333 if( EsIsSelected( es ) )
1335 if( i_cat == AUDIO_ES )
1337 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1338 p_sys->p_es_audio &&
1339 p_sys->p_es_audio != es &&
1340 EsIsSelected( p_sys->p_es_audio ) )
1342 EsUnselect( out, p_sys->p_es_audio, false );
1344 p_sys->p_es_audio = es;
1346 else if( i_cat == SPU_ES )
1348 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1350 p_sys->p_es_sub != es &&
1351 EsIsSelected( p_sys->p_es_sub ) )
1353 EsUnselect( out, p_sys->p_es_sub, false );
1355 p_sys->p_es_sub = es;
1357 else if( i_cat == VIDEO_ES )
1359 p_sys->p_es_video = es;
1365 * Send a block for the given es_out
1367 * \param out the es_out to send from
1368 * \param es the es_out_id
1369 * \param p_block the data block to send
1371 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1373 es_out_sys_t *p_sys = out->p_sys;
1374 input_thread_t *p_input = p_sys->p_input;
1375 es_out_pgrm_t *p_pgrm = es->p_pgrm;
1379 if( es->fmt.i_cat == AUDIO_ES )
1380 i_delay = p_sys->i_audio_delay;
1381 else if( es->fmt.i_cat == SPU_ES )
1382 i_delay = p_sys->i_spu_delay;
1386 if( libvlc_stats (p_input) )
1388 vlc_mutex_lock( &p_input->p->counters.counters_lock );
1389 stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1390 p_block->i_buffer, &i_total );
1391 stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1392 (float)i_total, NULL );
1393 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1396 /* Mark preroll blocks */
1397 if( es->i_preroll_end >= 0 )
1399 int64_t i_date = p_block->i_pts;
1401 i_date = p_block->i_dts;
1403 if( i_date < es->i_preroll_end )
1404 p_block->i_flags |= BLOCK_FLAG_PREROLL;
1406 es->i_preroll_end = -1;
1409 if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1411 p_block->i_dts += i_delay;
1413 else if( p_block->i_dts > 0 )
1416 input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay;
1418 if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
1420 p_block->i_pts += i_delay;
1422 else if( p_block->i_pts > 0 )
1425 input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay;
1427 if ( p_block->i_rate == INPUT_RATE_DEFAULT &&
1428 es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
1430 mtime_t current_date = mdate();
1432 || p_block->i_pts > current_date + 10000000
1433 || current_date > p_block->i_pts )
1435 /* ETSI EN 300 472 Annex A : do not take into account the PTS
1436 * for teletext streams. */
1437 p_block->i_pts = current_date + 400000
1438 + p_input->i_pts_delay + i_delay;
1442 p_block->i_rate = p_sys->i_rate;
1444 /* TODO handle mute */
1446 ( es->fmt.i_cat != AUDIO_ES ||
1447 ( p_sys->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
1448 p_sys->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
1451 bool b_cc_new = false;
1453 input_DecoderDecode( es->p_dec, p_block );
1455 /* Check CC status */
1456 input_DecoderIsCcPresent( es->p_dec, pb_cc );
1457 for( i = 0; i < 4; i++ )
1459 static const vlc_fourcc_t fcc[4] = {
1460 VLC_FOURCC('c', 'c', '1', ' '),
1461 VLC_FOURCC('c', 'c', '2', ' '),
1462 VLC_FOURCC('c', 'c', '3', ' '),
1463 VLC_FOURCC('c', 'c', '4', ' '),
1465 static const char ppsz_description[4][18] = {
1466 N_("Closed captions 1"),
1467 N_("Closed captions 2"),
1468 N_("Closed captions 3"),
1469 N_("Closed captions 4"),
1473 if( es->pb_cc_present[i] || !pb_cc[i] )
1475 msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
1477 es_format_Init( &fmt, SPU_ES, fcc[i] );
1478 fmt.i_group = es->fmt.i_group;
1479 fmt.psz_description = strdup( _(ppsz_description[i] ) );
1480 es->pp_cc_es[i] = EsOutAdd( out, &fmt );
1481 es->pp_cc_es[i]->p_master = es;
1482 es_format_Clean( &fmt );
1485 es->pb_cc_present[i] = true;
1489 var_SetBool( p_sys->p_input, "intf-change", true );
1493 block_Release( p_block );
1499 /*****************************************************************************
1501 *****************************************************************************/
1502 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1504 es_out_sys_t *p_sys = out->p_sys;
1505 bool b_reselect = false;
1508 /* We don't try to reselect */
1511 while( !out->p_sys->p_input->b_die && es->p_dec )
1513 if( input_DecoderEmpty( es->p_dec ) )
1517 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1520 if( es->p_pgrm == p_sys->p_pgrm )
1521 EsOutESVarUpdate( out, es, true );
1523 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1526 if( es->p_pgrm->i_es == 0 )
1528 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1531 if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1532 p_sys->p_es_sub == es ) b_reselect = true;
1534 if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1535 if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1536 if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
1538 switch( es->fmt.i_cat )
1551 /* Re-select another track when needed */
1553 for( i = 0; i < p_sys->i_es; i++ )
1555 if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1556 EsOutSelect( out, p_sys->es[i], false );
1559 free( es->psz_language );
1560 free( es->psz_language_code );
1562 es_format_Clean( &es->fmt );
1568 * Control query handler
1570 * \param out the es_out to control
1571 * \param i_query A es_out query as defined in include/ninput.h
1572 * \param args a variable list of arguments for the query
1573 * \return VLC_SUCCESS or an error code
1575 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1577 es_out_sys_t *p_sys = out->p_sys;
1585 case ES_OUT_SET_ES_STATE:
1586 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1587 b = (bool) va_arg( args, int );
1588 if( b && !EsIsSelected( es ) )
1590 EsSelect( out, es );
1591 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
1593 else if( !b && EsIsSelected( es ) )
1595 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1600 case ES_OUT_GET_ES_STATE:
1601 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1602 pb = (bool*) va_arg( args, bool * );
1604 *pb = EsIsSelected( es );
1607 case ES_OUT_SET_ACTIVE:
1609 b = (bool) va_arg( args, int );
1610 p_sys->b_active = b;
1613 var_SetBool( p_sys->p_input, "intf-change", true );
1617 case ES_OUT_GET_ACTIVE:
1618 pb = (bool*) va_arg( args, bool * );
1619 *pb = p_sys->b_active;
1622 case ES_OUT_SET_MODE:
1623 i = (int) va_arg( args, int );
1624 if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1625 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1629 /* Reapply policy mode */
1630 for( i = 0; i < p_sys->i_es; i++ )
1632 if( EsIsSelected( p_sys->es[i] ) )
1634 EsUnselect( out, p_sys->es[i],
1635 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1638 for( i = 0; i < p_sys->i_es; i++ )
1640 EsOutSelect( out, p_sys->es[i], false );
1644 return VLC_EGENERIC;
1646 case ES_OUT_GET_MODE:
1647 pi = (int*) va_arg( args, int* );
1648 *pi = p_sys->i_mode;
1652 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1653 /* Special case NULL, NULL+i_cat */
1656 for( i = 0; i < p_sys->i_es; i++ )
1658 if( EsIsSelected( p_sys->es[i] ) )
1659 EsUnselect( out, p_sys->es[i],
1660 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1663 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1665 for( i = 0; i < p_sys->i_es; i++ )
1667 if( p_sys->es[i]->fmt.i_cat == AUDIO_ES &&
1668 EsIsSelected( p_sys->es[i] ) )
1669 EsUnselect( out, p_sys->es[i],
1670 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1673 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1675 for( i = 0; i < p_sys->i_es; i++ )
1677 if( p_sys->es[i]->fmt.i_cat == VIDEO_ES &&
1678 EsIsSelected( p_sys->es[i] ) )
1679 EsUnselect( out, p_sys->es[i],
1680 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1683 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1685 for( i = 0; i < p_sys->i_es; i++ )
1687 if( p_sys->es[i]->fmt.i_cat == SPU_ES &&
1688 EsIsSelected( p_sys->es[i] ) )
1689 EsUnselect( out, p_sys->es[i],
1690 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1695 for( i = 0; i < p_sys->i_es; i++ )
1697 if( es == p_sys->es[i] )
1699 EsOutSelect( out, es, true );
1706 event.type = vlc_InputSelectedStreamChanged;
1707 vlc_event_send( &p_sys->p_input->p->event_manager, &event );
1711 case ES_OUT_SET_DEFAULT:
1713 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1717 /*p_sys->i_default_video_id = -1;*/
1718 /*p_sys->i_default_audio_id = -1;*/
1719 p_sys->i_default_sub_id = -1;
1721 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1723 /*p_sys->i_default_video_id = -1;*/
1725 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1727 /*p_sys->i_default_audio_id = -1;*/
1729 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1731 p_sys->i_default_sub_id = -1;
1735 /*if( es->fmt.i_cat == VIDEO_ES )
1736 p_sys->i_default_video_id = es->i_id;
1738 if( es->fmt.i_cat == AUDIO_ES )
1739 p_sys->i_default_audio_id = es->i_id;
1741 if( es->fmt.i_cat == SPU_ES )
1742 p_sys->i_default_sub_id = es->i_id;
1747 case ES_OUT_SET_PCR:
1748 case ES_OUT_SET_GROUP_PCR:
1750 es_out_pgrm_t *p_pgrm = NULL;
1754 if( i_query == ES_OUT_SET_PCR )
1756 p_pgrm = p_sys->p_pgrm;
1761 i_group = (int)va_arg( args, int );
1762 for( i = 0; i < p_sys->i_pgrm; i++ )
1764 if( p_sys->pgrm[i]->i_id == i_group )
1766 p_pgrm = p_sys->pgrm[i];
1771 if( p_pgrm == NULL )
1772 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
1774 i_pcr = (int64_t)va_arg( args, int64_t );
1775 /* search program */
1776 input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr );
1780 case ES_OUT_RESET_PCR:
1781 for( i = 0; i < p_sys->i_pgrm; i++ )
1782 input_ClockResetPCR( &p_sys->pgrm[i]->clock );
1788 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1789 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1790 *pi_ts = input_ClockGetTS( p_sys->p_input,
1791 &p_sys->p_pgrm->clock, i_ts );
1794 return VLC_EGENERIC;
1796 case ES_OUT_GET_GROUP:
1797 pi = (int*) va_arg( args, int* );
1799 *pi = p_sys->p_pgrm->i_id;
1801 *pi = -1; /* FIXME */
1804 case ES_OUT_SET_GROUP:
1807 i = (int) va_arg( args, int );
1808 for( j = 0; j < p_sys->i_pgrm; j++ )
1810 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1811 if( p_pgrm->i_id == i )
1813 EsOutProgramSelect( out, p_pgrm );
1817 return VLC_EGENERIC;
1820 case ES_OUT_SET_FMT:
1822 /* This ain't pretty but is need by some demuxers (eg. Ogg )
1823 * to update the p_extra data */
1825 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1826 p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1827 if( es == NULL ) return VLC_EGENERIC;
1829 if( p_fmt->i_extra )
1831 es->fmt.i_extra = p_fmt->i_extra;
1832 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1833 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1835 if( !es->p_dec ) return VLC_SUCCESS;
1838 input_DecoderDelete( es->p_dec );
1839 es->p_dec = input_DecoderNew( p_sys->p_input,
1843 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1844 es->p_dec->fmt_in.p_extra =
1845 realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1846 memcpy( es->p_dec->fmt_in.p_extra,
1847 p_fmt->p_extra, p_fmt->i_extra );
1854 case ES_OUT_SET_NEXT_DISPLAY_TIME:
1858 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1859 i_date = (int64_t)va_arg( args, int64_t );
1861 if( !es || !es->p_dec )
1862 return VLC_EGENERIC;
1864 /* XXX We should call input_ClockGetTS but PCR has been reseted
1865 * and it will return 0, so we won't call input_ClockGetTS on all preroll samples
1866 * but that's ugly(more time discontinuity), it need to be improved -- fenrir */
1867 es->i_preroll_end = i_date;
1871 case ES_OUT_SET_GROUP_META:
1873 int i_group = (int)va_arg( args, int );
1874 vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1876 EsOutProgramMeta( out, i_group, p_meta );
1879 case ES_OUT_SET_GROUP_EPG:
1881 int i_group = (int)va_arg( args, int );
1882 vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1884 EsOutProgramEpg( out, i_group, p_epg );
1887 case ES_OUT_DEL_GROUP:
1889 int i_group = (int)va_arg( args, int );
1891 return EsOutProgramDel( out, i_group );
1895 msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1896 return VLC_EGENERIC;
1900 /****************************************************************************
1901 * LanguageGetName: try to expend iso639 into plain name
1902 ****************************************************************************/
1903 static char *LanguageGetName( const char *psz_code )
1905 const iso639_lang_t *pl;
1907 if( psz_code == NULL )
1909 return strdup( "" );
1912 if( strlen( psz_code ) == 2 )
1914 pl = GetLang_1( psz_code );
1916 else if( strlen( psz_code ) == 3 )
1918 pl = GetLang_2B( psz_code );
1919 if( !strcmp( pl->psz_iso639_1, "??" ) )
1921 pl = GetLang_2T( psz_code );
1926 return strdup( psz_code );
1929 if( !strcmp( pl->psz_iso639_1, "??" ) )
1931 return strdup( psz_code );
1935 if( *pl->psz_native_name )
1937 return strdup( pl->psz_native_name );
1939 return strdup( pl->psz_eng_name );
1943 /* Get a 2 char code */
1944 static char *LanguageGetCode( const char *psz_lang )
1946 const iso639_lang_t *pl;
1948 if( psz_lang == NULL || *psz_lang == '\0' )
1949 return strdup("??");
1951 for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1953 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1954 !strcasecmp( pl->psz_native_name, psz_lang ) ||
1955 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1956 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1957 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1961 if( pl->psz_iso639_1 != NULL )
1962 return strdup( pl->psz_iso639_1 );
1964 return strdup("??");
1967 static char **LanguageSplit( const char *psz_langs )
1974 if( psz_langs == NULL ) return NULL;
1976 psz_parser = psz_dup = strdup(psz_langs);
1978 while( psz_parser && *psz_parser )
1983 psz = strchr(psz_parser, ',' );
1984 if( psz ) *psz++ = '\0';
1986 if( !strcmp( psz_parser, "any" ) )
1988 TAB_APPEND( i_psz, ppsz, strdup("any") );
1992 psz_code = LanguageGetCode( psz_parser );
1993 if( strcmp( psz_code, "??" ) )
1995 TAB_APPEND( i_psz, ppsz, psz_code );
2008 TAB_APPEND( i_psz, ppsz, NULL );
2015 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
2019 if( !ppsz_langs || !psz_lang ) return -1;
2021 for( i = 0; ppsz_langs[i]; i++ )
2023 if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2024 !strcasecmp( ppsz_langs[i], "any" ) )
2033 /****************************************************************************
2035 * - add meta info to the playlist item
2036 ****************************************************************************/
2037 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
2039 es_out_sys_t *p_sys = out->p_sys;
2040 input_thread_t *p_input = p_sys->p_input;
2041 es_format_t *fmt = &es->fmt;
2045 /* Add stream info */
2046 if( asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ) == -1 )
2049 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
2050 "%.4s", (char*)&fmt->i_codec );
2052 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
2053 "%s", es->psz_language );
2055 /* Add information */
2056 switch( fmt->i_cat )
2059 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2060 _("Type"), _("Audio") );
2062 if( fmt->audio.i_channels > 0 )
2063 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
2064 "%u", fmt->audio.i_channels );
2066 if( fmt->audio.i_rate > 0 )
2068 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
2069 _("%u Hz"), fmt->audio.i_rate );
2070 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
2073 if( fmt->audio.i_bitspersample > 0 )
2074 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2075 _("Bits per sample"), "%u",
2076 fmt->audio.i_bitspersample );
2078 if( fmt->i_bitrate > 0 )
2080 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
2081 _("%u kb/s"), fmt->i_bitrate / 1000 );
2082 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
2087 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2088 _("Type"), _("Video") );
2090 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
2091 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2092 _("Resolution"), "%ux%u",
2093 fmt->video.i_width, fmt->video.i_height );
2095 if( fmt->video.i_visible_width > 0 &&
2096 fmt->video.i_visible_height > 0 )
2097 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2098 _("Display resolution"), "%ux%u",
2099 fmt->video.i_visible_width,
2100 fmt->video.i_visible_height);
2101 if( fmt->video.i_frame_rate > 0 &&
2102 fmt->video.i_frame_rate_base > 0 )
2104 div = lldiv( (float)fmt->video.i_frame_rate /
2105 fmt->video.i_frame_rate_base * 1000000,
2107 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2108 _("Frame rate"), "%"PRId64".%06u",
2109 div.quot, (unsigned int )div.rem );
2114 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2115 _("Type"), _("Subtitle") );