player: make refresh seeks slightly more robust

Refresh seeks are automatically issued when changing filters, which
improves user experience if these filters change buffering or such.

The refresh seek could actually overwrite a previously ongoing seek:

	set pause yes
	set time-pos 10
	set vf ""

Here, the video code issued a refresh seek to the previous video
position, which could be different from the previously triggered (and
still ongoing) seek, this overwriting the seek.

Factor all refresh seek handling into a new function, and make it handle
ongoing seeks correctly.

Remove the weird new canonical_pts field, which actually had no use.

Fixes #4757.
This commit is contained in:
wm4 2017-08-14 14:02:13 +02:00
parent b6d79deebb
commit 68201f4591
6 changed files with 40 additions and 33 deletions

View File

@ -279,12 +279,8 @@ int reinit_audio_filters(struct MPContext *mpctx)
// Only force refresh if the amount of dropped buffered data is going to
// cause "issues" for the A/V sync logic.
if (mpctx->audio_status == STATUS_PLAYING &&
mpctx->playback_pts != MP_NOPTS_VALUE && delay > 0.2)
{
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->playback_pts,
MPSEEK_EXACT, 0);
}
if (mpctx->audio_status == STATUS_PLAYING && delay > 0.2)
issue_refresh_seek(mpctx, MPSEEK_EXACT);
return 1;
}

View File

@ -73,8 +73,8 @@ enum seek_type {
};
enum seek_precision {
MPSEEK_DEFAULT = 0,
// The following values are numerically sorted by increasing precision
MPSEEK_DEFAULT = 0,
MPSEEK_KEYFRAME,
MPSEEK_EXACT,
MPSEEK_VERY_EXACT,
@ -85,6 +85,13 @@ enum seek_flags {
MPSEEK_FLAG_NOFLUSH = 1 << 1, // keeping remaining data for seamless loops
};
struct seek_params {
enum seek_type type;
enum seek_precision exact;
double amount;
unsigned flags; // MPSEEK_FLAG_*
};
enum video_sync {
VS_DEFAULT = 0,
VS_DISP_RESAMPLE,
@ -339,6 +346,7 @@ typedef struct MPContext {
bool hrseek_lastframe; // drop everything until last frame reached
bool hrseek_backstep; // go to frame before seek target
double hrseek_pts;
struct seek_params current_seek;
bool ab_loop_clip; // clip to the "b" part of an A-B loop if available
// AV sync: the next frame should be shown when the audio out has this
// much (in seconds) buffered data left. Increased when more data is
@ -367,8 +375,6 @@ typedef struct MPContext {
double last_frame_duration;
// Video PTS, or audio PTS if video has ended.
double playback_pts;
// Last known "good" PTS
double canonical_pts;
// audio stats only
int64_t audio_stat_start;
double written_audio;
@ -398,13 +404,7 @@ typedef struct MPContext {
// Used to turn a new time value to a delta from last time.
int64_t last_time;
// Used to communicate the parameters of a seek between parts
struct seek_params {
enum seek_type type;
enum seek_precision exact;
double amount;
unsigned flags; // MPSEEK_FLAG_*
} seek;
struct seek_params seek;
// Allow audio to issue a second seek if audio is too far ahead (for non-hr
// seeks with external audio tracks).
@ -532,6 +532,7 @@ struct MPContext *mp_create(void);
void mp_destroy(struct MPContext *mpctx);
void mp_print_version(struct mp_log *log, int always);
void mp_update_logging(struct MPContext *mpctx, bool preinit);
void issue_refresh_seek(struct MPContext *mpctx, enum seek_precision min_prec);
// misc.c
double rel_time_to_abs(struct MPContext *mpctx, struct m_rel_time t);

View File

@ -1127,13 +1127,8 @@ done:
void update_lavfi_complex(struct MPContext *mpctx)
{
if (mpctx->playback_initialized) {
if (reinit_complex_filters(mpctx, false) != 0 &&
mpctx->canonical_pts != MP_NOPTS_VALUE)
{
// Refresh seek to avoid weird situations.
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->canonical_pts,
MPSEEK_EXACT, 0);
}
if (reinit_complex_filters(mpctx, false) != 0)
issue_refresh_seek(mpctx, MPSEEK_EXACT);
}
}
@ -1166,7 +1161,6 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->speed_factor_a = mpctx->speed_factor_v = 1.0;
mpctx->display_sync_error = 0.0;
mpctx->display_sync_active = false;
mpctx->canonical_pts = MP_NOPTS_VALUE;
mpctx->seek = (struct seek_params){ 0 };
reset_playback_state(mpctx);

View File

@ -111,6 +111,25 @@ double get_track_seek_offset(struct MPContext *mpctx, struct track *track)
return 0;
}
void issue_refresh_seek(struct MPContext *mpctx, enum seek_precision min_prec)
{
// let queued seeks execute at a slightly later point
if (mpctx->seek.type) {
mp_wakeup_core(mpctx);
return;
}
// repeat currently ongoing seeks
if (mpctx->current_seek.type) {
mpctx->seek = mpctx->current_seek;
mp_wakeup_core(mpctx);
return;
}
// maybe happens when changing filters while file is loaded - ignore for now
if (mpctx->playback_pts == MP_NOPTS_VALUE)
return;
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->playback_pts, min_prec, 0);
}
float mp_get_cache_percent(struct MPContext *mpctx)
{
struct stream_cache_info info = {0};

View File

@ -232,6 +232,7 @@ void reset_playback_state(struct MPContext *mpctx)
mpctx->hrseek_framedrop = false;
mpctx->hrseek_lastframe = false;
mpctx->hrseek_backstep = false;
mpctx->current_seek = (struct seek_params){0};
mpctx->playback_pts = MP_NOPTS_VALUE;
mpctx->last_seek_pts = MP_NOPTS_VALUE;
mpctx->cache_wait_time = 0;
@ -377,7 +378,7 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
mpctx->ab_loop_clip = mpctx->last_seek_pts < opts->ab_loop[1];
mpctx->canonical_pts = mpctx->last_seek_pts;
mpctx->current_seek = seek;
}
// This combines consecutive seek requests.
@ -958,8 +959,6 @@ static void handle_playback_time(struct MPContext *mpctx)
{
mpctx->playback_pts = playing_audio_pts(mpctx);
}
if (mpctx->playback_pts != MP_NOPTS_VALUE)
mpctx->canonical_pts = mpctx->playback_pts;
}
// We always make sure audio and video buffers are filled before actually
@ -993,6 +992,7 @@ static void handle_playback_restart(struct MPContext *mpctx)
if (!mpctx->restart_complete) {
mpctx->hrseek_active = false;
mpctx->restart_complete = true;
mpctx->current_seek = (struct seek_params){0};
mpctx->audio_allow_second_chance_seek = false;
handle_playback_time(mpctx);
mp_notify(mpctx, MPV_EVENT_PLAYBACK_RESTART, NULL);

View File

@ -551,13 +551,10 @@ void mp_force_video_refresh(struct MPContext *mpctx)
return;
// If not paused, the next frame should come soon enough.
if ((opts->pause || mpctx->time_frame >= 0.5) &&
(mpctx->video_status >= STATUS_PLAYING ||
mpctx->video_status <= STATUS_DRAINING) &&
mpctx->last_vo_pts != MP_NOPTS_VALUE)
if (opts->pause || mpctx->time_frame >= 0.5 ||
mpctx->video_status == STATUS_EOF)
{
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->last_vo_pts,
MPSEEK_VERY_EXACT, 0);
issue_refresh_seek(mpctx, MPSEEK_VERY_EXACT);
}
}