X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fes_out.c;h=733d907dd874b2c7b720c749d9902d9fab2b4ade;hb=2e7e22467bd0ba3d9ef6cb2211fab3133ae40486;hp=504fff82ecb948ff3885db7dc2597455deb14489;hpb=79cb45a41bdeaca63eb5fa2f3c53913ce463c6a5;p=vlc diff --git a/src/input/es_out.c b/src/input/es_out.c index 504fff82ec..733d907dd8 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -25,14 +25,18 @@ /***************************************************************************** * Preamble *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include -#include #include #include #include +#include #include "input_internal.h" @@ -78,7 +82,15 @@ struct es_out_id_t es_format_t fmt; char *psz_language; char *psz_language_code; + decoder_t *p_dec; + + /* Fields for Video with CC */ + vlc_bool_t pb_cc_present[4]; + es_out_id_t *pp_cc_es[4]; + + /* Field for CC track from a master video */ + es_out_id_t *p_master; }; struct es_out_sys_t @@ -108,6 +120,7 @@ struct es_out_sys_t /* es to select */ int i_audio_last, i_audio_id; int i_sub_last, i_sub_id; + int i_default_sub_id; /* As specified in container; if applicable */ char **ppsz_audio_language; char **ppsz_sub_language; @@ -119,6 +132,9 @@ struct es_out_sys_t /* delay */ int64_t i_audio_delay; int64_t i_spu_delay; + + /* Rate used to rescale ES ts */ + int i_rate; }; static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * ); @@ -129,6 +145,7 @@ static int EsOutControl( es_out_t *, int i_query, va_list ); static void EsOutAddInfo( es_out_t *, es_out_id_t *es ); +static vlc_bool_t EsIsSelected( es_out_id_t *es ); static void EsSelect( es_out_t *out, es_out_id_t *es ); static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ); static char *LanguageGetName( const char *psz_code ); @@ -138,10 +155,28 @@ static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang ); static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm ); +static const vlc_fourcc_t EsOutFourccClosedCaptions[4] = { + VLC_FOURCC('c', 'c', '1', ' '), + VLC_FOURCC('c', 'c', '2', ' '), + VLC_FOURCC('c', 'c', '3', ' '), + VLC_FOURCC('c', 'c', '4', ' '), +}; +static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc ) +{ + int i; + for( i = 0; i < 4; i++ ) + { + if( fcc == EsOutFourccClosedCaptions[i] ) + return i; + } + return -1; +} + + /***************************************************************************** * input_EsOutNew: *****************************************************************************/ -es_out_t *input_EsOutNew( input_thread_t *p_input ) +es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate ) { es_out_t *out = malloc( sizeof( es_out_t ) ); es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) ); @@ -179,6 +214,8 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) var_Get( p_input, "sub-track", &val ); p_sys->i_sub_last = val.i_int; + p_sys->i_default_sub_id = -1; + if( !p_input->b_preparsing ) { var_Get( p_input, "audio-language", &val ); @@ -189,7 +226,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) msg_Dbg( p_input, "selected audio language[%d] %s", i, p_sys->ppsz_audio_language[i] ); } - if( val.psz_string ) free( val.psz_string ); + free( val.psz_string ); var_Get( p_input, "sub-language", &val ); p_sys->ppsz_sub_language = LanguageSplit(val.psz_string); @@ -199,7 +236,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) msg_Dbg( p_input, "selected subtitle language[%d] %s", i, p_sys->ppsz_sub_language[i] ); } - if( val.psz_string ) free( val.psz_string ); + free( val.psz_string ); } else { @@ -220,6 +257,8 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) p_sys->i_audio_delay= 0; p_sys->i_spu_delay = 0; + p_sys->i_rate = i_rate; + return out; } @@ -237,10 +276,8 @@ void input_EsOutDelete( es_out_t *out ) { input_DecoderDelete( p_sys->es[i]->p_dec ); } - if( p_sys->es[i]->psz_language ) - free( p_sys->es[i]->psz_language ); - if( p_sys->es[i]->psz_language_code ) - free( p_sys->es[i]->psz_language_code ); + free( p_sys->es[i]->psz_language ); + free( p_sys->es[i]->psz_language_code ); es_format_Clean( &p_sys->es[i]->fmt ); free( p_sys->es[i] ); @@ -258,19 +295,15 @@ void input_EsOutDelete( es_out_t *out ) free( p_sys->ppsz_sub_language ); } - if( p_sys->es ) - free( p_sys->es ); + free( p_sys->es ); /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */ for( i = 0; i < p_sys->i_pgrm; i++ ) { es_out_pgrm_t *p_pgrm = p_sys->pgrm[i]; - if( p_pgrm->psz_now_playing ) - free( p_pgrm->psz_now_playing ); - if( p_pgrm->psz_publisher ) - free( p_pgrm->psz_publisher ); - if( p_pgrm->psz_name ) - free( p_pgrm->psz_name ); + free( p_pgrm->psz_now_playing ); + free( p_pgrm->psz_publisher ); + free( p_pgrm->psz_name ); if( p_pgrm->p_epg ) vlc_epg_Delete( p_pgrm->p_epg ); @@ -299,7 +332,7 @@ es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id ) return NULL; } -void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio ) +static void EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio ) { es_out_sys_t *p_sys = out->p_sys; int i; @@ -314,6 +347,17 @@ void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_a input_DecoderDiscontinuity( es->p_dec, b_flush ); } } +void input_EsOutChangeRate( es_out_t *out, int i_rate ) +{ + es_out_sys_t *p_sys = out->p_sys; + int i; + + p_sys->i_rate = i_rate; + EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE ); + + for( i = 0; i < p_sys->i_pgrm; i++ ) + input_ClockSetRate( &p_sys->pgrm[i]->clock, i_rate ); +} void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) { @@ -324,6 +368,30 @@ void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) else if( i_cat == SPU_ES ) p_sys->i_spu_delay = i_delay; } +void input_EsOutChangeState( es_out_t *out ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + + if( p_input->i_state == PAUSE_S ) + { + /* Send discontinuity to decoders (it will allow them to flush + * * if implemented */ + EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE ); + } + else + { + /* Out of pause, reset pcr */ + es_out_Control( out, ES_OUT_RESET_PCR ); + } +} +void input_EsOutChangePosition( es_out_t *out ) +{ + //es_out_sys_t *p_sys = out->p_sys; + + es_out_Control( out, ES_OUT_RESET_PCR ); + EsOutDiscontinuity( out, VLC_TRUE, VLC_FALSE ); +} vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out ) { @@ -343,8 +411,8 @@ vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out ) /***************************************************************************** * *****************************************************************************/ -static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, - vlc_bool_t b_delete ) +static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language, + vlc_bool_t b_delete ) { es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; @@ -352,18 +420,18 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, const char *psz_var; - if( es->fmt.i_cat == AUDIO_ES ) + if( fmt->i_cat == AUDIO_ES ) psz_var = "audio-es"; - else if( es->fmt.i_cat == VIDEO_ES ) + else if( fmt->i_cat == VIDEO_ES ) psz_var = "video-es"; - else if( es->fmt.i_cat == SPU_ES ) + else if( fmt->i_cat == SPU_ES ) psz_var = "spu-es"; else return; if( b_delete ) { - val.i_int = es->i_id; + val.i_int = i_id; var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); return; @@ -382,26 +450,26 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, } /* Take care of the ES description */ - if( es->fmt.psz_description && *es->fmt.psz_description ) + if( fmt->psz_description && *fmt->psz_description ) { - if( es->psz_language && *es->psz_language ) + if( psz_language && *psz_language ) { - text.psz_string = malloc( strlen( es->fmt.psz_description) + - strlen( es->psz_language ) + 10 ); - sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, - es->psz_language ); + text.psz_string = malloc( strlen( fmt->psz_description) + + strlen( psz_language ) + 10 ); + sprintf( text.psz_string, "%s - [%s]", fmt->psz_description, + psz_language ); } - else text.psz_string = strdup( es->fmt.psz_description ); + else text.psz_string = strdup( fmt->psz_description ); } else { - if( es->psz_language && *es->psz_language ) + if( psz_language && *psz_language ) { char *temp; text.psz_string = malloc( strlen( _("Track %i") )+ - strlen( es->psz_language ) + 30 ); + strlen( psz_language ) + 30 ); asprintf( &temp, _("Track %i"), val.i_int ); - sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language ); + sprintf( text.psz_string, "%s - [%s]", temp, psz_language ); free( temp ); } else @@ -411,7 +479,7 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, } } - val.i_int = es->i_id; + val.i_int = i_id; var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text ); free( text.psz_string ); @@ -419,6 +487,12 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); } +static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, + vlc_bool_t b_delete ) +{ + EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete ); +} + /* EsOutProgramSelect: * Select a program and update the object variable */ @@ -439,7 +513,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec && + if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) && p_sys->i_mode != ES_OUT_MODE_ALL ) EsUnselect( out, p_sys->es[i], VLC_TRUE ); } @@ -478,10 +552,10 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) } /* Update now playing */ - vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, - p_pgrm->psz_now_playing ); - vlc_meta_SetPublisher( p_input->p->input.p_item->p_meta, - p_pgrm->psz_publisher ); + input_item_SetNowPlaying( p_input->p->input.p_item, + p_pgrm->psz_now_playing ); + input_item_SetPublisher( p_input->p->input.p_item, + p_pgrm->psz_publisher ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); } @@ -505,7 +579,7 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) p_pgrm->psz_now_playing = NULL; p_pgrm->psz_publisher = NULL; p_pgrm->p_epg = NULL; - input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average ); + input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average, p_sys->i_rate ); /* Append it */ TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm ); @@ -560,9 +634,9 @@ static int EsOutProgramDel( es_out_t *out, int i_group ) /* If program is selected we need to unselect it */ if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL; - if( p_pgrm->psz_name ) free( p_pgrm->psz_name ); - if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing ); - if( p_pgrm->psz_publisher ) free( p_pgrm->psz_publisher ); + free( p_pgrm->psz_name ); + free( p_pgrm->psz_now_playing ); + free( p_pgrm->psz_publisher ); if( p_pgrm->p_epg ) vlc_epg_Delete( p_pgrm->p_epg ); free( p_pgrm ); @@ -594,15 +668,20 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) es_out_pgrm_t *p_pgrm = NULL; input_thread_t *p_input = p_sys->p_input; char *psz_cat; - char *psz_title = NULL; - char *psz_provider = NULL; + const char *psz_title = NULL; + const char *psz_provider = NULL; int i; msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group ); /* Check against empty meta data (empty for what we handle) */ - if( !p_meta->psz_title && !p_meta->psz_nowplaying && !p_meta->psz_publisher && p_meta->i_extra <= 0 ) + if( !vlc_meta_Get( p_meta, vlc_meta_Title) && + !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) && + !vlc_meta_Get( p_meta, vlc_meta_Publisher) && + vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 ) + { return; + } /* Find program */ for( i = 0; i < p_sys->i_pgrm; i++ ) { @@ -616,8 +695,8 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */ /* */ - psz_title = p_meta->psz_title; - psz_provider = p_meta->psz_publisher; + psz_title = vlc_meta_Get( p_meta, vlc_meta_Title); + psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher); /* Update the description text of the program */ if( psz_title && *psz_title ) @@ -634,7 +713,7 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) /* TODO update epg name */ free( psz_cat ); } - if( p_pgrm->psz_name ) free( p_pgrm->psz_name ); + free( p_pgrm->psz_name ); p_pgrm->psz_name = strdup( psz_title ); /* ugly but it works */ @@ -649,7 +728,7 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) } else { - text.psz_string = psz_title; + text.psz_string = (char *)psz_title; var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); } } @@ -658,28 +737,20 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) if( psz_provider ) { if( p_sys->p_pgrm == p_pgrm ) - vlc_meta_SetPublisher( p_input->p->input.p_item->p_meta, psz_provider ); - input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(VLC_META_PUBLISHER), psz_provider ); + input_item_SetPublisher( p_input->p->input.p_item, psz_provider ); + input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider ); + } + char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags ); + for( i = 0; ppsz_all_keys[i]; i++ ) + { + input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]), + vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) ); + free( ppsz_all_keys[i] ); } - for( i = 0; i < p_meta->i_extra; i++ ) - input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(p_meta->ppsz_extra_name[i]), p_meta->ppsz_extra_value[i] ); + free( ppsz_all_keys ); free( psz_cat ); } -#define TAB_INSERT_CAST( cast, count, tab, p, index ) do { \ - if( (count) > 0 ) \ - (tab) = cast realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \ - else \ - (tab) = cast malloc( sizeof( void ** ) ); \ - if( (count) - (index) > 0 ) \ - memmove( (void**)(tab) + (index) + 1, \ - (void**)(tab) + (index), \ - ((count) - (index)) * sizeof(*(tab)) );\ - (tab)[(index)] = (p); \ - (count)++; \ -} while(0) - -#define TAB_INSERT( count, tab, p, index ) TAB_INSERT_CAST( , count, tab, p, index ) static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src ) { @@ -733,7 +804,6 @@ static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg ) input_thread_t *p_input = p_sys->p_input; es_out_pgrm_t *p_pgrm = NULL; char *psz_cat; - char *psz_epg; int i; /* Find program */ @@ -756,7 +826,9 @@ static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg ) /* Update info */ psz_cat = EsOutProgramGetMetaName( p_pgrm ); #ifdef HAVE_LOCALTIME_R - asprintf( &psz_epg, "EPG %s", psz_cat ); + char *psz_epg; + if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 ) + psz_epg = NULL; input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL ); msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name ); for( i = 0; i < p_pgrm->p_epg->i_event; i++ ) @@ -782,23 +854,26 @@ static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg ) free( psz_epg ); #endif /* Update now playing */ - if( p_pgrm->psz_now_playing ) - free( p_pgrm->psz_now_playing ); + free( p_pgrm->psz_now_playing ); p_pgrm->psz_now_playing = NULL; - if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name ) - { p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name ); - if( p_pgrm == p_sys->p_pgrm ) - vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, p_pgrm->psz_now_playing ); - input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(VLC_META_NOW_PLAYING), p_pgrm->psz_now_playing ); + + if( p_pgrm == p_sys->p_pgrm ) + input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing ); + + if( p_pgrm->psz_now_playing ) + { + input_Control( p_input, INPUT_ADD_INFO, psz_cat, + input_MetaTypeToLocalizedString(vlc_meta_NowPlaying), + p_pgrm->psz_now_playing ); } else { - if( p_pgrm == p_sys->p_pgrm ) - vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, NULL ); - input_Control( p_input, INPUT_DEL_INFO, psz_cat, _(VLC_META_NOW_PLAYING) ); + input_Control( p_input, INPUT_DEL_INFO, psz_cat, + input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) ); } + free( psz_cat ); } @@ -849,8 +924,31 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) switch( fmt->i_cat ) { case AUDIO_ES: + { + audio_replay_gain_t rg; + es->i_channel = p_sys->i_audio; + + vlc_mutex_lock( &p_input->p->input.p_item->lock ); + memset( &rg, 0, sizeof(rg) ); + vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta ); + vlc_mutex_unlock( &p_input->p->input.p_item->lock ); + + for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ ) + { + if( !es->fmt.audio_replay_gain.pb_peak[i] ) + { + es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i]; + es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i]; + } + if( !es->fmt.audio_replay_gain.pb_gain[i] ) + { + es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i]; + es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i]; + } + } break; + } case VIDEO_ES: es->i_channel = p_sys->i_video; @@ -872,6 +970,9 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */ es->psz_language_code = LanguageGetCode( fmt->psz_language ); es->p_dec = NULL; + for( i = 0; i < 4; i++ ) + es->pb_cc_present[i] = VLC_FALSE; + es->p_master = VLC_FALSE; if( es->p_pgrm == p_sys->p_pgrm ) EsOutESVarUpdate( out, es, VLC_FALSE ); @@ -900,6 +1001,24 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) return es; } +static vlc_bool_t EsIsSelected( es_out_id_t *es ) +{ + if( es->p_master ) + { + vlc_bool_t b_decode = VLC_FALSE; + if( es->p_master->p_dec ) + { + int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec ); + if( i_channel != -1 ) + input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel ); + } + return b_decode; + } + else + { + return es->p_dec != NULL; + } +} static void EsSelect( es_out_t *out, es_out_id_t *es ) { es_out_sys_t *p_sys = out->p_sys; @@ -907,49 +1026,62 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) vlc_value_t val; const char *psz_var; - if( es->p_dec ) + if( EsIsSelected( es ) ) { msg_Warn( p_input, "ES 0x%x is already selected", es->i_id ); return; } - if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES ) + if( es->p_master ) { - if( !var_GetBool( p_input, "video" ) || - ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) ) - { - msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x", - es->i_id ); + int i_channel; + if( !es->p_master->p_dec ) + return; + + i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec ); + if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, VLC_TRUE, i_channel ) ) return; - } } - else if( es->fmt.i_cat == AUDIO_ES ) + else { - var_Get( p_input, "audio", &val ); - if( !var_GetBool( p_input, "audio" ) || - ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) ) + if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES ) { - msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x", - es->i_id ); - return; + if( !var_GetBool( p_input, "video" ) || + ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) ) + { + msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x", + es->i_id ); + return; + } } - } - if( es->fmt.i_cat == SPU_ES ) - { - var_Get( p_input, "spu", &val ); - if( !var_GetBool( p_input, "spu" ) || - ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) ) + else if( es->fmt.i_cat == AUDIO_ES ) { - msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x", - es->i_id ); - return; + var_Get( p_input, "audio", &val ); + if( !var_GetBool( p_input, "audio" ) || + ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) ) + { + msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x", + es->i_id ); + return; + } + } + if( es->fmt.i_cat == SPU_ES ) + { + var_Get( p_input, "spu", &val ); + if( !var_GetBool( p_input, "spu" ) || + ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) ) + { + msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x", + es->i_id ); + return; + } } - } - es->i_preroll_end = -1; - es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE ); - if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) - return; + es->i_preroll_end = -1; + es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE ); + if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) + return; + } if( es->fmt.i_cat == VIDEO_ES ) psz_var = "video-es"; @@ -964,7 +1096,6 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) val.i_int = es->i_id; var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); } @@ -975,14 +1106,45 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) vlc_value_t val; const char *psz_var; - if( es->p_dec == NULL ) + if( !EsIsSelected( es ) ) { msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id ); return; } - input_DecoderDelete( es->p_dec ); - es->p_dec = NULL; + if( es->p_master ) + { + if( es->p_master->p_dec ) + { + int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec ); + if( i_channel != -1 ) + input_DecoderSetCcState( es->p_master->p_dec, VLC_FALSE, i_channel ); + } + } + else + { + const int i_spu_id = var_GetInteger( p_input, "spu-es"); + int i; + for( i = 0; i < 4; i++ ) + { + if( !es->pb_cc_present[i] || !es->pp_cc_es[i] ) + continue; + + if( i_spu_id == es->pp_cc_es[i]->i_id ) + { + /* Force unselection of the CC */ + val.i_int = -1; + var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL ); + if( !b_update ) + var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + } + EsOutDel( out, es->pp_cc_es[i] ); + + es->pb_cc_present[i] = VLC_FALSE; + } + input_DecoderDelete( es->p_dec ); + es->p_dec = NULL; + } if( !b_update ) return; @@ -999,7 +1161,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) else return; - /* Mark it as selected */ + /* Mark it as unselected */ val.i_int = -1; var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL ); @@ -1029,7 +1191,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force ) { - if( !es->p_dec ) + if( !EsIsSelected( es ) ) EsSelect( out, es ); } else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL ) @@ -1041,7 +1203,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) { if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force ) { - if( !es->p_dec ) + if( !EsIsSelected( es ) ) EsSelect( out, es ); break; } @@ -1120,6 +1282,12 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) i_wanted = es->i_channel; } + else if( p_sys->i_default_sub_id >= 0 ) + { + if( es->i_id == p_sys->i_default_sub_id ) + i_wanted = es->i_channel; + } + if( p_sys->i_sub_last >= 0 ) i_wanted = p_sys->i_sub_last; @@ -1136,19 +1304,19 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) i_wanted = es->i_channel; } - if( i_wanted == es->i_channel && es->p_dec == NULL ) + if( i_wanted == es->i_channel && !EsIsSelected( es ) ) EsSelect( out, es ); } /* FIXME TODO handle priority here */ - if( es->p_dec ) + if( EsIsSelected( es ) ) { if( i_cat == AUDIO_ES ) { if( p_sys->i_mode == ES_OUT_MODE_AUTO && p_sys->p_es_audio && p_sys->p_es_audio != es && - p_sys->p_es_audio->p_dec ) + EsIsSelected( p_sys->p_es_audio ) ) { EsUnselect( out, p_sys->p_es_audio, VLC_FALSE ); } @@ -1159,7 +1327,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) if( p_sys->i_mode == ES_OUT_MODE_AUTO && p_sys->p_es_sub && p_sys->p_es_sub != es && - p_sys->p_es_sub->p_dec ) + EsIsSelected( p_sys->p_es_sub ) ) { EsUnselect( out, p_sys->p_es_sub, VLC_FALSE ); } @@ -1217,7 +1385,6 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) es->i_preroll_end = -1; } - /* +11 -> avoid null value with non null dts/pts */ if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) ) { p_block->i_dts += i_delay; @@ -1225,8 +1392,7 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) else if( p_block->i_dts > 0 ) { p_block->i_dts = - input_ClockGetTS( p_input, &p_pgrm->clock, - ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay; + input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay; } if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) ) { @@ -1235,8 +1401,7 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) else if( p_block->i_pts > 0 ) { p_block->i_pts = - input_ClockGetTS( p_input, &p_pgrm->clock, - ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay; + input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay; } if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) ) { @@ -1252,13 +1417,54 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) } } - p_block->i_rate = p_input->p->i_rate; + p_block->i_rate = p_sys->i_rate; /* TODO handle mute */ - if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || - p_input->p->i_rate == INPUT_RATE_DEFAULT ) ) + if( es->p_dec && + ( es->fmt.i_cat != AUDIO_ES || + ( p_sys->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE && + p_sys->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) ) { + vlc_bool_t pb_cc[4]; + vlc_bool_t b_cc_new = VLC_FALSE; + int i; input_DecoderDecode( es->p_dec, p_block ); + + /* Check CC status */ + input_DecoderIsCcPresent( es->p_dec, pb_cc ); + for( i = 0; i < 4; i++ ) + { + static const vlc_fourcc_t fcc[4] = { + VLC_FOURCC('c', 'c', '1', ' '), + VLC_FOURCC('c', 'c', '2', ' '), + VLC_FOURCC('c', 'c', '3', ' '), + VLC_FOURCC('c', 'c', '4', ' '), + }; + static const char *ppsz_description[4] = { + N_("Closed captions 1"), + N_("Closed captions 2"), + N_("Closed captions 3"), + N_("Closed captions 4"), + }; + es_format_t fmt; + + if( es->pb_cc_present[i] || !pb_cc[i] ) + continue; + msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id ); + + es_format_Init( &fmt, SPU_ES, fcc[i] ); + fmt.i_group = es->fmt.i_group; + fmt.psz_description = strdup( _(ppsz_description[i] ) ); + es->pp_cc_es[i] = EsOutAdd( out, &fmt ); + es->pp_cc_es[i]->p_master = es; + es_format_Clean( &fmt ); + + /* */ + es->pb_cc_present[i] = VLC_TRUE; + b_cc_new = VLC_TRUE; + } + if( b_cc_new ) + var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); } else { @@ -1328,10 +1534,8 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) EsOutSelect( out, p_sys->es[i], VLC_FALSE ); } - if( es->psz_language ) - free( es->psz_language ); - if( es->psz_language_code ) - free( es->psz_language_code ); + free( es->psz_language ); + free( es->psz_language_code ); es_format_Clean( &es->fmt ); @@ -1358,13 +1562,13 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { case ES_OUT_SET_ES_STATE: es = (es_out_id_t*) va_arg( args, es_out_id_t * ); - b = (vlc_bool_t) va_arg( args, vlc_bool_t ); - if( b && es->p_dec == NULL ) + b = (bool) va_arg( args, int ); + if( b && !EsIsSelected( es ) ) { EsSelect( out, es ); - return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC; + return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC; } - else if( !b && es->p_dec ) + else if( !b && EsIsSelected( es ) ) { EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm ); return VLC_SUCCESS; @@ -1375,12 +1579,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) es = (es_out_id_t*) va_arg( args, es_out_id_t * ); pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * ); - *pb = es->p_dec ? VLC_TRUE : VLC_FALSE; + *pb = EsIsSelected( es ); return VLC_SUCCESS; case ES_OUT_SET_ACTIVE: { - b = (vlc_bool_t) va_arg( args, vlc_bool_t ); + b = (bool) va_arg( args, int ); p_sys->b_active = b; /* Needed ? */ if( b ) @@ -1403,7 +1607,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) /* Reapply policy mode */ for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_dec ) + if( EsIsSelected( p_sys->es[i] ) ) { EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); @@ -1429,7 +1633,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_dec ) + if( EsIsSelected( p_sys->es[i] ) ) EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); } @@ -1438,8 +1642,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_dec && - p_sys->es[i]->fmt.i_cat == AUDIO_ES ) + if( p_sys->es[i]->fmt.i_cat == AUDIO_ES && + EsIsSelected( p_sys->es[i] ) ) EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); } @@ -1448,8 +1652,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_dec && - p_sys->es[i]->fmt.i_cat == VIDEO_ES ) + if( p_sys->es[i]->fmt.i_cat == VIDEO_ES && + EsIsSelected( p_sys->es[i] ) ) EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); } @@ -1458,8 +1662,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_dec && - p_sys->es[i]->fmt.i_cat == SPU_ES ) + if( p_sys->es[i]->fmt.i_cat == SPU_ES && + EsIsSelected( p_sys->es[i] ) ) EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); } @@ -1479,11 +1683,47 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) playlist_t * p_playlist = pl_Yield( p_sys->p_input ); PL_LOCK; p_playlist->gc_date = mdate(); - vlc_cond_signal( &p_playlist->object_wait ); + vlc_object_signal_unlocked( p_playlist ); PL_UNLOCK; pl_Release( p_playlist ); } return VLC_SUCCESS; + + case ES_OUT_SET_DEFAULT: + { + es = (es_out_id_t*) va_arg( args, es_out_id_t * ); + + if( es == NULL ) + { + /*p_sys->i_default_video_id = -1;*/ + /*p_sys->i_default_audio_id = -1;*/ + p_sys->i_default_sub_id = -1; + } + else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) ) + { + /*p_sys->i_default_video_id = -1;*/ + } + else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) ) + { + /*p_sys->i_default_audio_id = -1;*/ + } + else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) ) + { + p_sys->i_default_sub_id = -1; + } + else + { + /*if( es->fmt.i_cat == VIDEO_ES ) + p_sys->i_default_video_id = es->i_id; + else + if( es->fmt.i_cat == AUDIO_ES ) + p_sys->i_default_audio_id = es->i_id; + else*/ + if( es->fmt.i_cat == SPU_ES ) + p_sys->i_default_sub_id = es->i_id; + } + return VLC_SUCCESS; + } case ES_OUT_SET_PCR: case ES_OUT_SET_GROUP_PCR: @@ -1514,18 +1754,13 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) i_pcr = (int64_t)va_arg( args, int64_t ); /* search program */ - /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */ - input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, - (i_pcr + 11 ) * 9 / 100); + input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr ); return VLC_SUCCESS; } case ES_OUT_RESET_PCR: for( i = 0; i < p_sys->i_pgrm; i++ ) - { - p_sys->pgrm[i]->clock.i_synchro_state = SYNCHRO_REINIT; - p_sys->pgrm[i]->clock.last_pts = 0; - } + input_ClockResetPCR( &p_sys->pgrm[i]->clock ); return VLC_SUCCESS; case ES_OUT_GET_TS: @@ -1534,8 +1769,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) int64_t i_ts = (int64_t)va_arg( args, int64_t ); int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * ); *pi_ts = input_ClockGetTS( p_sys->p_input, - &p_sys->p_pgrm->clock, - ( i_ts + 11 ) * 9 / 100 ); + &p_sys->p_pgrm->clock, i_ts ); return VLC_SUCCESS; } return VLC_EGENERIC; @@ -1730,10 +1964,21 @@ static char **LanguageSplit( const char *psz_langs ) psz = strchr(psz_parser, ',' ); if( psz ) *psz++ = '\0'; - psz_code = LanguageGetCode( psz_parser ); - if( strcmp( psz_code, "??" ) ) + if( !strcmp( psz_parser, "any" ) ) { - TAB_APPEND( i_psz, ppsz, psz_code ); + TAB_APPEND( i_psz, ppsz, strdup("any") ); + } + else + { + psz_code = LanguageGetCode( psz_parser ); + if( strcmp( psz_code, "??" ) ) + { + TAB_APPEND( i_psz, ppsz, psz_code ); + } + else + { + free( psz_code ); + } } psz_parser = psz; @@ -1755,7 +2000,13 @@ static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang ) if( !ppsz_langs || !psz_lang ) return -1; for( i = 0; ppsz_langs[i]; i++ ) - if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i; + { + if( !strcasecmp( ppsz_langs[i], psz_lang ) || + !strcasecmp( ppsz_langs[i], "any" ) ) + { + return i; + } + } return -1; } @@ -1790,24 +2041,24 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) if( fmt->audio.i_channels > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"), - "%d", fmt->audio.i_channels ); + "%u", fmt->audio.i_channels ); if( fmt->audio.i_rate > 0 ) { input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"), - _("%d Hz"), fmt->audio.i_rate ); + _("%u Hz"), fmt->audio.i_rate ); var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate ); } if( fmt->audio.i_bitspersample > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Bits per sample"), "%d", + _("Bits per sample"), "%u", fmt->audio.i_bitspersample ); if( fmt->i_bitrate > 0 ) { input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"), - _("%d kb/s"), fmt->i_bitrate / 1000 ); + _("%u kb/s"), fmt->i_bitrate / 1000 ); var_SetInteger( p_input, "bit-rate", fmt->i_bitrate ); } break; @@ -1818,13 +2069,13 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) if( fmt->video.i_width > 0 && fmt->video.i_height > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Resolution"), "%dx%d", + _("Resolution"), "%ux%u", fmt->video.i_width, fmt->video.i_height ); if( fmt->video.i_visible_width > 0 && fmt->video.i_visible_height > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Display resolution"), "%dx%d", + _("Display resolution"), "%ux%u", fmt->video.i_visible_width, fmt->video.i_visible_height); if( fmt->video.i_frame_rate > 0 &&