int64_t i_audio_delay;
int64_t i_spu_delay;
- /* Rate used for clock */
+ /* Clock configuration */
+ mtime_t i_pts_delay;
+ int i_cr_average;
int i_rate;
/* */
static void EsOutDelete ( es_out_t * );
static void EsOutSelect( es_out_t *, es_out_id_t *es, bool b_force );
-static void EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const es_format_t * );
+static void EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const es_format_t *, const vlc_meta_t * );
static int EsOutSetRecord( es_out_t *, bool b_record );
static bool EsIsSelected( es_out_id_t *es );
}
return -1;
}
-
+static inline bool EsFmtIsTeletext( const es_format_t *p_fmt )
+{
+ return p_fmt->i_cat == SPU_ES && p_fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' );
+}
/*****************************************************************************
* input_EsOutNew:
p_sys->i_pause_date = -1;
p_sys->i_rate = i_rate;
+ p_sys->i_pts_delay = 0;
+ p_sys->i_cr_average = 0;
p_sys->b_buffering = true;
p_sys->i_buffering_extra_initial = 0;
/* We do not have a wake up date if the input cannot have its speed
* controlled or sout is imposing its own or while buffering
*
- * FIXME for !p_input->b_can_pace_control a wkeup time is still needed to avoid too strong buffering */
- if( !p_input->b_can_pace_control ||
+ * FIXME for !p_input->p->b_can_pace_control a wkeup time is still needed to avoid too strong buffering */
+ if( !p_input->p->b_can_pace_control ||
p_input->p->b_out_pace_control ||
p_sys->b_buffering )
return 0;
if( !i_ret )
{
/* FIXME pcr != exactly what wanted */
- const mtime_t i_used = /*(i_stream_duration - p_sys->p_input->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
+ const mtime_t i_used = /*(i_stream_duration - p_sys->p_input->p->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
i_date -= i_used;
}
p_sys->i_buffering_extra_initial = 0;
{
es_out_sys_t *p_sys = out->p_sys;
+ input_SendEventCache( p_sys->p_input, 0.0 );
+
for( int i = 0; i < p_sys->i_es; i++ )
{
es_out_id_t *p_es = p_sys->es[i];
input_DecoderStartBuffering( p_es->p_dec );
if( p_es->p_dec_record )
- input_DecoderStartBuffering( p_es->p_dec );
+ input_DecoderStartBuffering( p_es->p_dec_record );
}
for( int i = 0; i < p_sys->i_pgrm; i++ )
if( p_sys->i_preroll_end >= 0 )
i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
- const mtime_t i_buffering_duration = p_sys->p_input->i_pts_delay +
+ const mtime_t i_buffering_duration = p_sys->i_pts_delay +
i_preroll_duration +
p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
if( i_stream_duration <= i_buffering_duration && !b_forced )
{
- msg_Dbg( p_sys->p_input, "Buffering %d%%",
- (int)(100 * i_stream_duration / i_buffering_duration ) );
+ const double f_level = (double)i_stream_duration / i_buffering_duration;
+ input_SendEventCache( p_sys->p_input, f_level );
+
+ msg_Dbg( p_sys->p_input, "Buffering %d%%", (int)(100 * f_level) );
return;
}
+ input_SendEventCache( p_sys->p_input, 1.0 );
msg_Dbg( p_sys->p_input, "Stream buffering done (%d ms in %d ms)",
(int)(i_stream_duration/1000), (int)(i_system_duration/1000) );
{
es_out_id_t *p_es = p_sys->es[i];
- if( !p_es->p_dec )
+ if( !p_es->p_dec || p_es->fmt.i_cat == SPU_ES )
continue;
input_DecoderWaitBuffering( p_es->p_dec );
if( p_es->p_dec_record )
msg_Dbg( p_sys->p_input, "Decoder buffering done in %d ms",
(int)(mdate() - i_decoder_buffering_start)/1000 );
+ /* Here is a good place to destroy unused vout with every demuxer */
+ input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
+
+ /* */
const mtime_t i_wakeup_delay = 10*1000; /* FIXME CLEANUP thread wake up time*/
const mtime_t i_current_date = p_sys->b_paused ? p_sys->i_pause_date : mdate();
input_DecoderStopBuffering( p_es->p_dec );
if( p_es->p_dec_record )
- input_DecoderStopBuffering( p_es->p_dec );
+ input_DecoderStopBuffering( p_es->p_dec_record );
}
}
static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
if( i_ret )
return;
- p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->p_input->i_pts_delay; /* FIXME < 0 ? */
+ p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->i_pts_delay; /* FIXME < 0 ? */
p_sys->i_buffering_extra_system =
p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
}
}
const mtime_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration;
- i_delay = p_sys->p_input->i_pts_delay - i_consumed;
+ i_delay = p_sys->i_pts_delay - i_consumed;
}
if( i_delay < 0 )
return 0;
return i_delay;
}
-static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
+static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id,
+ const es_format_t *fmt, const char *psz_language,
bool b_delete )
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
- const bool b_teletext = fmt->i_cat == SPU_ES && fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' );
vlc_value_t val, text;
if( b_delete )
{
- /* TODO it should probably be a list */
- if( b_teletext )
- input_SendEventTeletext( p_sys->p_input, -1 );
+ if( EsFmtIsTeletext( fmt ) )
+ input_SendEventTeletextDel( p_sys->p_input, i_id );
- input_SendEventEsDel( p_input, SPU_ES, i_id );
+ input_SendEventEsDel( p_input, fmt->i_cat, i_id );
return;
}
}
input_SendEventEsAdd( p_input, fmt->i_cat, i_id, text.psz_string );
-
- free( text.psz_string );
-
- if( b_teletext )
+ if( EsFmtIsTeletext( fmt ) )
{
- /* TODO it should probably be a list */
- if( var_GetInteger( p_sys->p_input, "teletext-es" ) < 0 )
- input_SendEventTeletext( p_sys->p_input, i_id );
+ char psz_page[3+1];
+ snprintf( psz_page, sizeof(psz_page), "%d%2.2x",
+ fmt->subs.teletext.i_magazine,
+ fmt->subs.teletext.i_page );
+ input_SendEventTeletextAdd( p_sys->p_input,
+ i_id, fmt->subs.teletext.i_magazine >= 0 ? psz_page : NULL );
}
+
+ free( text.psz_string );
}
static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
input_SendEventEsDel( p_input, AUDIO_ES, -1 );
input_SendEventEsDel( p_input, VIDEO_ES, -1 );
input_SendEventEsDel( p_input, SPU_ES, -1 );
+ input_SendEventTeletextDel( p_input, -1 );
/* TODO event */
var_SetInteger( p_input, "teletext-es", -1 );
}
/* Update now playing */
- 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 );
+ input_item_SetNowPlaying( 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 );
}
p_pgrm->psz_now_playing = NULL;
p_pgrm->psz_publisher = NULL;
p_pgrm->p_epg = NULL;
- p_pgrm->p_clock = input_clock_New( p_input->p->input.i_cr_average, p_sys->i_rate );
+ p_pgrm->p_clock = input_clock_New( p_sys->i_rate );
if( !p_pgrm->p_clock )
{
free( p_pgrm );
return NULL;
}
+ input_clock_SetJitter( p_pgrm->p_clock, p_sys->i_pts_delay, p_sys->i_cr_average );
+
/* Append it */
TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
{
if( p_sys->p_pgrm == p_pgrm )
{
- input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
+ input_item_SetPublisher( p_input->p->p_item, psz_provider );
input_SendEventMeta( p_input );
}
input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
}
if( b_add )
{
- vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
+ vlc_epg_event_t *p_copy = calloc( 1, sizeof(vlc_epg_event_t) );
if( !p_copy )
break;
- memset( p_copy, 0, sizeof(vlc_epg_event_t) );
p_copy->i_start = p_evt->i_start;
p_copy->i_duration = p_evt->i_duration;
p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
if( p_pgrm == p_sys->p_pgrm )
{
- input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
+ input_item_SetNowPlaying( p_input->p->p_item, p_pgrm->psz_now_playing );
input_SendEventMeta( p_input );
}
es->i_channel = p_sys->i_audio;
memset( &rg, 0, sizeof(rg) );
- vlc_mutex_lock( &p_input->p->input.p_item->lock );
- vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
- vlc_mutex_unlock( &p_input->p->input.p_item->lock );
+ vlc_mutex_lock( &p_input->p->p_item->lock );
+ vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->p_item->p_meta );
+ vlc_mutex_unlock( &p_input->p->p_item->lock );
for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
{
break;
}
- EsOutUpdateInfo( out, es, &es->fmt );
+ EsOutUpdateInfo( out, es, &es->fmt, NULL );
vlc_mutex_unlock( &p_sys->lock );
/* Mark it as selected */
input_SendEventEsSelect( p_input, es->fmt.i_cat, es->i_id );
+ input_SendEventTeletextSelect( p_input, EsFmtIsTeletext( &es->fmt ) ? es->i_id : -1 );
}
static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
if( !b_update )
return;
- /* Update var */
- if( es->p_dec == NULL )
- return;
-
/* Mark it as unselected */
input_SendEventEsSelect( p_input, es->fmt.i_cat, -1 );
+ if( EsFmtIsTeletext( &es->fmt ) )
+ input_SendEventTeletextSelect( p_input, -1 );
}
/**
input_DecoderDecode( es->p_dec, p_block );
es_format_t fmt_dsc;
- if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc ) )
+ vlc_meta_t *p_meta_dsc;
+ if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
{
- EsOutUpdateInfo( out, es, &fmt_dsc );
+ EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );
+
es_format_Clean( &fmt_dsc );
+ if( p_meta_dsc )
+ vlc_meta_Delete( p_meta_dsc );
}
/* Check CC status */
case ES_OUT_SET_ACTIVE:
{
b = (bool) va_arg( args, int );
+ if( b && !p_sys->b_active && p_sys->i_es > 0 )
+ {
+ /* XXX Terminate vout if there are tracks but no video one.
+ * This one is not mandatory but is he earliest place where it
+ * can be done */
+ for( i = 0; i < p_sys->i_es; i++ )
+ {
+ es_out_id_t *p_es = p_sys->es[i];
+ if( p_es->fmt.i_cat == VIDEO_ES )
+ break;
+ }
+ if( i >= p_sys->i_es )
+ input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
+ }
p_sys->b_active = b;
return VLC_SUCCESS;
}
/* search program
* TODO do not use mdate() but proper stream acquisition date */
input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
- p_sys->p_input->b_can_pace_control || p_sys->b_buffering, i_pcr, mdate() );
+ p_sys->p_input->p->b_can_pace_control || p_sys->b_buffering, i_pcr, mdate() );
/* Check buffering state on master clock update */
if( p_sys->b_buffering && p_pgrm == p_sys->p_pgrm )
EsOutDecodersStopBuffering( out, false );
EsOutChangePosition( out );
return VLC_SUCCESS;
- case ES_OUT_GET_TS:
- if( p_sys->p_pgrm )
- {
- 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_clock_GetTS( p_sys->p_pgrm->p_clock, NULL,
- p_sys->p_input->i_pts_delay, i_ts );
- return VLC_SUCCESS;
- }
- return VLC_EGENERIC;
-
case ES_OUT_SET_GROUP:
{
int j;
assert(0);
}
/* TODO if the lock is made non recursive it should be changed */
- return es_out_Control( out, i_new_query, p_es );
+ int i_ret = es_out_Control( out, i_new_query, p_es );
+
+ /* Clean up vout after user action (in active mode only).
+ * FIXME it does not work well with multiple video windows */
+ if( p_sys->b_active )
+ input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
+ return i_ret;
}
case ES_OUT_GET_BUFFERING:
if( f_position < 0 )
f_position = 0;
- input_SendEventTimes( p_sys->p_input, f_position, i_time, i_length );
+ if( !p_sys->b_buffering )
+ input_SendEventTimes( p_sys->p_input, f_position, i_time, i_length );
+ return VLC_SUCCESS;
+ }
+ case ES_OUT_SET_JITTER:
+ {
+ mtime_t i_pts_delay = (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;
+
+ p_sys->i_pts_delay = i_pts_delay;
+ p_sys->i_cr_average = i_cr_average;
+
+ for( int i = 0; i < p_sys->i_pgrm; i++ )
+ input_clock_SetJitter( p_sys->pgrm[i]->p_clock,
+ i_pts_delay, i_cr_average );
return VLC_SUCCESS;
}
* EsOutUpdateInfo:
* - add meta info to the playlist item
****************************************************************************/
-static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt )
+static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt, const vlc_meta_t *p_meta )
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
if( fmt->audio.i_physical_channels & AOUT_CHAN_PHYSMASK )
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
- "%s", aout_FormatPrintChannels( &fmt->audio ) );
+ "%s", _( aout_FormatPrintChannels( &fmt->audio ) ) );
else if( fmt->audio.i_channels > 0 )
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
"%u", fmt->audio.i_channels );
break;
}
+ /* Append generic meta */
+ if( p_meta )
+ {
+ char **ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
+ for( int i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
+ {
+ char *psz_key = ppsz_all_keys[i];
+ char *psz_value = vlc_dictionary_value_for_key( &p_meta->extra_tags, psz_key );
+
+ if( psz_value )
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(psz_key), _(psz_value) );
+ free( psz_key );
+ }
+ free( ppsz_all_keys );
+ }
+
free( psz_cat );
}