static void ObjectKillChildrens( input_thread_t *, vlc_object_t * );
-static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
+static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
static void ControlReduce( input_thread_t * );
static bool Control( input_thread_t *, int, vlc_value_t );
if( !p_input->p )
return NULL;
- /* One "randomly" selected input thread is responsible for computing
- * the global stats. Check if there is already someone doing this */
- if( p_input->p_libvlc->p_stats && !b_quick )
- {
- libvlc_priv_t *p_private = libvlc_priv( p_input->p_libvlc );
- vlc_mutex_lock( &p_input->p_libvlc->p_stats->lock );
- if( p_private->p_stats_computer == NULL )
- p_private->p_stats_computer = p_input;
- vlc_mutex_unlock( &p_input->p_libvlc->p_stats->lock );
- }
-
p_input->b_preparsing = b_quick;
p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
p_input->p->p_es_out = NULL;
p_input->p->p_sout = NULL;
p_input->p->b_out_pace_control = false;
- p_input->p->i_pts_delay = 0;
- p_input->p->i_cr_average = 0;
vlc_gc_incref( p_item ); /* Released in Destructor() */
p_input->p->p_item = p_item;
input_ControlVarInit( p_input );
/* */
- p_input->p->i_cr_average = var_GetInteger( p_input, "cr-average" );
-
if( !p_input->b_preparsing )
{
var_Get( p_input, "bookmarks", &val );
/**
* Initialize an input and initialize it to preparse the item
- * This function is blocking. It will only accept to parse files
+ * This function is blocking. It will only accept parsing regular files.
*
* \param p_parent a vlc_object_t
* \param p_item an input item
* \return VLC_SUCCESS or an error
*/
-int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
+int input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
{
input_thread_t *p_input;
int i;
/* FIXME ObjectKillChildrens seems a very bad idea in fact */
- if( p_obj->i_object_type == VLC_OBJECT_VOUT ||
- p_obj->i_object_type == VLC_OBJECT_AOUT ||
+ i = vlc_internals( p_obj )->i_object_type;
+ if( i == VLC_OBJECT_VOUT ||i == VLC_OBJECT_AOUT ||
p_obj == VLC_OBJECT(p_input->p->p_sout) ||
- p_obj->i_object_type == VLC_OBJECT_DECODER ||
- p_obj->i_object_type == VLC_OBJECT_PACKETIZER )
+ i == VLC_OBJECT_DECODER || i == VLC_OBJECT_PACKETIZER )
return;
vlc_object_kill( p_obj );
static void MainLoopStatistic( input_thread_t *p_input )
{
stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
- /* Are we the thread responsible for computing global stats ? */
- if( libvlc_priv( p_input->p_libvlc )->p_stats_computer == p_input )
- {
- stats_ComputeGlobalStats( p_input->p_libvlc,
- p_input->p_libvlc->p_stats );
- }
input_SendEventStatistics( p_input );
}
i_deadline = __MIN( i_intf_update, i_statistic_update );
/* Handle control */
- vlc_mutex_lock( &p_input->p->lock_control );
ControlReduce( p_input );
- while( !ControlPopNoLock( p_input, &i_type, &val, i_deadline ) )
+ while( !ControlPop( p_input, &i_type, &val, i_deadline ) )
{
+
msg_Dbg( p_input, "control type=%d", i_type );
if( Control( p_input, i_type, val ) )
b_force_update = true;
}
- vlc_mutex_unlock( &p_input->p->lock_control );
/* Update interface and statistics */
i_current = mdate();
{
/* Setup variables */
input_ControlVarNavigation( p_input );
- input_ControlVarTitle( p_input, 0 );
+ input_SendEventTitle( p_input, 0 );
}
/* Global flag */
p_input->p->b_can_pace_control = p_master->b_can_pace_control;
p_input->p->b_can_pause = p_master->b_can_pause;
p_input->p->b_can_rate_control = p_master->b_can_rate_control;
-
- /* Fix pts delay */
- if( p_input->p->i_pts_delay < 0 )
- p_input->p->i_pts_delay = 0;
-
- /* If the desynchronisation requested by the user is < 0, we need to
- * cache more data. */
- const int i_desynch = var_GetInteger( p_input, "audio-desync" );
- if( i_desynch < 0 )
- p_input->p->i_pts_delay -= i_desynch * 1000;
-
- /* Update cr_average depending on the caching */
- p_input->p->i_cr_average *= (10 * p_input->p->i_pts_delay / 200000);
- p_input->p->i_cr_average /= 10;
- if( p_input->p->i_cr_average < 10 )
- p_input->p->i_cr_average = 10;
}
static void StartTitle( input_thread_t * p_input )
msg_Warn( p_input, "invalid stop-time ignored" );
p_input->p->i_stop = 0;
}
+ p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
}
static void LoadSubtitles( input_thread_t *p_input )
free( psz_org );
}
+static void UpdatePtsDelay( input_thread_t *p_input )
+{
+ input_thread_private_t *p_sys = p_input->p;
+
+ /* Get max pts delay from input source */
+ mtime_t i_pts_delay = p_sys->input.i_pts_delay;
+ for( int i = 0; i < p_sys->i_slave; i++ )
+ i_pts_delay = __MAX( i_pts_delay, p_sys->slave[i]->i_pts_delay );
+
+ if( i_pts_delay < 0 )
+ i_pts_delay = 0;
+
+ /* Take care of audio/spu delay */
+ const mtime_t i_audio_delay = var_GetTime( p_input, "audio-delay" );
+ const mtime_t i_spu_delay = var_GetTime( p_input, "spu-delay" );
+ const mtime_t i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
+ if( i_extra_delay < 0 )
+ i_pts_delay -= i_extra_delay;
+
+ /* Update cr_average depending on the caching */
+ const int i_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY;
+
+ /* */
+ es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, i_cr_average );
+}
+
static void InitPrograms( input_thread_t * p_input )
{
int i_es_out_mode;
vlc_value_t val;
+ /* Compute correct pts_delay */
+ UpdatePtsDelay( p_input );
+
/* Set up es_out */
es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, true );
i_es_out_mode = ES_OUT_MODE_AUTO;
#ifdef ENABLE_SOUT
ret = InitSout( p_input );
if( ret != VLC_SUCCESS )
- return ret; /* FIXME: goto error; should be better here */
+ goto error_stats;
#endif
/* Create es out */
InputUpdateMeta( p_input, p_meta );
}
- if( !p_input->b_preparsing )
- {
- msg_Dbg( p_input, "`%s' successfully opened",
- p_input->p->p_item->psz_uri );
-
- }
+ msg_Dbg( p_input, "`%s' successfully opened",
+ p_input->p->p_item->psz_uri );
/* initialization is complete */
input_ChangeState( p_input, PLAYING_S );
input_ressource_SetInput( p_input->p->p_ressource, NULL );
}
+#ifdef ENABLE_SOUT
+error_stats:
+#endif
if( !p_input->b_preparsing && libvlc_stats( p_input ) )
{
#define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
/* make sure we are up to date */
stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
- if( p_private->p_stats_computer == p_input )
- {
- stats_ComputeGlobalStats( p_input->p_libvlc,
- p_input->p_libvlc->p_stats );
- /* FIXME how can it be thread safe ? */
- p_private->p_stats_computer = NULL;
- }
CL_CO( read_bytes );
CL_CO( read_packets );
CL_CO( demux_read );
vlc_mutex_unlock( &p_input->p->lock_control );
}
-static inline int ControlPopNoLock( input_thread_t *p_input,
- int *pi_type, vlc_value_t *p_val,
- mtime_t i_deadline )
+static inline int ControlPop( input_thread_t *p_input,
+ int *pi_type, vlc_value_t *p_val,
+ mtime_t i_deadline )
{
+ input_thread_private_t *p_sys = p_input->p;
- while( p_input->p->i_control <= 0 )
+ vlc_mutex_lock( &p_sys->lock_control );
+ while( p_sys->i_control <= 0 )
{
- if( !vlc_object_alive( p_input ) )
- return VLC_EGENERIC;
-
- if( i_deadline < 0 )
+ if( !vlc_object_alive( p_input ) || i_deadline < 0 )
+ {
+ vlc_mutex_unlock( &p_sys->lock_control );
return VLC_EGENERIC;
+ }
- if( vlc_cond_timedwait( &p_input->p->wait_control, &p_input->p->lock_control, i_deadline ) )
+ if( vlc_cond_timedwait( &p_sys->wait_control, &p_sys->lock_control,
+ i_deadline ) )
+ {
+ vlc_mutex_unlock( &p_sys->lock_control );
return VLC_EGENERIC;
+ }
}
- *pi_type = p_input->p->control[0].i_type;
- *p_val = p_input->p->control[0].val;
-
- p_input->p->i_control--;
- if( p_input->p->i_control > 0 )
- {
- int i;
+ /* */
+ *pi_type = p_sys->control[0].i_type;
+ *p_val = p_sys->control[0].val;
- for( i = 0; i < p_input->p->i_control; i++ )
- {
- p_input->p->control[i].i_type = p_input->p->control[i+1].i_type;
- p_input->p->control[i].val = p_input->p->control[i+1].val;
- }
- }
+ p_sys->i_control--;
+ if( p_sys->i_control > 0 )
+ memmove( &p_sys->control[0], &p_sys->control[1],
+ sizeof(*p_sys->control) * p_sys->i_control );
+ vlc_mutex_unlock( &p_sys->lock_control );
return VLC_SUCCESS;
}
static void ControlReduce( input_thread_t *p_input )
{
- int i;
-
- if( !p_input )
- return;
+ vlc_mutex_lock( &p_input->p->lock_control );
- for( i = 1; i < p_input->p->i_control; i++ )
+ for( int i = 1; i < p_input->p->i_control; i++ )
{
const int i_lt = p_input->p->control[i-1].i_type;
const int i_ct = p_input->p->control[i].i_type;
*/
}
}
+ vlc_mutex_unlock( &p_input->p->lock_control );
}
/* Pause input */
static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
{
/* FIXME What to do ? */
msg_Warn( p_input, "cannot unset pause -> EOF" );
- vlc_mutex_unlock( &p_input->p->lock_control );
input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
- vlc_mutex_lock( &p_input->p->lock_control );
}
}
/* Reset the decoders states and clock sync (before calling the demuxer */
es_out_SetTime( p_input->p->p_es_out, -1 );
if( demux_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION,
- f_pos ) )
+ f_pos, !p_input->p->b_fast_seek ) )
{
msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
"%2.1f%% failed", f_pos * 100 );
es_out_SetTime( p_input->p->p_es_out, -1 );
i_ret = demux_Control( p_input->p->input.p_demux,
- DEMUX_SET_TIME, i_time );
+ DEMUX_SET_TIME, i_time,
+ !p_input->p->b_fast_seek );
if( i_ret )
{
int64_t i_length;
{
double f_pos = (double)i_time / (double)i_length;
i_ret = demux_Control( p_input->p->input.p_demux,
- DEMUX_SET_POSITION, f_pos );
+ DEMUX_SET_POSITION, f_pos,
+ !p_input->p->b_fast_seek );
}
}
if( i_ret )
case INPUT_CONTROL_SET_AUDIO_DELAY:
if( !es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, val.i_time ) )
+ {
input_SendEventAudioDelay( p_input, val.i_time );
+ UpdatePtsDelay( p_input );
+ }
break;
case INPUT_CONTROL_SET_SPU_DELAY:
if( !es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, val.i_time ) )
+ {
input_SendEventSubtitleDelay( p_input, val.i_time );
+ UpdatePtsDelay( p_input );
+ }
break;
case INPUT_CONTROL_SET_TITLE:
es_out_SetTime( p_input->p->p_es_out, -1 );
demux_Control( p_demux, DEMUX_SET_TITLE, i_title );
- input_ControlVarTitle( p_input, i_title );
+ input_SendEventTitle( p_input, i_title );
}
}
else if( p_input->p->input.i_title > 0 )
stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
ACCESS_SET_TITLE, i_title );
+ input_SendEventTitle( p_input, i_title );
}
}
break;
es_out_SetTime( p_input->p->p_es_out, -1 );
demux_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
+ input_SendEventSeekpoint( p_input, p_demux->info.i_title, i_seekpoint );
}
}
else if( p_input->p->input.i_title > 0 )
stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
ACCESS_SET_SEEKPOINT, i_seekpoint );
+ input_SendEventSeekpoint( p_input, p_access->info.i_title, i_seekpoint );
}
}
break;
break;
}
if( demux_Control( slave->p_demux,
- DEMUX_SET_TIME, i_time ) )
+ DEMUX_SET_TIME, i_time, true ) )
{
msg_Err( p_input, "seek failed for new slave" );
InputSourceClean( slave );
if( in->p_demux )
{
- int64_t i_pts_delay;
-
/* Get infos from access_demux */
demux_Control( in->p_demux,
- DEMUX_GET_PTS_DELAY, &i_pts_delay );
- p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
+ DEMUX_GET_PTS_DELAY, &in->i_pts_delay );
in->b_title_demux = true;
if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
}
else
{
- int64_t i_pts_delay;
-
/* Now try a real access */
in->p_access = access_New( p_input, psz_access, psz_demux, psz_path );
if( !p_input->b_preparsing )
{
access_Control( in->p_access,
- ACCESS_GET_PTS_DELAY, &i_pts_delay );
- p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
+ ACCESS_GET_PTS_DELAY, &in->i_pts_delay );
in->b_title_demux = false;
if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO,
}
{
- /* Take access redirections into account */
+ /* Take access/stream redirections into account */
char *psz_real_path;
char *psz_buf = NULL;
- if( in->p_access->psz_path )
+ if( in->p_stream->psz_path )
{
const char *psz_a, *psz_d;
- psz_buf = strdup( in->p_access->psz_path );
+ psz_buf = strdup( in->p_stream->psz_path );
input_SplitMRL( &psz_a, &psz_d, &psz_real_path, psz_buf );
}
else
{
input_source_t *in = p_input->p->slave[i];
- if( demux_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
+ if( demux_Control( in->p_demux, DEMUX_SET_TIME, i_time, true ) )
{
if( !in->b_eof )
msg_Err( p_input, "seek failed for slave %d -> EOF", i );
vlc_meta_Delete( 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 )
{
- vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, psz_arturl );
+ input_item_SetArtURL( p_item, psz_arturl );
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 )
- vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, "" );
+ input_item_SetArtURL( p_item, "" );
else
input_ExtractAttachmentAndCacheArt( p_input );
}
}
free( psz_arturl );
- vlc_mutex_unlock( &p_item->lock );
-
if( psz_title )
{
input_item_SetName( p_item, psz_title );