summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-11-13 22:47:14 +0100
committerwm4 <wm4@nowhere>2015-11-13 22:47:14 +0100
commit62b386c2fdb6d113c2c1042f0b3a973f3fb11828 (patch)
tree7028e7d60521971ef5d94cbf957a7ff63015c2c5
parentfad254562b09dcff4d6c95aff5982a6252b09ebb (diff)
downloadmpv-62b386c2fdb6d113c2c1042f0b3a973f3fb11828.tar.bz2
mpv-62b386c2fdb6d113c2c1042f0b3a973f3fb11828.tar.xz
player: compute required display-sync speed change differently
Instead of looking at the current frame duration for the intended speedup, look at all past frames, and find a good average speed. This ties in with not wanting to average _all_ frame durations, which doesn't make sense in VFR situations. This is currently done in the most naive way possible, but already sort of works for VFR which switches between frame durations that are integer multiples of a base rate. Certainly more improvements could be made, such as trying to adjust directly on FPS changes, instead of averaging everything, but for now this is not needed at all.
-rw-r--r--player/video.c58
1 files changed, 36 insertions, 22 deletions
diff --git a/player/video.c b/player/video.c
index d6140773eb..8ee9c87e93 100644
--- a/player/video.c
+++ b/player/video.c
@@ -814,6 +814,40 @@ double calc_average_frame_duration(struct MPContext *mpctx)
return num > 0 ? total / num : 0;
}
+// 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.
+// Both parameters are durations in seconds.
+static double calc_best_speed(double vsync, double frame)
+{
+ double ratio = frame / vsync;
+ double best_scale = -1;
+ double best_dev = INFINITY;
+ for (int factor = 1; factor <= 5; factor++) {
+ double scale = ratio * factor / rint(ratio * factor);
+ double dev = fabs(scale - 1);
+ if (dev < best_dev) {
+ best_scale = scale;
+ best_dev = dev;
+ }
+ }
+ return best_scale;
+}
+
+static double find_best_speed(struct MPContext *mpctx, double vsync)
+{
+ double total = 0;
+ int num = 0;
+ for (int n = 0; n < mpctx->num_past_frames; n++) {
+ double dur = mpctx->past_frames[n].approx_duration;
+ if (dur <= 0)
+ continue;
+ total += calc_best_speed(vsync, dur / mpctx->opts->playback_speed);
+ num++;
+ }
+ return num > 0 ? total / num : 1;
+}
+
static bool using_spdif_passthrough(struct MPContext *mpctx)
{
if (mpctx->d_audio && mpctx->d_audio->afilter)
@@ -861,24 +895,6 @@ static void adjust_audio_speed(struct MPContext *mpctx, double vsync)
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.
-// Both parameters are durations in seconds.
-static double calc_best_speed(struct MPContext *mpctx, double vsync, double frame)
-{
- struct MPOpts *opts = mpctx->opts;
-
- double ratio = frame / vsync;
- for (int factor = 1; factor <= 5; factor++) {
- double scale = ratio * factor / floor(ratio * factor + 0.5);
- if (fabs(scale - 1) > opts->sync_max_video_change / 100)
- continue; // large deviation, skip
- return scale; // decent match found
- }
- return -1;
-}
-
// Manipulate frame timing for display sync, or do nothing for normal timing.
static void handle_display_sync_frame(struct MPContext *mpctx,
struct vo_frame *frame)
@@ -913,15 +929,13 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
goto done;
double adjusted_duration = mpctx->past_frames[0].approx_duration;
- double avg_duration = calc_average_frame_duration(mpctx);
adjusted_duration /= opts->playback_speed;
- avg_duration /= opts->playback_speed;
if (adjusted_duration <= 0.001 || adjusted_duration > 0.5)
goto done;
- mpctx->speed_factor_v = calc_best_speed(mpctx, vsync, avg_duration);
+ mpctx->speed_factor_v = find_best_speed(mpctx, vsync);
// If it doesn't work, play at normal speed.
- if (mpctx->speed_factor_v <= 0)
+ if (fabs(mpctx->speed_factor_v - 1.0) > opts->sync_max_video_change / 100)
mpctx->speed_factor_v = 1.0;
double av_diff = mpctx->last_av_difference;