File mpv_PR12840.patch of Package mpv

From e339f79154e2b9eda8a03c21da801590a7c85a43 Mon Sep 17 00:00:00 2001
From: Dudemanguy <random342@airmail.cc>
Date: Mon, 6 Nov 2023 12:21:50 -0600
Subject: [PATCH] dec_sub: cache up to 10 packets

062104d16e34f348ffd9324ca4c997b6b0f487d4 started saving 2 packets in
memory for the purposes of runtime updates of some options, but
sometimes we need more. There are subs out there that will have
overlapping durations so saving only 2 packets would only update those 2
subs at most and drop the rest. So with that in mind, let's just cache
up to 10 (arbitrary but surely no one needs more) packets instead. We
don't always want to hold onto that many since it's useless 99% of the
time, so do some logic by checking the video pts and the durations. At
least 2 must always be kept though so there's some extra conditions.
---
 sub/dec_sub.c | 50 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index 18d826e8b591..8222d5ac6eca 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -32,6 +32,8 @@
 #include "misc/dispatch.h"
 #include "osdep/threads.h"
 
+#define PKT_CACHE 10
+
 extern const struct sd_functions sd_ass;
 extern const struct sd_functions sd_lavc;
 
@@ -68,7 +70,7 @@ struct dec_sub {
     struct sd *sd;
 
     struct demux_packet *new_segment;
-    struct demux_packet *cached_pkts[2];
+    struct demux_packet *cached_pkts[PKT_CACHE];
 };
 
 static void update_subtitle_speed(struct dec_sub *sub)
@@ -193,6 +195,30 @@ struct dec_sub *sub_create(struct mpv_global *global, struct track *track,
     return NULL;
 }
 
+// Called locked.
+static void update_cached_packets(struct dec_sub *sub, struct demux_packet *pkt,
+                                  double video_pts)
+{
+    // Unconditionally cleared.
+    if (sub->cached_pkts[PKT_CACHE - 1])
+        TA_FREEP(&sub->cached_pkts[PKT_CACHE - 1]);
+
+    // Always save at least 2 packets but allow up to PKT_CACHE
+    // for subs with overlapping durations.
+    int i = PKT_CACHE;
+    while (--i) {
+        struct demux_packet *prev_pkt = sub->cached_pkts[i - 1];
+        if (prev_pkt) {
+            double prev_pkt_end = prev_pkt->pts + prev_pkt->duration;
+            if (sub->cached_pkts[i] && prev_pkt_end < video_pts)
+                TA_FREEP(&sub->cached_pkts[i]);
+            sub->cached_pkts[i] = prev_pkt;
+            sub->cached_pkts[i - 1] = NULL;
+        }
+    }
+    sub->cached_pkts[0] = pkt;
+}
+
 // Called locked.
 static void update_segment(struct dec_sub *sub)
 {
@@ -309,15 +335,7 @@ bool sub_read_packets(struct dec_sub *sub, double video_pts, bool force)
         if (sub->recorder_sink)
             mp_recorder_feed_packet(sub->recorder_sink, pkt);
 
-
-        // Update cached packets
-        if (sub->cached_pkts[0]) {
-            if (sub->cached_pkts[1])
-                talloc_free(sub->cached_pkts[1]);
-            sub->cached_pkts[1] = sub->cached_pkts[0];
-        }
-        sub->cached_pkts[0] = pkt;
-
+        update_cached_packets(sub, pkt, video_pts);
         sub->last_pkt_pts = pkt->pts;
 
         if (is_new_segment(sub, pkt)) {
@@ -339,10 +357,10 @@ bool sub_read_packets(struct dec_sub *sub, double video_pts, bool force)
 void sub_redecode_cached_packets(struct dec_sub *sub)
 {
     mp_mutex_lock(&sub->lock);
-    if (sub->cached_pkts[0])
-        sub->sd->driver->decode(sub->sd, sub->cached_pkts[0]);
-    if (sub->cached_pkts[1])
-        sub->sd->driver->decode(sub->sd, sub->cached_pkts[1]);
+    for (int i = 0; i < PKT_CACHE; i++) {
+        if (sub->cached_pkts[i])
+            sub->sd->driver->decode(sub->sd, sub->cached_pkts[i]);
+    }
     mp_mutex_unlock(&sub->lock);
 }
 
@@ -417,8 +435,8 @@ void sub_reset(struct dec_sub *sub)
         sub->sd->driver->reset(sub->sd);
     sub->last_pkt_pts = MP_NOPTS_VALUE;
     sub->last_vo_pts = MP_NOPTS_VALUE;
-    TA_FREEP(&sub->cached_pkts[0]);
-    TA_FREEP(&sub->cached_pkts[1]);
+    for (int i = 0; i < PKT_CACHE; i++)
+        TA_FREEP(&sub->cached_pkts[i]);
     TA_FREEP(&sub->new_segment);
     mp_mutex_unlock(&sub->lock);
 }
openSUSE Build Service is sponsored by