static char *LanguageGetName( const char *psz_code );
static char *LanguageGetCode( const char *psz_lang );
static char **LanguageSplit( const char *psz_langs, bool b_default_any );
-static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
+static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang );
static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
if( !out )
return NULL;
- es_out_sys_t *p_sys = malloc( sizeof( *p_sys ) );
+ es_out_sys_t *p_sys = calloc( 1, sizeof( *p_sys ) );
if( !p_sys )
{
free( out );
TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
- p_sys->p_pgrm = NULL;
-
- p_sys->i_id = 0;
TAB_INIT( p_sys->i_es, p_sys->es );
- p_sys->i_audio = 0;
- p_sys->i_video = 0;
- 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" );
p_sys->i_default_sub_id = -1;
}
free( psz_string );
}
- else
- {
- p_sys->ppsz_sub_language = NULL;
- p_sys->ppsz_audio_language = NULL;
- }
p_sys->i_audio_id = var_GetInteger( p_input, "audio-track-id" );
p_sys->i_sub_id = var_GetInteger( p_input, "sub-track-id" );
- p_sys->p_es_audio = NULL;
- p_sys->p_es_video = NULL;
- p_sys->p_es_sub = NULL;
-
- p_sys->i_audio_delay= 0;
- p_sys->i_spu_delay = 0;
-
- p_sys->b_paused = false;
p_sys->i_pause_date = -1;
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;
- p_sys->i_buffering_extra_initial = 0;
- p_sys->i_buffering_extra_stream = 0;
- p_sys->i_buffering_extra_system = 0;
p_sys->i_preroll_end = -1;
- p_sys->p_sout_record = NULL;
-
return out;
}
if( !psz_sout && psz_path )
{
- char *psz_file = input_CreateFilename( VLC_OBJECT(p_input), psz_path, INPUT_RECORD_PREFIX, NULL );
+ char *psz_file = input_CreateFilename( p_input, psz_path, INPUT_RECORD_PREFIX, NULL );
if( psz_file )
{
if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file ) < 0 )
p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
if( p_es->p_dec_record && p_sys->b_buffering )
- input_DecoderStartBuffering( p_es->p_dec_record );
+ input_DecoderStartWait( p_es->p_dec_record );
}
}
else
{
es_out_id_t *p_es = p_sys->es[i];
- if( !p_es->p_dec )
- continue;
-
- input_DecoderStartBuffering( p_es->p_dec );
-
- if( p_es->p_dec_record )
- input_DecoderStartBuffering( p_es->p_dec_record );
+ if( p_es->p_dec != NULL )
+ {
+ input_DecoderFlush( p_es->p_dec );
+ if( !p_sys->b_buffering )
+ {
+ input_DecoderStartWait( p_es->p_dec );
+ if( p_es->p_dec_record != NULL )
+ input_DecoderStartWait( p_es->p_dec_record );
+ }
+ }
}
for( int i = 0; i < p_sys->i_pgrm; i++ )
static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
{
es_out_sys_t *p_sys = out->p_sys;
- int i_ret;
mtime_t i_stream_start;
mtime_t i_system_start;
mtime_t i_stream_duration;
mtime_t i_system_duration;
- i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
+ if (input_clock_GetState( p_sys->p_pgrm->p_clock,
&i_stream_start, &i_system_start,
- &i_stream_duration, &i_system_duration );
- assert( !i_ret || b_forced );
- if( i_ret )
+ &i_stream_duration, &i_system_duration ))
return;
mtime_t i_preroll_duration = 0;
if( i_stream_duration <= i_buffering_duration && !b_forced )
{
- const double f_level = __MAX( (double)i_stream_duration / i_buffering_duration, 0 );
+ double f_level;
+ if (i_buffering_duration == 0)
+ f_level = 0;
+ else
+ 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 || p_es->fmt.i_cat == SPU_ES )
continue;
- input_DecoderWaitBuffering( p_es->p_dec );
+ input_DecoderWait( p_es->p_dec );
if( p_es->p_dec_record )
- input_DecoderWaitBuffering( p_es->p_dec_record );
+ input_DecoderWait( p_es->p_dec_record );
}
- msg_Dbg( p_sys->p_input, "Decoder buffering done in %d ms",
+ msg_Dbg( p_sys->p_input, "Decoder wait done in %d ms",
(int)(mdate() - i_decoder_buffering_start)/1000 );
/* Here is a good place to destroy unused vout with every demuxer */
if( !p_es->p_dec )
continue;
- input_DecoderStopBuffering( p_es->p_dec );
+ input_DecoderStopWait( p_es->p_dec );
if( p_es->p_dec_record )
- input_DecoderStopBuffering( p_es->p_dec_record );
+ input_DecoderStopWait( p_es->p_dec_record );
}
}
static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
static mtime_t EsOutGetBuffering( es_out_t *out )
{
es_out_sys_t *p_sys = out->p_sys;
+ mtime_t i_stream_duration, i_system_start;
if( !p_sys->p_pgrm )
return 0;
+ else
+ {
+ mtime_t i_stream_start, i_system_duration;
- int i_ret;
- mtime_t i_stream_start;
- mtime_t i_system_start;
- mtime_t i_stream_duration;
- mtime_t i_system_duration;
- i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
+ if( input_clock_GetState( p_sys->p_pgrm->p_clock,
&i_stream_start, &i_system_start,
- &i_stream_duration, &i_system_duration );
-
- if( i_ret )
- return 0;
+ &i_stream_duration, &i_system_duration ) )
+ return 0;
+ }
mtime_t i_delay;
else
{
mtime_t i_system_duration;
+
if( p_sys->b_paused )
{
i_system_duration = p_sys->i_pause_date - i_system_start;
}
/* Update now playing */
- input_item_SetNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
+ input_item_SetESNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
input_item_SetPublisher( p_input->p->p_item, p_pgrm->psz_publisher );
input_SendEventMeta( p_input );
/* Check against empty meta data (empty for what we handle) */
if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
- !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
+ !vlc_meta_Get( p_meta, vlc_meta_ESNowPlaying) &&
!vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
vlc_meta_GetExtraCount( p_meta ) <= 0 )
{
if( p_pgrm == p_sys->p_pgrm )
{
- input_item_SetNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
+ input_item_SetESNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
input_SendEventMeta( p_input );
}
if( p_pgrm->psz_now_playing )
{
input_Control( p_input, INPUT_ADD_INFO, psz_cat,
- vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying),
+ vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying), "%s",
p_pgrm->psz_now_playing );
}
else
{
input_Control( p_input, INPUT_DEL_INFO, psz_cat,
- vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying) );
+ vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying) );
}
free( psz_cat );
{
es_out_sys_t *p_sys = p_out->p_sys;
input_thread_t *p_input = p_sys->p_input;
-
input_item_t *p_item = input_GetItem( p_input );
- char *psz_title = NULL;
- char *psz_arturl = input_item_GetArtURL( p_item );
-
- vlc_mutex_lock( &p_item->lock );
+ if( vlc_meta_Get( p_meta, vlc_meta_Title ) != NULL )
+ input_item_SetName( p_item, vlc_meta_Get( p_meta, vlc_meta_Title ) );
- if( vlc_meta_Get( p_meta, vlc_meta_Title ) && !p_item->b_fixed_name )
- psz_title = strdup( vlc_meta_Get( p_meta, vlc_meta_Title ) );
+ char *psz_arturl = NULL;
+ if( vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL ) != NULL )
+ psz_arturl = input_item_GetArtURL( p_item ); /* save value */
+ vlc_mutex_lock( &p_item->lock );
vlc_meta_Merge( p_item->p_meta, p_meta );
-
- if( !psz_arturl || *psz_arturl == '\0' )
- {
- const char *psz_tmp = vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL );
- if( psz_tmp )
- psz_arturl = strdup( psz_tmp );
- }
vlc_mutex_unlock( &p_item->lock );
- if( psz_arturl && *psz_arturl )
- {
+ if( psz_arturl != NULL ) /* restore/favor previously set item art URL */
input_item_SetArtURL( p_item, psz_arturl );
+ else
+ psz_arturl = input_item_GetArtURL( p_item );
- if( !strncmp( psz_arturl, "attachment://", strlen("attachment") ) )
- {
- /* Don't look for art cover if sout
- * XXX It can change when sout has meta data support */
- if( p_input->p->p_sout && !p_input->b_preparsing )
- input_item_SetArtURL( p_item, "" );
- else
- input_ExtractAttachmentAndCacheArt( p_input );
- }
+ if( psz_arturl != NULL && !strncmp( psz_arturl, "attachment://", 13 ) )
+ { /* Clear art cover if streaming out.
+ * FIXME: Why? Remove this when sout gets meta data support. */
+ if( p_input->p->p_sout && !p_input->b_preparsing )
+ input_item_SetArtURL( p_item, NULL );
+ else
+ input_ExtractAttachmentAndCacheArt( p_input, psz_arturl + 13 );
}
free( psz_arturl );
- if( psz_title )
- {
- input_item_SetName( p_item, psz_title );
- free( psz_title );
- }
input_item_SetPreparsed( p_item, true );
input_SendEventMeta( p_input );
if( p_es->p_dec )
{
if( p_sys->b_buffering )
- input_DecoderStartBuffering( p_es->p_dec );
+ input_DecoderStartWait( p_es->p_dec );
if( !p_es->p_master && p_sys->p_sout_record )
{
p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
if( p_es->p_dec_record && p_sys->b_buffering )
- input_DecoderStartBuffering( p_es->p_dec_record );
+ input_DecoderStartWait( p_es->p_dec_record );
}
}
int i_cat = es->fmt.i_cat;
if( !p_sys->b_active ||
- ( !b_force && es->fmt.i_priority < 0 ) )
+ ( !b_force && es->fmt.i_priority < ES_PRIORITY_SELECTABLE_MIN ) )
{
return;
}
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 )
+ if( p_sys->ppsz_audio_language )
{
- 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;
+ int es_idx = LanguageArrayIndex( p_sys->ppsz_audio_language,
+ es->psz_language_code );
+ if( !p_sys->p_es_audio )
+ {
+ /* Only select the language if it's in the list */
+ if( es_idx >= 0 )
+ i_wanted = es->i_channel;
+ }
+ else
+ {
+ int selected_es_idx =
+ LanguageArrayIndex( p_sys->ppsz_audio_language,
+ p_sys->p_es_audio->psz_language_code );
+ if( es_idx >= 0 &&
+ ( selected_es_idx < 0 || es_idx < selected_es_idx ||
+ ( es_idx == selected_es_idx &&
+ p_sys->p_es_audio->fmt.i_priority < es->fmt.i_priority ) ) )
+ 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 )
+ /* Select the first one if there is no selected audio yet
+ * then choose by ES priority */
+ if( !p_sys->p_es_audio ||
+ p_sys->p_es_audio->fmt.i_priority < es->fmt.i_priority )
i_wanted = es->i_channel;
}
}
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 )
+ if( p_sys->ppsz_sub_language )
{
- 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;
+ int es_idx = LanguageArrayIndex( p_sys->ppsz_sub_language,
+ es->psz_language_code );
+ if( !p_sys->p_es_sub )
+ {
+ /* Select the language if it's in the list */
+ if( es_idx >= 0 ||
+ /*FIXME: Should default subtitle not in the list be
+ * displayed if not forbidden by none? */
+ ( p_sys->i_default_sub_id >= 0 &&
+ /* check if the subtitle isn't forbidden by none */
+ LanguageArrayIndex( p_sys->ppsz_sub_language, "none" ) < 0 &&
+ es->i_id == p_sys->i_default_sub_id ) )
+ i_wanted = es->i_channel;
+ }
+ else
+ {
+ int selected_es_idx =
+ LanguageArrayIndex( p_sys->ppsz_sub_language,
+ p_sys->p_es_sub->psz_language_code );
+
+ if( es_idx >= 0 &&
+ ( selected_es_idx < 0 || es_idx < selected_es_idx ||
+ ( es_idx == selected_es_idx &&
+ p_sys->p_es_sub->fmt.i_priority < es->fmt.i_priority ) ) )
+ i_wanted = es->i_channel;
+ }
}
- else if( idx1 >= 0 )
+ else if ( es->fmt.i_codec == EsOutFourccClosedCaptions[0] ||
+ es->fmt.i_codec == EsOutFourccClosedCaptions[1] ||
+ es->fmt.i_codec == EsOutFourccClosedCaptions[2] ||
+ es->fmt.i_codec == EsOutFourccClosedCaptions[3])
{
- msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
- idx1, es->psz_language_code );
-
- i_wanted = es->i_channel;
+ /* We don't want to enable on initial create since p_master
+ isn't set yet (otherwise we will think it's a standard
+ ES_SUB stream and cause a resource leak) */
+ return;
}
- else if( p_sys->i_default_sub_id >= 0 )
+ else
{
- if( es->i_id == p_sys->i_default_sub_id )
+ /* If there is no user preference, select the default subtitle
+ * or adapt by ES priority */
+ if( ( !p_sys->p_es_sub &&
+ ( p_sys->i_default_sub_id >= 0 &&
+ es->i_id == p_sys->i_default_sub_id ) ) ||
+ ( p_sys->p_es_sub &&
+ p_sys->p_es_sub->fmt.i_priority < es->fmt.i_priority ) )
i_wanted = es->i_channel;
+ else if( p_sys->p_es_sub &&
+ p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
+ i_wanted = p_sys->p_es_sub->i_channel;
}
if( p_sys->i_sub_last >= 0 )
/* */
es->pb_cc_present[i] = true;
+
+ /* Enable if user specified on command line */
+ if (p_sys->i_sub_last == i)
+ EsOutSelect(out, es->pp_cc_es[i], true);
}
vlc_mutex_unlock( &p_sys->lock );
/* We don't try to reselect */
if( es->p_dec )
{
- while( !p_sys->p_input->b_die && !p_sys->b_buffering && es->p_dec )
+ while( vlc_object_alive(p_sys->p_input) && !p_sys->b_buffering )
{
if( input_DecoderIsEmpty( es->p_dec ) &&
( !es->p_dec_record || input_DecoderIsEmpty( es->p_dec_record ) ))
EsOutIsExtraBufferingAllowed( out ),
i_pcr, mdate() );
- if( p_pgrm == p_sys->p_pgrm )
+ if( !p_sys->p_pgrm )
+ return VLC_SUCCESS;
+
+ if( p_sys->b_buffering )
{
- if( p_sys->b_buffering )
- {
- /* Check buffering state on master clock update */
- EsOutDecodersStopBuffering( out, false );
- }
- else if( b_late && ( !p_sys->p_input->p->p_sout ||
+ /* Check buffering state on master clock update */
+ EsOutDecodersStopBuffering( out, false );
+ }
+ else if( p_pgrm == p_sys->p_pgrm )
+ {
+ 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;
"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;
+
+ /* reset clock */
+ for( int i = 0; i < p_sys->i_pgrm; i++ )
+ input_clock_Reset( p_sys->pgrm[i]->p_clock );
}
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 */
+ /* Force a rebufferization when we are too late */
- /* 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 );
+ /* 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_SetJitter( out, i_pts_delay_base, i_pts_delay - i_pts_delay_base, p_sys->i_cr_average );
}
{
const int i_id = (int)va_arg( args, int );
es_out_id_t *p_es = EsOutGetFromID( out, i_id );
- int i_new_query;
+ int i_new_query = 0;
switch( i_query )
{
case ES_OUT_RESTART_ES_BY_ID: i_new_query = ES_OUT_RESTART_ES; break;
case ES_OUT_SET_ES_DEFAULT_BY_ID: i_new_query = ES_OUT_SET_ES_DEFAULT; break;
default:
- assert(0);
+ vlc_assert_unreachable();
}
/* TODO if the lock is made non recursive it should be changed */
int i_ret = es_out_Control( out, i_new_query, p_es );
{
for (int i = 0; i < p_sys->i_es; i++) {
es_out_id_t *id = p_sys->es[i];
- decoder_t *p_dec = id->p_dec;
- if (!p_dec)
- continue;
- block_t *p_block = block_Alloc(0);
- if( !p_block )
- break;
-
- p_block->i_flags |= BLOCK_FLAG_CORE_EOS;
- input_DecoderDecode(p_dec, p_block, false);
+ if (id->p_dec != NULL)
+ input_DecoderDrain(id->p_dec);
}
return VLC_SUCCESS;
}
}
else
{
- if( *pl->psz_native_name )
- {
- return strdup( pl->psz_native_name );
- }
- return strdup( pl->psz_eng_name );
+ return strdup( vlc_gettext(pl->psz_eng_name) );
}
}
for( pl = p_languages; pl->psz_eng_name != 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;
+ return strdup( pl->psz_iso639_1 );
}
- if( pl->psz_eng_name != NULL )
- return strdup( pl->psz_iso639_1 );
-
return strdup("??");
}
return ppsz;
}
-static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
+static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang )
{
if( !ppsz_langs || !psz_lang )
return -1;
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_original_fourcc : p_fmt_es->i_codec;
- if( psz_codec_description )
+ if( psz_codec_description && *psz_codec_description )
info_category_AddInfo( p_cat, _("Codec"), "%s (%.4s)",
psz_codec_description, (char*)&i_codec_fourcc );
- else
+ else if ( i_codec_fourcc != VLC_FOURCC(0,0,0,0) )
info_category_AddInfo( p_cat, _("Codec"), "%.4s",
(char*)&i_codec_fourcc );