Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] avcodec/sanm: implement codec45 (PR #20795)
@ 2025-10-30 15:23 Manuel Lauss via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: Manuel Lauss via ffmpeg-devel @ 2025-10-30 15:23 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

PR #20795 opened by Manuel Lauss (mlauss2)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20795
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20795.patch

This is another post-processing codec: it sums the r/g/b componentes
of the 4 surrounding pixels, and uses the 15bit-rgb value as an index into
a second table to find a matching pixel.

It is only used in the first 10-20 frames of the Rebel Assault 2 LxxRETRY.SAN files
to slightly blur the outline of the "opening aperture" effect.


Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>


>From 137913ee994bf18fd3444b76893237474ec93ef4 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <manuel.lauss@gmail.com>
Date: Thu, 30 Oct 2025 16:01:10 +0100
Subject: [PATCH] avcodec/sanm: implement codec45

This is another post-processing codec: it sums the r/g/b componentes
of the 4 surrounding pixels, and uses the 15bit-rgb value as an index into
a second table to find a matching pixel.

It is only used in 10-20 frames of the Rebel Assault 2 LxxRETRY.SAN files
to slightly blur the outline of the "opening aperture" effect.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 libavcodec/sanm.c | 77 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 2 deletions(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 742fc1d477..1d04edc672 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -297,6 +297,8 @@ typedef struct SANMVideoContext {
     uint8_t c4tbl[2][256][16];
     uint16_t c4param;
     uint8_t c47cb[4];
+    uint8_t c45tbl1[0x300];
+    uint8_t c45tbl2[0x8000];
 } SANMVideoContext;
 
 enum GlyphEdge {
@@ -1946,6 +1948,71 @@ static int old_codec48(SANMVideoContext *ctx, GetByteContext *gb, int top, int l
     return 0;
 }
 
+static void old_codec45(SANMVideoContext *ctx, GetByteContext *gb, int top, int left, int flag)
+{
+    int t1, t2, i;
+    int16_t x, y;
+
+    if (bytestream2_get_bytes_left(gb) < 6)
+        return;
+
+    bytestream2_skip(gb, 2);
+    t1 = bytestream2_get_le16u(gb);
+    t2 = bytestream2_get_byteu(gb);
+    bytestream2_skip(gb, 1);
+    if (t2 != 1)
+        return;
+    if (t1 == 0) {
+        if (bytestream2_get_bytes_left(gb) < 0x300)
+            return;
+        bytestream2_get_bufferu(gb, ctx->c45tbl1, 0x300);
+        i = 0;
+        while ((bytestream2_get_bytes_left(gb) > 1) && (i < 0x8000)) {
+            uint8_t len = bytestream2_get_byteu(gb);
+            uint8_t val = bytestream2_get_byteu(gb);
+            if ((i + len) > 0x8000)
+                len = 0x8000 - i;
+            memset(ctx->c45tbl2 + i, val, len);
+            i += len;
+        }
+    }
+
+    if (flag)
+        return;
+
+    x = left;
+    y = top;
+    while (bytestream2_get_bytes_left(gb) > 3) {
+        int16_t xd = bytestream2_get_le16u(gb);
+        int8_t yd = bytestream2_get_byteu(gb);
+        x += xd;
+        y += yd;
+        int len = bytestream2_get_byteu(gb);
+        while (len >= 0) {
+            if ((x > 0) && (y > 0) && (x < ctx->width - 1)) {
+                if (y >= ctx->height)
+                    return;
+
+                uint8_t *dst = (uint8_t *)ctx->fbuf + x + y * ctx->pitch;
+                unsigned int c1 = *(dst - 1) * 3;
+                unsigned int c2 = *(dst + 1) * 3;
+                unsigned int r = ctx->c45tbl1[c1 + 0] + ctx->c45tbl1[c2 + 0];
+                unsigned int g = ctx->c45tbl1[c1 + 1] + ctx->c45tbl1[c2 + 1];
+                unsigned int b = ctx->c45tbl1[c1 + 2] + ctx->c45tbl1[c2 + 2];
+                c1 = *(dst - ctx->pitch) * 3;
+                c2 = *(dst + ctx->pitch) * 3;
+                r += ctx->c45tbl1[c1 + 0] + ctx->c45tbl1[c2 + 0];
+                g += ctx->c45tbl1[c1 + 1] + ctx->c45tbl1[c2 + 1];
+                b += ctx->c45tbl1[c1 + 2] + ctx->c45tbl1[c2 + 2];
+                *dst = ctx->c45tbl2[((r << 5) & 0x7c00) | (g & 0x3e0) | (b >> 5)];
+            }
+            x++;
+            len--;
+        }
+        x--;
+    }
+}
+
 static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
                              int xoff, int yoff)
 {
@@ -1964,6 +2031,12 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
     parm2 = bytestream2_get_le16u(gb);
 
     if (w < 1 || h < 1 || w > 640 || h > 480 || left > 640 || top > 480 || left + w <= 0 || top + h <= 0) {
+        /* codec45 frames with data for the 2 tables have nonsensical dimensions */
+        if (codec == 45) {
+            old_codec45(ctx, gb, 0, 0, 1);
+            return 0;
+        }
+
         av_log(ctx->avctx, AV_LOG_WARNING,
                "ignoring invalid fobj dimensions: c%d %d %d @ %d %d\n",
                codec, w, h, left, top);
@@ -1980,7 +2053,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
     if ((w == 640) && (h == 272) && (top == 60) && (codec == 47))
         left = top = 0;
 
-    if (!ctx->have_dimensions) {
+    if (!ctx->have_dimensions && (codec != 45)) {
         int xres, yres;
         if (ctx->subversion < 2) {
             /* Rebel Assault 1: 384x242 internal size */
@@ -2073,7 +2146,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
     case 37:
         return old_codec37(ctx, gb, top, left, w, h); break;
     case 45:
-        return 0;
+        old_codec45(ctx, gb, top, left, 0); break;
     case 47:
         return old_codec47(ctx, gb, top, left, w, h); break;
     case 48:
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-10-30 15:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-30 15:23 [FFmpeg-devel] [PATCH] avcodec/sanm: implement codec45 (PR #20795) Manuel Lauss via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git