PR #25195 opened by thardin
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25195
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25195.patch

This is essentially #23216 but with FATE changes applied. Not sure if this is 
the best way to go about fixing someone else's PR. Original commit message 
below:

---

The Saturn Cinepak libraries require that all chunks start on a 32-bit
boundary, presumably for performance reasons: the SH-2 processor used
doesn't support unaligned 32-bit or 16-bit loads.

We can easily achieve this by padding all chunks to a multiple of 4
bytes using zeroes.

This is not gated behind an option as the overhead is negligible (eg.
~0.02% for a 3-minute, 320x224 video at -q:v 50)


>From 578a4cda6272ebd9bb3cb3581df36f247fe96166 Mon Sep 17 00:00:00 2001
From: abrasive <[email protected]>
Date: Sun, 24 May 2026 12:48:37 +1000
Subject: [PATCH] avcodec/cinepakenc: align for vintage Sega Saturn decoder

The Saturn Cinepak libraries require that all chunks start on a 32-bit
boundary, presumably for performance reasons: the SH-2 processor used
doesn't support unaligned 32-bit or 16-bit loads.

We can easily achieve this by padding all chunks to a multiple of 4
bytes using zeroes.

This is not gated behind an option as the overhead is negligible (eg.
~0.02% for a 3-minute, 320x224 video at -q:v 50)
---
 libavcodec/cinepakenc.c              | 30 ++++++++++++++++++++++++----
 tests/ref/vsynth/vsynth1-cinepak     |  4 ++--
 tests/ref/vsynth/vsynth2-cinepak     |  4 ++--
 tests/ref/vsynth/vsynth_lena-cinepak |  4 ++--
 4 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c
index 104a9f485e..bfc1df9bce 100644
--- a/libavcodec/cinepakenc.c
+++ b/libavcodec/cinepakenc.c
@@ -379,20 +379,30 @@ static int write_chunk_header(unsigned char *buf, int 
chunk_type, int chunk_size
     return CHUNK_HEADER_SIZE;
 }
 
