summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-11-13 22:50:58 +0100
committerwm4 <wm4@nowhere>2015-11-13 22:50:58 +0100
commitc362c3d7ae85ac65e5e87004d33775f3cb291498 (patch)
tree39594bcaee88f5bf91fa9a461e609a2e2a49a8d4
parent07b8abbd62c8d5b28f52a3e5e0192f16cad2405b (diff)
downloadmpv-c362c3d7ae85ac65e5e87004d33775f3cb291498.tar.bz2
mpv-c362c3d7ae85ac65e5e87004d33775f3cb291498.tar.xz
player: change display-sync audio speed only if needed
As long as it's within the desync tolerance, do not change the audio speed at all for resampling. This reduces speed changes which might be caused by jittering timestamps and similar cases. (While in theory you could just not care and change speed every single frame, I'm afraid that such changes could possibly cause audio artifacts. So better just avoid it in the first place.)
-rw-r--r--player/video.c86
1 files changed, 48 insertions, 38 deletions
diff --git a/player/video.c b/player/video.c
index 281789e2a4..65982d319e 100644
--- a/player/video.c
+++ b/player/video.c
@@ -854,44 +854,47 @@ static bool using_spdif_passthrough(struct MPContext *mpctx)
return false;
}
-static void adjust_audio_speed(struct MPContext *mpctx, double vsync)
+static void adjust_audio_resample_speed(struct MPContext *mpctx, double vsync)
{
struct MPOpts *opts = mpctx->opts;
int mode = opts->video_sync;
- double audio_factor = 1.0;
-
- if (mode == VS_DISP_RESAMPLE && mpctx->audio_status == STATUS_PLAYING) {
- // Try to smooth out audio timing drifts. This can happen if either
- // video isn't playing at expected speed, or audio is not playing at
- // the requested speed. Both are unavoidable.
- // The audio desync is made up of 2 parts: 1. drift due to rounding
- // errors and imperfect information, and 2. an offset, due to
- // unaligned audio/video start, or disruptive events halting audio
- // or video for a small time.
- // Instead of trying to be clever, just apply an awfully dumb drift
- // compensation with a constant factor, which does what we want. In
- // theory we could calculate the exact drift compensation needed,
- // but it likely would be wrong anyway, and we'd run into the same
- // issues again, except with more complex code.
- // 1 means drifts to positive, -1 means drifts to negative
- double max_drift = vsync / 2;
- double av_diff = mpctx->last_av_difference;
- int new = mpctx->display_sync_drift_dir;
- if (av_diff * -mpctx->display_sync_drift_dir >= 0)
- new = 0;
- if (fabs(av_diff) > max_drift)
- new = av_diff >= 0 ? 1 : -1;
- if (mpctx->display_sync_drift_dir != new) {
- MP_VERBOSE(mpctx, "Change display sync audio drift: %d\n", new);
- mpctx->display_sync_drift_dir = new;
- }
- double max_correct = opts->sync_max_audio_change / 100;
- audio_factor = 1 + max_correct * -mpctx->display_sync_drift_dir;
+
+ if (mode != VS_DISP_RESAMPLE || mpctx->audio_status != STATUS_PLAYING) {
+ mpctx->speed_factor_a = mpctx->speed_factor_v;
+ return;
}
- mpctx->speed_factor_a = audio_factor * mpctx->speed_factor_v;
+ // Try to smooth out audio timing drifts. This can happen if either
+ // video isn't playing at expected speed, or audio is not playing at
+ // the requested speed. Both are unavoidable.
+ // The audio desync is made up of 2 parts: 1. drift due to rounding
+ // errors and imperfect information, and 2. an offset, due to
+ // unaligned audio/video start, or disruptive events halting audio
+ // or video for a small time.
+ // Instead of trying to be clever, just apply an awfully dumb drift
+ // compensation with a constant factor, which does what we want. In
+ // theory we could calculate the exact drift compensation needed,
+ // but it likely would be wrong anyway, and we'd run into the same
+ // issues again, except with more complex code.
+ // 1 means drifts to positive, -1 means drifts to negative
+ double max_drift = vsync / 2;
+ double av_diff = mpctx->last_av_difference;
+ int new = mpctx->display_sync_drift_dir;
+ if (av_diff * -mpctx->display_sync_drift_dir >= 0)
+ new = 0;
+ if (fabs(av_diff) > max_drift)
+ new = av_diff >= 0 ? 1 : -1;
+
+ bool change = mpctx->display_sync_drift_dir != new;
+ if (new || change) {
+ if (change)
+ MP_VERBOSE(mpctx, "Change display sync audio drift: %d\n", new);
+ mpctx->display_sync_drift_dir = new;
- MP_STATS(mpctx, "value %f aspeed", mpctx->speed_factor_a - 1);
+ double max_correct = opts->sync_max_audio_change / 100;
+ double audio_factor = 1 + max_correct * -mpctx->display_sync_drift_dir;
+ mpctx->speed_factor_a = audio_factor * mpctx->speed_factor_v;
+ }
}
// Manipulate frame timing for display sync, or do nothing for normal timing.
@@ -908,8 +911,6 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
}
mpctx->display_sync_active = false;
- mpctx->speed_factor_a = 1.0;
- mpctx->speed_factor_v = 1.0;
if (!VS_IS_DISP(mode))
goto done;
@@ -1002,8 +1003,11 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
mpctx->past_frames[0].num_vsyncs = num_vsyncs;
- if (resample)
- adjust_audio_speed(mpctx, vsync);
+ if (resample) {
+ adjust_audio_resample_speed(mpctx, vsync);
+ } else {
+ mpctx->speed_factor_a = 1.0;
+ }
// A bad guess, only needed when reverting to audio sync.
mpctx->time_frame = time_left;
@@ -1012,10 +1016,12 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
frame->display_synced = true;
mpctx->display_sync_active = true;
+ update_playback_speed(mpctx);
-done:
+ MP_STATS(mpctx, "value %f aspeed", mpctx->speed_factor_a - 1);
+ MP_STATS(mpctx, "value %f vspeed", mpctx->speed_factor_v - 1);
- update_playback_speed(mpctx);
+done:
if (mpctx->num_past_frames > 1 &&
((mpctx->past_frames[1].num_vsyncs >= 0) != mpctx->display_sync_active))
@@ -1030,6 +1036,10 @@ static void schedule_frame(struct MPContext *mpctx, struct vo_frame *frame)
handle_display_sync_frame(mpctx, frame);
if (!mpctx->display_sync_active) {
+ mpctx->speed_factor_a = 1.0;
+ mpctx->speed_factor_v = 1.0;
+ update_playback_speed(mpctx);
+
update_av_diff(mpctx, mpctx->time_frame > 0 ?
mpctx->time_frame * mpctx->video_speed : 0);
}