[FFmpeg-devel] [PATCH] libavcodec/sanm: implement codec37 subcodec1

Manuel Lauss manuel.lauss at gmail.com
Tue Jan 7 16:46:09 EET 2025


RLE-compressed stream of motion vector indices and a special opcode
to fill a block with data from the source stream.

It is used in the LucasArts "Full Throttle" blink*.san animations.

Signed-off-by: Manuel Lauss <manuel.lauss at gmail.com>
---
 libavcodec/sanm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index a278ef24b1..b6e599c120 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -625,7 +625,7 @@ static int old_codec37(SANMVideoContext *ctx, int top,
                        int left, int width, int height)
 {
     ptrdiff_t stride = ctx->pitch;
-    int i, j, k, t;
+    int i, j, k, l, t;
     uint8_t *dst, *prev;
     int skip_run = 0;
     int compr = bytestream2_get_byte(&ctx->gb);
@@ -665,6 +665,68 @@ static int old_codec37(SANMVideoContext *ctx, int top,
         memset(ctx->frm1, 0, ctx->height * stride);
         memset(ctx->frm2, 0, ctx->height * stride);
         break;
+    case 1:
+        int run = 0;
+        int len = -1;
+        int code = 0;
+        int skip, mx, my;
+
+        for (j = 0; j < height; j += 4) {
+            for (i = 0; i < width; i += 4) {
+                if (len < 0) {
+                    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+                        return AVERROR_INVALIDDATA;
+                    code = bytestream2_get_byte(&ctx->gb);
+                    len = code >> 1;
+                    run = code & 1;
+                    skip = 0;
+                } else {
+                    skip = run;
+                }
+
+                if (!skip) {
+                    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+                        return AVERROR_INVALIDDATA;
+                    code = bytestream2_get_byte(&ctx->gb);
+                    if (code == 0xff) {
+                        len--;
+                        for (k = 0; k < 4; k++) {
+                            for (l = 0; l < 4; l++) {
+                                if (len < 0) {
+                                    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+                                        return AVERROR_INVALIDDATA;
+                                    code = bytestream2_get_byte(&ctx->gb);
+                                    len = code >> 1;
+                                    run = code & 1;
+                                    if (run) {
+                                        if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+                                            return AVERROR_INVALIDDATA;
+                                        code = bytestream2_get_byte(&ctx->gb);
+                                    }
+                                }
+                                if (!run) {
+                                    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+                                            return AVERROR_INVALIDDATA;
+                                        code = bytestream2_get_byte(&ctx->gb);
+                                }
+                                *(dst + i + (k * stride) + l) = code;
+                                len--;
+                            }
+                        }
+                        continue;
+                    }
+                }
+                /* 4x4 block copy from prev with MV */
+                mx = c37_mv[(mvoff * 255 + code) * 2];
+                my = c37_mv[(mvoff * 255 + code) * 2 + 1];
+                codec37_mv(dst + i, prev + i + mx + my * stride,
+                           ctx->height, stride, i + mx, j + my);
+                len--;
+            }
+            dst += stride * 4;
+            prev += stride * 4;
+        }
+        break;
     case 2:
         if (rle_decode(ctx, dst, decoded_size))
             return AVERROR_INVALIDDATA;
-- 
2.47.1



More information about the ffmpeg-devel mailing list