From c362c3d7ae85ac65e5e87004d33775f3cb291498 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 13 Nov 2015 22:50:58 +0100 Subject: 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.) --- player/video.c | 86 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 38 deletions(-) (limited to 'player/video.c') 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); } -- cgit v1.2.3