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
openSUSE Build Service is sponsored by