summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorDudemanguy <random342@airmail.cc>2024-02-25 16:26:30 -0600
committerDudemanguy <random342@airmail.cc>2024-02-26 15:41:34 +0000
commite3af545421322e357eb9355395923710ea93f83b (patch)
treec7c121d7a51da5c01580ed1e653ca5fae6f34dbf /player
parent7051e94e4bacd00e53e88835d28e9d9082de3bb3 (diff)
downloadmpv-e3af545421322e357eb9355395923710ea93f83b.tar.bz2
mpv-e3af545421322e357eb9355395923710ea93f83b.tar.xz
player: reset av state on speed changes
Playback speed changes should be treated as a discontinuity just like seeking. Previously, this was being treated internally as just plain normal playback, but that can't really work. The frame timings from before the speed change and after the speed change are completely different and shouldn't be compared to each other. This lead to frames being adjusted to weird places and possibly even being skipped (as if mpv was seeking) on speed changes. What we should do is clear out and reset all av related fields like what happens when you seek, but it is not quite as aggressive. No need to do a full video state reset or such. We also wait an arbitrary amount of frames before adjusting for av sync again. compute_audio_drift already used a magic number of 10 which sounds reasonable enough so define that and use it here. Fixes #13513.
Diffstat (limited to 'player')
-rw-r--r--player/command.c1
-rw-r--r--player/core.h1
-rw-r--r--player/video.c22
3 files changed, 22 insertions, 2 deletions
diff --git a/player/command.c b/player/command.c
index d5a315290e..f8fac69ef7 100644
--- a/player/command.c
+++ b/player/command.c
@@ -7228,6 +7228,7 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags,
if (opt_ptr == &opts->playback_speed) {
update_playback_speed(mpctx);
+ reset_av_state(mpctx);
mp_wakeup_core(mpctx);
}
diff --git a/player/core.h b/player/core.h
index 2fc3c45700..9dc6b8bf90 100644
--- a/player/core.h
+++ b/player/core.h
@@ -636,6 +636,7 @@ void update_osd_msg(struct MPContext *mpctx);
bool update_subtitles(struct MPContext *mpctx, double video_pts);
// video.c
+void reset_av_state(struct MPContext *mpctx);
void reset_video_state(struct MPContext *mpctx);
int init_video_decoder(struct MPContext *mpctx, struct track *track);
void reinit_video_chain(struct MPContext *mpctx);
diff --git a/player/video.c b/player/video.c
index 70ef18958b..6b63cc7b0e 100644
--- a/player/video.c
+++ b/player/video.c
@@ -45,6 +45,8 @@
#include "command.h"
#include "screenshot.h"
+#define MIN_PAST_FRAMES 10
+
enum {
// update_video() - code also uses: <0 error, 0 eof, >0 progress
VD_ERROR = -1,
@@ -95,6 +97,17 @@ static void vo_chain_reset_state(struct vo_chain *vo_c)
vo_c->underrun_signaled = false;
}
+void reset_av_state(struct MPContext *mpctx)
+{
+ mpctx->delay = 0;
+ mpctx->display_sync_drift_dir = 0;
+ mpctx->display_sync_error = 0;
+ mpctx->last_av_difference = 0;
+ mpctx->logged_async_diff = -1;
+ mpctx->num_past_frames = 0;
+ mpctx->total_avsync_change = 0;
+}
+
void reset_video_state(struct MPContext *mpctx)
{
if (mpctx->vo_chain) {
@@ -592,7 +605,9 @@ static void update_avsync_before_frame(struct MPContext *mpctx)
if (mpctx->video_status < STATUS_READY) {
mpctx->time_frame = 0;
- } else if (mpctx->display_sync_active || vo->opts->video_sync == VS_NONE) {
+ } else if (mpctx->display_sync_active || vo->opts->video_sync == VS_NONE ||
+ mpctx->num_past_frames <= MIN_PAST_FRAMES)
+ {
// don't touch the timing
} else if (mpctx->audio_status == STATUS_PLAYING &&
mpctx->video_status == STATUS_PLAYING &&
@@ -726,7 +741,7 @@ static double compute_audio_drift(struct MPContext *mpctx, double vsync)
// audio desync for y. Assume speed didn't change for the frames we're
// looking at for simplicity. This also should actually use the realtime
// (minus paused time) for x, but use vsync scheduling points instead.
- if (mpctx->num_past_frames <= 10)
+ if (mpctx->num_past_frames <= MIN_PAST_FRAMES)
return NAN;
int num = mpctx->num_past_frames - 1;
double sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
@@ -831,6 +846,9 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
if (resample && using_spdif_passthrough(mpctx))
return;
+ if (mpctx->num_past_frames <= MIN_PAST_FRAMES)
+ return;
+
double vsync = vo_get_vsync_interval(vo) / 1e9;
if (vsync <= 0)
return;