From 8f7cf9443f9336c7ca94301aa302612937c463ca Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 4 Nov 2015 19:37:15 +0100 Subject: player: move audio speed adjustment code Move it (in a cosmetic sense), and also move its invocation to below all the video handling. All other changes remain cosmetic, including moving the framedrop calculation code, and getting rid of the video_speed_correction variable. --- player/video.c | 114 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 54 deletions(-) diff --git a/player/video.c b/player/video.c index 349353e230..540b27f4c4 100644 --- a/player/video.c +++ b/player/video.c @@ -874,6 +874,46 @@ static bool using_spdif_passthrough(struct MPContext *mpctx) return false; } +static void adjust_audio_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; + } + + mpctx->speed_factor_a = audio_factor * mpctx->speed_factor_v; + + MP_STATS(mpctx, "value %f aspeed", mpctx->speed_factor_a - 1); +} + // Find a speed factor such that the display FPS is an integer multiple of the // effective video FPS. If this is not possible, try to do it for multiples, // which still leads to an improved end result. @@ -938,9 +978,11 @@ static void handle_display_sync_frame(struct MPContext *mpctx, goto done; } - double video_speed_correction = calc_best_speed(mpctx, vsync, adjusted_duration); - if (video_speed_correction <= 0) + mpctx->speed_factor_v = calc_best_speed(mpctx, vsync, adjusted_duration); + if (mpctx->speed_factor_v <= 0) { + mpctx->speed_factor_v = 1.0; goto done; + } double av_diff = mpctx->last_av_difference; if (fabs(av_diff) > 0.5) @@ -956,59 +998,11 @@ static void handle_display_sync_frame(struct MPContext *mpctx, mpctx->display_sync_disable_counter = 50; } - MP_STATS(mpctx, "value %f avdiff", av_diff); - - // Intended number of additional display frames to drop (<0) or repeat (>0) - int drop_repeat = 0; - - // If we are too far ahead/behind, attempt to drop/repeat frames. In - // particular, don't attempt to change speed for them. - // Tolerate some desync to avoid frame dropping due to jitter. - if (drop && fabs(av_diff) >= 0.080 && fabs(av_diff) / vsync >= 2) - drop_repeat = -av_diff / vsync; // round towards 0 - - av_diff += drop_repeat * vsync; - - if (resample) { - 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; - 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; - } - - mpctx->speed_factor_a = audio_factor * video_speed_correction; - - MP_STATS(mpctx, "value %f aspeed", mpctx->speed_factor_a - 1); - } - // Determine for how many vsyncs a frame should be displayed. This can be // e.g. 2 for 30hz on a 60hz display. It can also be 0 if the video // framerate is higher than the display framerate. // We use the speed-adjusted (i.e. real) frame duration for this. - double frame_duration = adjusted_duration / video_speed_correction; + double frame_duration = adjusted_duration / mpctx->speed_factor_v; double ratio = (frame_duration + mpctx->display_sync_error) / vsync; int num_vsyncs = MPMAX(floor(ratio + 0.5), 0); double prev_error = mpctx->display_sync_error; @@ -1016,9 +1010,20 @@ static void handle_display_sync_frame(struct MPContext *mpctx, frame->vsync_offset = mpctx->display_sync_error * 1e6; MP_DBG(mpctx, "s=%f vsyncs=%d dur=%f ratio=%f err=%.20f (%f)\n", - video_speed_correction, num_vsyncs, adjusted_duration, ratio, + mpctx->speed_factor_v, num_vsyncs, adjusted_duration, ratio, mpctx->display_sync_error, mpctx->display_sync_error / vsync); + MP_STATS(mpctx, "value %f avdiff", av_diff); + + // Intended number of additional display frames to drop (<0) or repeat (>0) + int drop_repeat = 0; + + // If we are too far ahead/behind, attempt to drop/repeat frames. In + // particular, don't attempt to change speed for them. + // Tolerate some desync to avoid frame dropping due to jitter. + if (drop && fabs(av_diff) >= 0.080 && fabs(av_diff) / vsync >= 2) + drop_repeat = -av_diff / vsync; // round towards 0 + // We can only drop all frames at most. We can repeat much more frames, // but we still limit it to 10 times the original frames to avoid that // corner cases or exceptional situations cause too much havoc. @@ -1042,11 +1047,12 @@ static void handle_display_sync_frame(struct MPContext *mpctx, mpctx->total_avsync_change = 0; update_av_diff(mpctx, time_left * opts->playback_speed); + if (resample) + adjust_audio_speed(mpctx, vsync); + // A bad guess, only needed when reverting to audio sync. mpctx->time_frame = time_left; - mpctx->speed_factor_v = video_speed_correction; - frame->num_vsyncs = num_vsyncs; frame->display_synced = true; -- cgit v1.2.3