From 8edabd5644e0b69bffd1fa0d482acca1673db5df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=ED=95=9C=EC=8A=B9=EB=AF=BC?= <hanseungmin@proton.me>
Date: Sat, 22 Mar 2025 19:35:11 +0900
Subject: [PATCH] vo_kitty: do not add trailing `NULL` byte in payload

In the past `strlen` was used in the write function, which omitted the
trailing NULL byte, however with the addition of `bstr` API the NULL
byte produced by `av_base64_encode` in the output is also written to
stdout, this causes terminals (namely Ghostty) to not display the frame.

There was also an additional edge case where if the entire output is
less than 4096 bytes the finishing escape sequence `\033_Gm=0;` was
never emitted. Adding a check for this after the for loop fixes this
behavior.
---
 video/out/vo_kitty.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/video/out/vo_kitty.c b/video/out/vo_kitty.c
index 11a0b5ed7e..2e403af50a 100644
--- a/video/out/vo_kitty.c
+++ b/video/out/vo_kitty.c
@@ -346,19 +346,32 @@ static void flip_page(struct vo *vo)
         DCS_GUARD_APPEND(p, bstr_xappend_asprintf(NULL, &p->cmd, KITTY_ESC_IMG,
                               p->width, p->height));
 
-        for (int offset = 0; offset < p->output_size; ) {
-            int chunk = MPMIN(4096, p->output_size - offset);
+        int output_size = p->output_size - 1;
+        int offset = 0;
+
+        for (; offset < output_size; ) {
+            int chunk = MPMIN(4096, output_size - offset);
 
             if (offset > 0)
                 DCS_GUARD_APPEND(p, bstr_xappend_asprintf(NULL, &p->cmd,
                                     KITTY_ESC_CONTINUE,
-                                    offset + chunk < p->output_size));
+                                    offset + chunk < output_size));
 
             // Append at max chunk bytes
             bstr_xappend(NULL, &p->cmd, (bstr){p->output + offset, chunk});
             DCS_GUARD_APPEND(p, bstr_xappend(NULL, &p->cmd, KITTY_ESC_END));
             offset += chunk;
         }
+
+        // When the data is less than or equal to chunk size the final packet
+        // isn't sent, i.e. an escape sequence with `m=0`.
+        // This ensures that an escape sequence with `m=0` is sent and
+        // terminals stay happy
+        if (offset == 0) {
+            DCS_GUARD_APPEND(p, bstr_xappend_asprintf(NULL, &p->cmd,
+                                KITTY_ESC_CONTINUE, 0));
+            DCS_GUARD_APPEND(p, bstr_xappend(NULL, &p->cmd, KITTY_ESC_END));
+        }
     }
 
     write_bstr(p->cmd);