[FFmpeg-devel] [PATCH] sanm.c: Implement codec21.

Reimar Döffinger Reimar.Doeffinger at gmx.de
Sat Apr 2 14:29:46 CEST 2016


Used for cockpit in
http://samples.mplayerhq.hu/game-formats/la-san/rebelassault/L8PLAY.ANM

Signed-off-by: Reimar Döffinger <Reimar.Doeffinger at gmx.de>
---
 libavcodec/sanm.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 6aeaa2c..277949e 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -602,6 +602,43 @@ static int old_codec1(SANMVideoContext *ctx, int top,
     return 0;
 }
 
+static int old_codec21(SANMVideoContext *ctx, int top,
+                      int left, int width, int height)
+{
+    uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
+    int i, len, end;
+
+    for (i = 0; i < height; i++) {
+        int pos = 0;
+        if (bytestream2_get_bytes_left(&ctx->gb) < 4)
+            return AVERROR_INVALIDDATA;
+
+        bytestream2_skip(&ctx->gb, 2); // 00 01 in the files tested
+        end = bytestream2_tell(&ctx->gb);
+        len = bytestream2_get_le16u(&ctx->gb);
+        end += len;
+
+        while (bytestream2_tell(&ctx->gb) < end) {
+            int count;
+            if (bytestream2_get_bytes_left(&ctx->gb) < 4)
+                return AVERROR_INVALIDDATA;
+
+            pos += bytestream2_get_le16u(&ctx->gb);
+            count = bytestream2_get_le16u(&ctx->gb) + 1;
+            if (pos + count > width)
+                return AVERROR_INVALIDDATA;
+            if (bytestream2_get_bytes_left(&ctx->gb) < count)
+                return AVERROR_INVALIDDATA;
+            bytestream2_get_bufferu(&ctx->gb, dst + pos, count);
+            pos += count;
+        }
+        dst += ctx->pitch;
+    }
+    ctx->rotate_code = 0;
+
+    return 0;
+}
+
 static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
                               int height, int stride, int x, int y)
 {
@@ -1125,6 +1162,10 @@ static int process_frame_obj(SANMVideoContext *ctx)
         return AVERROR_INVALIDDATA;
     }
 
+    // ignore negative values (padding?)
+    if (left & 0x8000) left = 0;
+    if (top & 0x8000) top = 0;
+
     if (ctx->width < left + w || ctx->height < top + h) {
         int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
                                     FFMAX(top + h, ctx->height));
@@ -1137,7 +1178,7 @@ static int process_frame_obj(SANMVideoContext *ctx)
             return AVERROR(ENOMEM);
         }
     }
-    bytestream2_skip(&ctx->gb, 4);
+    bytestream2_skip(&ctx->gb, codec == 21 ? 2 : 4);
 
     switch (codec) {
     case 1:
@@ -1147,6 +1188,8 @@ static int process_frame_obj(SANMVideoContext *ctx)
         ctx->prev_codec = codec;
         return old_codec1(ctx, top, left, w, h);
         break;
+    case 21:
+        return old_codec21(ctx, top, left, w, h);
     case 37:
         if (ctx->prev_codec == 1) FFSWAP(uint16_t*, ctx->frm0, ctx->frm1);
         ctx->prev_codec = codec;
-- 
2.7.0



More information about the ffmpeg-devel mailing list