+static int align_longword(int size)
+{
+  // Sega Saturn vintage decoder requires that all chunks start on a longword 
(4
+  // byte) boundary, as it can't do unaligned 32-bit or 16-bit loads. Making
+  // sure all chunks are a multiple of 4 bytes long achieves this
+  return (size + 3) & ~3;
+}
+
 static int encode_codebook(CinepakEncContext *s, int *codebook, int size,
                            int chunk_type_yuv, int chunk_type_gray,
                            unsigned char *buf)
 {
-    int x, y, ret, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
+    int x, y, ret, chunk_size, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 
: 4;
     int incremental_codebook_replacement_mode = 0; // hardcoded here,
     // the compiler should notice that this is a constant -- rl
 
+    chunk_size = align_longword(entry_size * size +
+                     (incremental_codebook_replacement_mode ? (size + 31) / 32 
* 4 : 0));
+
     ret = write_chunk_header(buf,
                              s->pix_fmt == AV_PIX_FMT_RGB24 ?
                              chunk_type_yuv  + 
(incremental_codebook_replacement_mode ? 1 : 0) :
                              chunk_type_gray + 
(incremental_codebook_replacement_mode ? 1 : 0),
-                             entry_size * size +
-                             (incremental_codebook_replacement_mode ? (size + 
31) / 32 * 4 : 0));
+                             chunk_size);
 
     // we do codebook encoding according to the "intra" mode
     // but we keep the "dead" code for reference in case we will want
@@ -423,6 +433,9 @@ static int encode_codebook(CinepakEncContext *s, int 
*codebook, int size,
             for (y = 0; y < entry_size; y++)
                 buf[ret++] = codebook[y + x * entry_size] ^ (y >= 4 ? 0x80 : 
0);
 
+    while (ret & 3)
+        buf[ret++] = 0;
+
     return ret;
 }
 
@@ -568,11 +581,14 @@ static int encode_mode(CinepakEncContext *s, int h,
 
     switch (info->mode) {
     case MODE_V1_ONLY:
-        ret += write_chunk_header(buf + ret, 0x32, mb_count);
+        ret += write_chunk_header(buf + ret, 0x32, align_longword(mb_count));
 
         for (x = 0; x < mb_count; x++)
             buf[ret++] = s->mb[x].v1_vector;
 
+        while (ret & 3)
+            buf[ret++] = 0;
+
         break;
     case MODE_V1_V4:
         // remember header position
@@ -599,6 +615,9 @@ static int encode_mode(CinepakEncContext *s, int h,
             }
         }
 
+        while (ret & 3)
+            buf[ret++] = 0;
+
         write_chunk_header(buf + header_ofs, 0x30, ret - header_ofs - 
CHUNK_HEADER_SIZE);
 
         break;
@@ -659,6 +678,9 @@ static int encode_mode(CinepakEncContext *s, int h,
             ret += temp_size;
         }
 
+        while (ret & 3)
+            buf[ret++] = 0;
+
         write_chunk_header(buf + header_ofs, 0x31, ret - header_ofs - 
CHUNK_HEADER_SIZE);
 
         break;
diff --git a/tests/ref/vsynth/vsynth1-cinepak b/tests/ref/vsynth/vsynth1-cinepak
index 7cb33220e7..66469b4c78 100644
--- a/tests/ref/vsynth/vsynth1-cinepak
+++ b/tests/ref/vsynth/vsynth1-cinepak
@@ -1,4 +1,4 @@
-6b9b4d2b32854fd8b0f84ee4d76b1fed *tests/data/fate/vsynth1-cinepak.avi
-408910 tests/data/fate/vsynth1-cinepak.avi
+9ac6a985c698a34f6d9e6251324a6bfb *tests/data/fate/vsynth1-cinepak.avi
+409272 tests/data/fate/vsynth1-cinepak.avi
 4acdcc3e664d12facbcefc389079cfa6 *tests/data/fate/vsynth1-cinepak.out.rawvideo
 stddev:   61.38 PSNR: 12.37 MAXDIFF:  223 bytes:  7603200/   921600
diff --git a/tests/ref/vsynth/vsynth2-cinepak b/tests/ref/vsynth/vsynth2-cinepak
index 72b8794116..8a420e916c 100644
--- a/tests/ref/vsynth/vsynth2-cinepak
+++ b/tests/ref/vsynth/vsynth2-cinepak
@@ -1,4 +1,4 @@
-675d6a4370c315dc53c219a9271be4c6 *tests/data/fate/vsynth2-cinepak.avi
-400720 tests/data/fate/vsynth2-cinepak.avi
+d7420dd4f4656006f2491626bf225655 *tests/data/fate/vsynth2-cinepak.avi
+401072 tests/data/fate/vsynth2-cinepak.avi
 cbf6900b882b484bc531f9b4799c226e *tests/data/fate/vsynth2-cinepak.out.rawvideo
 stddev:   80.96 PSNR:  9.96 MAXDIFF:  229 bytes:  7603200/   921600
diff --git a/tests/ref/vsynth/vsynth_lena-cinepak 
b/tests/ref/vsynth/vsynth_lena-cinepak
index c9cb2cfaba..4d9c5ccbcb 100644
--- a/tests/ref/vsynth/vsynth_lena-cinepak
+++ b/tests/ref/vsynth/vsynth_lena-cinepak
@@ -1,4 +1,4 @@
-a79f907fecb95c8a5b5de670ccda215b *tests/data/fate/vsynth_lena-cinepak.avi
-407952 tests/data/fate/vsynth_lena-cinepak.avi
+c6ab0e311006ab71d1fea084a4ece5db *tests/data/fate/vsynth_lena-cinepak.avi
+408304 tests/data/fate/vsynth_lena-cinepak.avi
 2664cdff5f14508e891477b498cc840e 
*tests/data/fate/vsynth_lena-cinepak.out.rawvideo
 stddev:   58.10 PSNR: 12.85 MAXDIFF:  185 bytes:  7603200/   921600
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to