int i_video;
int i_sub;
- /* es to select */
+ /* es/group to select */
+ int i_group_id;
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 */
/* Clock configuration */
mtime_t i_pts_delay;
+ mtime_t i_pts_jitter;
int i_cr_average;
int i_rate;
static char *LanguageGetName( const char *psz_code );
static char *LanguageGetCode( const char *psz_lang );
-static char **LanguageSplit( const char *psz_langs );
+static char **LanguageSplit( const char *psz_langs, bool b_default_any );
static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
p_sys->i_sub = 0;
/* */
+ p_sys->i_group_id = var_GetInteger( p_input, "program" );
+
p_sys->i_audio_last = var_GetInteger( p_input, "audio-track" );
p_sys->i_sub_last = var_GetInteger( p_input, "sub-track" );
char *psz_string;
psz_string = var_GetString( p_input, "audio-language" );
- p_sys->ppsz_audio_language = LanguageSplit( psz_string );
+ p_sys->ppsz_audio_language = LanguageSplit( psz_string, true );
if( p_sys->ppsz_audio_language )
{
for( int i = 0; p_sys->ppsz_audio_language[i]; i++ )
free( psz_string );
psz_string = var_GetString( p_input, "sub-language" );
- p_sys->ppsz_sub_language = LanguageSplit( psz_string );
+ p_sys->ppsz_sub_language = LanguageSplit( psz_string, false );
if( p_sys->ppsz_sub_language )
{
for( int i = 0; p_sys->ppsz_sub_language[i]; i++ )
p_sys->i_rate = i_rate;
p_sys->i_pts_delay = 0;
+ p_sys->i_pts_jitter = 0;
p_sys->i_cr_average = 0;
p_sys->b_buffering = true;
if( i_stream_duration <= i_buffering_duration && !b_forced )
{
- const double f_level = (double)i_stream_duration / i_buffering_duration;
+ const double f_level = __MAX( (double)i_stream_duration / i_buffering_duration, 0 );
input_SendEventCache( p_sys->p_input, f_level );
msg_Dbg( p_sys->p_input, "Buffering %d%%", (int)(100 * f_level) );
if( p_es->p_dec_record )
i_size += input_DecoderGetFifoSize( p_es->p_dec_record );
}
- //fprintf( stderr, "----- EsOutIsExtraBufferingAllowed =% 5d kbytes -- ", i_size / 1024 );
+ //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
/* TODO maybe we want to be able to tune it ? */
#if defined(OPTIMIZE_MEMORY)
- const size_t i_level_high = 500000; /* 0.5 Mbytes */
+ const size_t i_level_high = 512*1024; /* 0.5 MiB */
#else
- const size_t i_level_high = 10000000; /* 10 Mbytes */
+ const size_t i_level_high = 10*1024*1024; /* 10 MiB */
#endif
return i_size < i_level_high;
}
{
if( psz_language && *psz_language )
{
- if( asprintf( &text.psz_string, "%s %i - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
+ if( asprintf( &text.psz_string, "%s %"PRId64" - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
text.psz_string = NULL;
}
else
{
- if( asprintf( &text.psz_string, "%s %i", _( "Track" ), val.i_int ) == -1 )
+ if( asprintf( &text.psz_string, "%s %"PRId64, _( "Track" ), val.i_int ) == -1 )
text.psz_string = NULL;
}
}
EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
}
+static bool EsOutIsProgramVisible( es_out_t *out, int i_group )
+{
+ return out->p_sys->i_group_id == 0 || out->p_sys->i_group_id == i_group;
+}
+
/* EsOutProgramSelect:
* Select a program and update the object variable
*/
TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
/* Update "program" variable */
- input_SendEventProgramAdd( p_input, i_group, NULL );
+ if( EsOutIsProgramVisible( out, i_group ) )
+ input_SendEventProgramAdd( p_input, i_group, NULL );
- if( i_group == var_GetInteger( p_input, "program" ) )
+ if( i_group == p_sys->i_group_id || ( !p_sys->p_pgrm && p_sys->i_group_id == 0 ) )
EsOutProgramSelect( out, p_pgrm );
return p_pgrm;
return;
}
/* Find program */
+ if( !EsOutIsProgramVisible( out, i_group ) )
+ return;
p_pgrm = EsOutProgramFind( out, i_group );
if( !p_pgrm )
return;
char **ppsz_all_keys = vlc_meta_CopyExtraNames(p_meta );
info_category_t *p_cat = NULL;
- if( psz_provider || *ppsz_all_keys[0] )
+ if( psz_provider || ( ppsz_all_keys[0] && *ppsz_all_keys[0] ) )
{
char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
if( psz_cat )
char *psz_cat;
/* Find program */
+ if( !EsOutIsProgramVisible( out, i_group ) )
+ return;
p_pgrm = EsOutProgramFind( out, i_group );
if( !p_pgrm )
return;
es->fmt.i_id = out->p_sys->i_id;
if( !es->fmt.i_original_fourcc )
es->fmt.i_original_fourcc = es->fmt.i_codec;
- es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat, es->fmt.i_codec );
+ if( es->fmt.i_cat == AUDIO_ES )
+ es->fmt.i_codec = vlc_fourcc_GetCodecAudio( es->fmt.i_codec,
+ es->fmt.audio.i_bitspersample );
+ else
+ es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat,
+ es->fmt.i_codec );
es->i_id = es->fmt.i_id;
es->i_meta_id = out->p_sys->i_id;
}
else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
{
- vlc_value_t val;
- int i;
- var_Get( p_sys->p_input, "programs", &val );
- for ( i = 0; i < val.p_list->i_count; i++ )
+ char *prgms = var_GetNonEmptyString( p_sys->p_input, "programs" );
+ if( prgms != NULL )
{
- if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
+ char *buf;
+
+ for ( const char *prgm = strtok_r( prgms, ",", &buf );
+ prgm != NULL;
+ prgm = strtok_r( NULL, ",", &buf ) )
{
- if( !EsIsSelected( es ) )
- EsSelect( out, es );
- break;
+ if( atoi( prgm ) == es->p_pgrm->i_id || b_force )
+ {
+ if( !EsIsSelected( es ) )
+ EsSelect( out, es );
+ break;
+ }
}
+ free( prgms );
}
- var_FreeList( &val, NULL );
}
else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
{
return VLC_SUCCESS;
}
+ case ES_OUT_GET_GROUP_FORCED:
+ {
+ int *pi_group = va_arg( args, int * );
+ *pi_group = p_sys->i_group_id;
+ return VLC_SUCCESS;
+ }
+
case ES_OUT_SET_MODE:
{
const int i_mode = va_arg( args, int );
else if( b_late && ( !p_sys->p_input->p->p_sout ||
!p_sys->p_input->p->b_out_pace_control ) )
{
+ const mtime_t i_pts_delay_base = p_sys->i_pts_delay - p_sys->i_pts_jitter;
mtime_t i_pts_delay = input_clock_GetJitter( p_pgrm->p_clock );
/* Avoid dangerously high value */
- const mtime_t i_pts_delay_max = 30000000;
- if( i_pts_delay > i_pts_delay_max )
- i_pts_delay = __MAX( i_pts_delay_max, p_sys->i_pts_delay );
+ const mtime_t i_jitter_max = INT64_C(1000) * var_InheritInteger( p_sys->p_input, "clock-jitter" );
+ if( i_pts_delay > __MIN( i_pts_delay_base + i_jitter_max, INPUT_PTS_DELAY_MAX ) )
+ {
+ msg_Err( p_sys->p_input,
+ "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
+ (int)(i_pts_delay - i_pts_delay_base) / 1000 );
+ i_pts_delay = p_sys->i_pts_delay;
+ }
+ else
+ {
+ msg_Err( p_sys->p_input,
+ "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
+ (int)(i_pts_delay/1000) );
+ }
/* Force a rebufferization when we are too late */
- msg_Err( p_sys->p_input,
- "ES_OUT_SET_(GROUP_)PCR is called too late, increasing pts_delay to %d ms",
- (int)(i_pts_delay/1000) );
/* It is not really good, as we throw away already buffered data
* TODO have a mean to correctly reenter bufferization */
es_out_Control( out, ES_OUT_RESET_PCR );
- es_out_Control( out, ES_OUT_SET_JITTER, i_pts_delay, p_sys->i_cr_average );
+ es_out_SetJitter( out, i_pts_delay_base, i_pts_delay - i_pts_delay_base, p_sys->i_cr_average );
}
}
return VLC_SUCCESS;
}
case ES_OUT_SET_JITTER:
{
- mtime_t i_pts_delay = (mtime_t)va_arg( args, mtime_t );
+ mtime_t i_pts_delay = (mtime_t)va_arg( args, mtime_t );
+ mtime_t i_pts_jitter = (mtime_t)va_arg( args, mtime_t );
int i_cr_average = (int)va_arg( args, int );
- if( i_pts_delay == p_sys->i_pts_delay &&
- i_cr_average == p_sys->i_cr_average )
- return VLC_SUCCESS;
+ bool b_change_clock =
+ i_pts_delay + i_pts_jitter != p_sys->i_pts_delay ||
+ i_cr_average != p_sys->i_cr_average;
- p_sys->i_pts_delay = i_pts_delay;
+ assert( i_pts_jitter >= 0 );
+ p_sys->i_pts_delay = i_pts_delay + i_pts_jitter;
+ p_sys->i_pts_jitter = i_pts_jitter;
p_sys->i_cr_average = i_cr_average;
- for( int i = 0; i < p_sys->i_pgrm; i++ )
+ for( int i = 0; i < p_sys->i_pgrm && b_change_clock; i++ )
input_clock_SetJitter( p_sys->pgrm[i]->p_clock,
- i_pts_delay, i_cr_average );
+ i_pts_delay + i_pts_jitter, i_cr_average );
return VLC_SUCCESS;
}
{
const iso639_lang_t *pl;
- if( psz_code == NULL )
+ if( psz_code == NULL || !strcmp( psz_code, "und" ) )
{
return strdup( "" );
}
return strdup("??");
}
-static char **LanguageSplit( const char *psz_langs )
+static char **LanguageSplit( const char *psz_langs, bool b_default_any )
{
char *psz_dup;
char *psz_parser;
{
TAB_APPEND( i_psz, ppsz, strdup("any") );
}
+ else if( !strcmp( psz_parser, "none" ) )
+ {
+ TAB_APPEND( i_psz, ppsz, strdup("none") );
+ }
else
{
psz_code = LanguageGetCode( psz_parser );
if( i_psz )
{
+ if( b_default_any && strcmp( ppsz[i_psz - 1], "none" ) )
+ TAB_APPEND( i_psz, ppsz, strdup("any") );
TAB_APPEND( i_psz, ppsz, NULL );
}
{
if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
!strcasecmp( ppsz_langs[i], "any" ) )
- {
return i;
- }
+ if( !strcasecmp( ppsz_langs[i], "none" ) )
+ break;
}
return -1;
if( !p_cat )
return;
- /* Add informations */
+ /* Add information */
const char *psz_type;
switch( fmt->i_cat )
{
const char *psz_codec_description =
vlc_fourcc_GetDescription( p_fmt_es->i_cat, p_fmt_es->i_codec );
- const vlc_fourcc_t i_codec_fourcc = p_fmt_es->i_original_fourcc ?: p_fmt_es->i_codec;
+ const vlc_fourcc_t i_codec_fourcc = ( p_fmt_es->i_original_fourcc )?
+ p_fmt_es->i_original_fourcc : p_fmt_es->i_codec;
if( psz_codec_description )
info_category_AddInfo( p_cat, _("Codec"), "%s (%.4s)",
psz_codec_description, (char*)&i_codec_fourcc );