X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fes_out.c;h=0c562fb7e6d14c248cefc78743a66491da3072a9;hb=70ee5fbf988a94c0c2e394f3346a3dc6eeb18d72;hp=061dfed728c868f99827b869a15948fef3434088;hpb=bf12bbf66e7ed8a0762fd1e3227199b4e4255153;p=vlc diff --git a/src/input/es_out.c b/src/input/es_out.c index 061dfed728..0c562fb7e6 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -34,6 +34,8 @@ #include "vlc_playlist.h" #include "iso_lang.h" +/* FIXME we should find a better way than including that */ +#include "../misc/iso-639_def.h" /***************************************************************************** * Local prototypes @@ -59,10 +61,14 @@ struct es_out_id_t int i_id; es_out_pgrm_t *p_pgrm; + /* */ + int64_t i_preroll_end; + /* Channel in the track type */ int i_channel; es_format_t fmt; - char *psz_description; + char *psz_language; + char *psz_language_code; decoder_t *p_dec; }; @@ -93,6 +99,8 @@ struct es_out_sys_t /* es to select */ int i_audio_last; int i_sub_last; + char **ppsz_audio_language; + char **ppsz_sub_language; /* current main es */ es_out_id_t *p_es_audio; @@ -115,6 +123,9 @@ static void EsOutAddInfo( es_out_t *, 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 ); +static char *LanguageGetCode( const char *psz_lang ); +static char **LanguageSplit( const char *psz_langs ); +static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang ); /***************************************************************************** * input_EsOutNew: @@ -124,6 +135,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) es_out_t *out = malloc( sizeof( es_out_t ) ); es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) ); vlc_value_t val; + int i; out->pf_add = EsOutAdd; out->pf_send = EsOutSend; @@ -149,12 +161,32 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) p_sys->i_video = 0; p_sys->i_sub = 0; - var_Get( p_input, "audio-channel", &val ); + /* */ + var_Get( p_input, "audio-track", &val ); p_sys->i_audio_last = val.i_int; - var_Get( p_input, "spu-channel", &val ); + var_Get( p_input, "sub-track", &val ); p_sys->i_sub_last = val.i_int; + var_Get( p_input, "audio-language", &val ); + p_sys->ppsz_audio_language = LanguageSplit(val.psz_string); + if( p_sys->ppsz_audio_language ) + { + for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) + msg_Dbg( p_input, "Select audio in language[%d] %s", + i, p_sys->ppsz_audio_language[i] ); + } + + var_Get( p_input, "sub-language", &val ); + p_sys->ppsz_sub_language = LanguageSplit(val.psz_string); + if( p_sys->ppsz_sub_language ) + { + for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) + msg_Dbg( p_input, "Select subtitle in language[%d] %s", + i, p_sys->ppsz_sub_language[i] ); + } + + /* */ p_sys->p_es_audio = NULL; p_sys->p_es_video = NULL; p_sys->p_es_sub = NULL; @@ -179,12 +211,27 @@ void input_EsOutDelete( es_out_t *out ) { input_DecoderDelete( p_sys->es[i]->p_dec ); } - if( p_sys->es[i]->psz_description ) - free( p_sys->es[i]->psz_description ); + 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 ); es_format_Clean( &p_sys->es[i]->fmt ); free( p_sys->es[i] ); } + if( p_sys->ppsz_audio_language ) + { + for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) + free( p_sys->ppsz_audio_language[i] ); + free( p_sys->ppsz_audio_language ); + } + if( p_sys->ppsz_sub_language ) + { + for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) + free( p_sys->ppsz_sub_language[i] ); + free( p_sys->ppsz_sub_language ); + } + if( p_sys->es ) free( p_sys->es ); @@ -301,14 +348,30 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, } /* Take care of the ES description */ - if( es->psz_description && *es->psz_description ) + if( es->fmt.psz_description && *es->fmt.psz_description ) { - text.psz_string = strdup( es->psz_description ); + if( es->psz_language && *es->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 ); + } + else text.psz_string = strdup( es->fmt.psz_description ); } else { - text.psz_string = malloc( strlen( _("Track %i") ) + 20 ); - sprintf( text.psz_string, _("Track %i"), val.i_int ); + if( es->psz_language && *es->psz_language ) + { + char *temp; + text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 ); + asprintf( &temp, _("Track %i"), val.i_int ); + sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language ); + free( temp ); + } + else + { + text.psz_string = malloc( strlen( _("Track %i") ) + 20 ); + sprintf( text.psz_string, _("Track %i"), val.i_int ); + } } val.i_int = es->i_id; @@ -343,6 +406,10 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) p_sys->i_mode != ES_OUT_MODE_ALL ) EsUnselect( out, p_sys->es[i], VLC_TRUE ); } + + p_sys->p_es_audio = NULL; + p_sys->p_es_sub = NULL; + p_sys->p_es_video = NULL; } msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id ); @@ -368,7 +435,8 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); for( i = 0; i < p_sys->i_es; i++ ) { - EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE ); + if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm ) + EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE ); EsOutSelect( out, p_sys->es[i], VLC_FALSE ); } @@ -452,6 +520,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->i_id = fmt->i_id; es->p_pgrm = p_pgrm; es_format_Copy( &es->fmt, fmt ); + es->i_preroll_end = -1; + switch( fmt->i_cat ) { case AUDIO_ES: @@ -470,7 +540,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->i_channel = 0; break; } - es->psz_description = LanguageGetName( fmt->psz_language ); + 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; if( es->p_pgrm == p_sys->p_pgrm ) @@ -535,6 +606,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) } } + 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; @@ -645,23 +717,63 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) if( i_cat == AUDIO_ES ) { + int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language, + es->psz_language_code ); + if( p_sys->p_es_audio && p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority ) { - return; + int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language, + p_sys->p_es_audio->psz_language_code ); + + if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) ) + return; + i_wanted = es->i_channel; + } + else + { + /* Select audio if (no audio selected yet) + * - no audio-language + * - no audio code for the ES + * - audio code in the requested list */ + if( idx1 >= 0 || + !strcmp( es->psz_language_code, "??" ) || + !p_sys->ppsz_audio_language ) + i_wanted = es->i_channel; } - i_wanted = p_sys->i_audio_last >= 0 ? - p_sys->i_audio_last : es->i_channel; + + if( p_sys->i_audio_last >= 0 ) + i_wanted = p_sys->i_audio_last; } else if( i_cat == SPU_ES ) { + int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language, + es->psz_language_code ); + if( p_sys->p_es_sub && - p_sys->p_es_sub->fmt.i_priority >= - es->fmt.i_priority ) + p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority ) { - return; + int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language, + p_sys->p_es_sub->psz_language_code ); + + msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)", + idx1, es->psz_language_code, idx2, + p_sys->p_es_sub->psz_language_code ); + + if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) ) + return; + /* We found a SPU that matches our language request */ + i_wanted = es->i_channel; + } + else if( idx1 >= 0 ) + { + msg_Dbg( p_sys->p_input, "idx1=%d(%s)", + idx1, es->psz_language_code ); + + i_wanted = es->i_channel; } - i_wanted = p_sys->i_sub_last; + if( p_sys->i_sub_last >= 0 ) + i_wanted = p_sys->i_sub_last; } else if( i_cat == VIDEO_ES ) { @@ -738,8 +850,33 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) input_ClockGetTS( p_input, &p_pgrm->clock, ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay; } + if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) ) + { + mtime_t current_date = mdate(); + if( !p_block->i_pts + || p_block->i_pts > current_date + 10000000 + || current_date > p_block->i_pts ) + { + /* ETSI EN 300 472 Annex A : do not take into account the PTS + * for teletext streams. */ + p_block->i_pts = current_date + 400000 + + p_input->i_pts_delay + i_delay; + } + } p_block->i_rate = p_input->i_rate; + /* Mark preroll blocks */ + if( es->i_preroll_end >= 0 ) + { + int64_t i_date = p_block->i_pts; + if( i_date <= 0 ) + i_date = p_block->i_dts; + + if( i_date < es->i_preroll_end ) + p_block->i_flags |= BLOCK_FLAG_PREROLL; + else + es->i_preroll_end = -1; + } /* TODO handle mute */ if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || @@ -795,8 +932,10 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) break; } - if( es->psz_description ) - free( es->psz_description ); + if( es->psz_language ) + free( es->psz_language ); + if( es->psz_language_code ) + free( es->psz_language_code ); es_format_Clean( &es->fmt ); @@ -1048,6 +1187,22 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) return VLC_SUCCESS; } + case ES_OUT_SET_NEXT_DISPLAY_TIME: + { + int64_t i_date; + + es = (es_out_id_t*) va_arg( args, es_out_id_t * ); + i_date = (int64_t)va_arg( args, int64_t ); + + if( !es || !es->p_dec ) + return VLC_EGENERIC; + + es->i_preroll_end = i_date; + input_DecoderPreroll( es->p_dec, i_date ); + + return VLC_SUCCESS; + } + default: msg_Err( p_sys->p_input, "unknown query in es_out_Control" ); return VLC_EGENERIC; @@ -1097,6 +1252,84 @@ static char *LanguageGetName( const char *psz_code ) } } +/* Get a 2 char code */ +static char *LanguageGetCode( const char *psz_lang ) +{ + const iso639_lang_t *pl; + + if( psz_lang == NULL || *psz_lang == '\0' ) + return strdup("??"); + + for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ ) + { + if( !strcasecmp( pl->psz_eng_name, psz_lang ) || + !strcasecmp( pl->psz_native_name, psz_lang ) || + !strcasecmp( pl->psz_iso639_1, psz_lang ) || + !strcasecmp( pl->psz_iso639_2T, psz_lang ) || + !strcasecmp( pl->psz_iso639_2B, psz_lang ) ) + break; + } + + if( pl->psz_iso639_1 != NULL ) + return strdup( pl->psz_iso639_1 ); + + return strdup("??"); +} + +static char **LanguageSplit( const char *psz_langs ) +{ + char *psz_dup; + char *psz_parser; + char **ppsz = NULL; + int i_psz = 0; + + if( psz_langs == NULL ) + return NULL; + + psz_parser = psz_dup = strdup(psz_langs); + + while( psz_parser && *psz_parser ) + { + char *psz; + char *psz_code; + + psz = strchr(psz_parser, ',' ); + if( psz ) + { + *psz++ = '\0'; + } + + psz_code = LanguageGetCode( psz_parser ); + if( strcmp( psz_code, "??" ) ) + { + TAB_APPEND( i_psz, ppsz, psz_code ); + } + + psz_parser = psz; + } + + if( i_psz ) + { + TAB_APPEND( i_psz, ppsz, NULL ); + } + + return ppsz; +} + +static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang ) +{ + int i; + + if( !ppsz_langs || !psz_lang ) + return -1; + + for( i = 0; ppsz_langs[i]; i++ ) + if( !strcasecmp( ppsz_langs[i], psz_lang ) ) + return i; + + return -1; +} + /**************************************************************************** * EsOutAddInfo: * - add meta info to the playlist item @@ -1115,7 +1348,7 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) "%.4s", (char*)&fmt->i_codec ); input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"), - "%s", es->psz_description ); + "%s", es->psz_language ); /* Add information */ switch( fmt->i_cat )