The branch, master has been updated
       via  d058d5db102234d15ee421a23c96a12518aa2faa (commit)
      from  8313dc1120a221962541000ae261c2f1fbc53a9e (commit)


- Log -----------------------------------------------------------------
commit d058d5db102234d15ee421a23c96a12518aa2faa
Author:     Manuel Lauss <[email protected]>
AuthorDate: Thu Oct 30 16:01:10 2025 +0100
Commit:     Lynne <[email protected]>
CommitDate: Tue Nov 4 10:28:57 2025 +0000

    avcodec/sanm: implement codec45
    
    This is a post-processing codec: given delta-x/y coordinates and a run 
length,
    the r/g/b components of the 4 surrounding pixels are summed up, and the 
resulting
    15bit value is used as index into a color quantization table to derive the
    resulting pixel at the center.
    
    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 <[email protected]>

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 742fc1d477..771ecf8246 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,66 @@ 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;
+
+    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;
+
+    while (bytestream2_get_bytes_left(gb) > 3) {
+        left += (int16_t)bytestream2_get_le16u(gb);
+        top += bytestream2_get_byteu(gb);
+        int len = bytestream2_get_byteu(gb);
+        while (len >= 0) {
+            if ((left > 0) && (top > 0) && (left < (ctx->width - 1))) {
+                if (top >= (ctx->height - 1))
+                    return;
+
+                uint8_t *dst = (uint8_t *)ctx->fbuf + left + top * 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)];
+            }
+            left++;
+            len--;
+        }
+        left--;
+    }
+}
+
 static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
                              int xoff, int yoff)
 {
@@ -1964,6 +2026,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 +2048,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 +2141,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:

-----------------------------------------------------------------------

Summary of changes:
 libavcodec/sanm.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 70 insertions(+), 2 deletions(-)


hooks/post-receive
-- 

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

Reply via email to