File mpv_PR12917.patch of Package mpv
From 5ea07394d96a3b13e92522095fce205eeeba55ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <kasper93@gmail.com>
Date: Sun, 19 Nov 2023 05:47:53 +0100
Subject: [PATCH] vo_gpu_next: limit pl_frame_mix to 16 Frames
This update addresses a limit in libplacebo that occurs when
`skip_anti_aliasing` is disabled. When the VPS/FPS ratio is
exceptionally high, `pl_queue` can return larger mixes dependent on the
chosen mixing kernel. This problem is further compounded by inaccurate
or outdated VPS estimations in `pl_queue`.
To circumvent this issue, the frame mix is now limited to 16 frames,
which is consistent with the implementation limit in libplacebo.
Fixes: src/renderer.c:3536: pl_render_image_mix: Assertion `fidx < MAX_MIX_FRAMES' failed.
---
video/out/vo_gpu_next.c | 43 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c
index e003f2391fdd..0b91b297fa81 100644
--- a/video/out/vo_gpu_next.c
+++ b/video/out/vo_gpu_next.c
@@ -861,6 +861,40 @@ static void update_tm_viz(struct pl_color_map_params *params,
params->visualize_hue = M_PI / 4.0;
}
+static void rearrange_frame_mix(struct pl_frame_mix *mix) {
+ // Internal libplacebo frame mixing limit
+ // https://code.videolan.org/videolan/libplacebo/-/blob/426f346762180e6496e714a087be9561a9a1e236/src/renderer.c#L3254
+ static const int frame_mix_limit = 16;
+
+ if (mix->num_frames <= frame_mix_limit)
+ return;
+
+ int nearest = 0;
+ float best_dist = fabsf(mix->timestamps[nearest]);
+ for (int i = 1; i < mix->num_frames; i++) {
+ float dist = fabsf(mix->timestamps[i]);
+ if (dist >= best_dist)
+ break;
+ best_dist = dist;
+ nearest = i;
+ }
+
+ int count = frame_mix_limit / 2;
+ int start = nearest - count;
+ if (start < 0) {
+ count -= start;
+ start = 0;
+ }
+ int end = MPMIN(nearest + count, mix->num_frames);
+
+ for (int i = start, j = 0; i < end; i++, j++) {
+ ((struct pl_frame **)mix->frames)[j] = (struct pl_frame *)mix->frames[i];
+ ((uint64_t *)mix->signatures)[j] = mix->signatures[i];
+ ((float *)mix->timestamps)[j] = mix->timestamps[i];
+ }
+ mix->num_frames = end - start;
+}
+
static void draw_frame(struct vo *vo, struct vo_frame *frame)
{
struct priv *p = vo->priv;
@@ -1021,6 +1055,15 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
break;
}
+ // When `skip_anti_aliasing` is set to false, libplacebo stretches the
+ // mixing kernel. This behavior depends on the VPS/FPS ratio and the
+ // chosen mixing kernel. Consequently, `pl_queue` may return a mix with
+ // an unbounded size. Such behavior is not supported and is internally
+ // asserted in libplacebo (see https://code.videolan.org/videolan/libplacebo/-/blob/426f346762180e6496e714a087be9561a9a1e236/src/renderer.c#L3536).
+ // To properly handle this scenario, keep the 16 closest frames in
+ // `pl_frame_mix` to prevent exceeding the implementation limits.
+ rearrange_frame_mix(&mix);
+
// Update source crop and overlays on all existing frames. We
// technically own the `pl_frame` struct so this is kosher. This could
// be partially avoided by instead flushing the queue on resizes, but