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 1/9] avcodec/sanm: codec37: reimplement comp4
@ 2025-03-11 15:03 Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 2/9] avcodec/sanm: better frame size detection for old codecs Manuel Lauss
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

Compression 4 code 0 means copy from delta buffer without mv,
AND start of a skip run.  This change gets rid of the extra case
and column index manipulation and implements this the same way it
is implemented in the original game exe, i.e. as a special case
after mv copy.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index a4f0a28c7c..cbf78f33b9 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -760,16 +760,14 @@ static int old_codec37(SANMVideoContext *ctx, int top,
                     t = bytestream2_get_byteu(&ctx->gb);
                     for (k = 0; k < 4; k++)
                         memset(dst + i + k * stride, t, 4);
-               } else if ((compr == 4) && (code == 0)) {
-                    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
-                        return AVERROR_INVALIDDATA;
-                    skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
-                    i -= 4;
                } else {
                     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);
+
+                    if ((compr == 4) && (code == 0))
+                        skip_run = bytestream2_get_byteu(&ctx->gb);
                 }
             }
             dst  += stride * 4;
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 2/9] avcodec/sanm: better frame size detection for old codecs
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 3/9] avcodec/sanm: disable left/top for fullscreen codecs Manuel Lauss
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

The size of the video frame (FOBJ) of the old codecs (ANIMv0/1/2) can
very reliably be determined:
- ANIMv0/1 (=Rebel Assault 1) uses a 384x242 internal buffer for
  everything.  The codec parameters only describe the size and offset
  of the specific FOBJ on that buffer.
- ANIMv2 titles usually use one of the fullscreen codecs (37/47/48)
  as first FOBJ, and their dimensions can generally be trusted.
- RA2 uses 424x260 as internal buffer, use that if encountered.
- ignore sizes smaller than 2x2 or larger than 800x600 as those
  don't exist in LucasArts titles.
- some videos have an initial fobj with either 1x1 or -1x-1
  pixels in size, ignore them with a warning (Full Throttle
  and the Rebel Assault 2 xxRETRY.SAN videos). Ignoring them
  does not impact the final image.

Once known/valid dimensions have been discovered, use them and
don't change them for subsequent FOBJs, rather clamp the large frame
to the determined dimensions (The Dig's sq1.san).

Tested with RA1, RA2, Full Throttle, Dig, Outlaws, SotE and MotS
videos.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index cbf78f33b9..ca345bc61a 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -264,7 +264,7 @@ typedef struct SANMVideoContext {
     AVCodecContext *avctx;
     GetByteContext gb;
 
-    int version, subversion;
+    int version, subversion, have_dimensions;
     uint32_t pal[PALETTE_SIZE];
     int16_t delta_pal[PALETTE_DELTA];
 
@@ -1241,21 +1241,52 @@ static int process_frame_obj(SANMVideoContext *ctx)
     uint16_t w     = bytestream2_get_le16u(&ctx->gb);
     uint16_t h     = bytestream2_get_le16u(&ctx->gb);
 
-    if (!w || !h) {
-        av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
-        return AVERROR_INVALIDDATA;
+    if (w < 2 || h < 2 || w > 800 || h > 600) {
+        av_log(ctx->avctx, AV_LOG_WARNING, "ignoring invalid fobj dimensions.\n");
+        return 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));
-        if (ret < 0)
-            return ret;
-        init_sizes(ctx, FFMAX(left + w, ctx->width),
-                   FFMAX(top + h, ctx->height));
-        if (init_buffers(ctx)) {
-            av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
-            return AVERROR(ENOMEM);
+    if (!ctx->have_dimensions) {
+        int xres, yres;
+        if (ctx->subversion < 2) {
+            /* Rebel Assault 1: 384x242 internal size */
+            xres = 384;
+            yres = 242;
+            ctx->have_dimensions = 1;
+        } else if (codec == 37 || codec == 47 || codec == 48) {
+            /* these codecs work on full frames, trust their dimensions */
+            xres = w;
+            yres = h;
+            ctx->have_dimensions = 1;
+        } else {
+            /* Rebel Assault 2: 424x260 internal size */
+            if (((left + w) == 424) && ((top + h) == 260))
+                ctx->have_dimensions = 1;
+
+            xres = FFMAX(left + w, ctx->width);
+            yres = FFMAX(top + h, ctx->height);
+        }
+
+        if (ctx->width < xres || ctx->height < yres) {
+            int ret = ff_set_dimensions(ctx->avctx, xres, yres);
+            if (ret < 0)
+                return ret;
+            init_sizes(ctx, xres, yres);
+            if (init_buffers(ctx)) {
+                av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
+                return AVERROR(ENOMEM);
+            }
+        }
+    } else {
+        if ((left + w > ctx->width) || (top + h > ctx->height)) {
+            /* correct unexpected overly large frames.
+             * this happens for instance with The Dig's sq1.san video: it has
+             * a few (all black) 640x480 frames halfway in.
+             */
+            left = top = 0;
+            w = ctx->width;
+            h = ctx->height;
+            av_log(ctx->avctx, AV_LOG_WARNING, "resizing too large fobj.\n");
         }
     }
     bytestream2_skip(&ctx->gb, 4);
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 3/9] avcodec/sanm: disable left/top for fullscreen codecs
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 2/9] avcodec/sanm: better frame size detection for old codecs Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 4/9] avcodec/sanm: fix codec3 Manuel Lauss
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

The block-based codecs 37/47/48 work on the full frame, and there's no
existing LucasArts game video that uses left/top offsets for these,
as it doesn't make sense. Ignore the left/top parameters for these codecs.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
Well, except for SotE, which uses "top" to move the widescreen video
to the center of the 4:3 game window, but ffmpeg doesn't need do do
that.

 libavcodec/sanm.c | 40 +++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index ca345bc61a..b2923515b1 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -621,8 +621,7 @@ static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
     }
 }
 
-static int old_codec37(SANMVideoContext *ctx, int top,
-                       int left, int width, int height)
+static int old_codec37(SANMVideoContext *ctx, int width, int height)
 {
     int i, j, k, l, t, run, len, code, skip, mx, my;
     ptrdiff_t stride = ctx->pitch;
@@ -638,8 +637,8 @@ static int old_codec37(SANMVideoContext *ctx, int top,
     flags = bytestream2_get_byte(&ctx->gb);
     bytestream2_skip(&ctx->gb, 3);
 
-    if (decoded_size > ctx->height * stride - left - top * stride) {
-        decoded_size = ctx->height * stride - left - top * stride;
+    if (decoded_size > ctx->height * stride) {
+        decoded_size = ctx->height * stride;
         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
     }
 
@@ -649,8 +648,8 @@ static int old_codec37(SANMVideoContext *ctx, int top,
         FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
     }
 
-    dst  = ((uint8_t*)ctx->frm1) + left + top * stride;
-    prev = ((uint8_t*)ctx->frm2) + left + top * stride;
+    dst  = ((uint8_t*)ctx->frm1);
+    prev = ((uint8_t*)ctx->frm2);
 
     if (mvoff > 2) {
         av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
@@ -923,15 +922,14 @@ static void codec47_comp1(SANMVideoContext *ctx, uint8_t *dst_in, int width,
     }
 }
 
-static int old_codec47(SANMVideoContext *ctx, int top,
-                       int left, int width, int height)
+static int old_codec47(SANMVideoContext *ctx, int width, int height)
 {
     uint32_t decoded_size;
     int i, j;
     ptrdiff_t stride = ctx->pitch;
-    uint8_t *dst   = (uint8_t *)ctx->frm0 + left + top * stride;
-    uint8_t *prev1 = (uint8_t *)ctx->frm1 + left + top * stride;
-    uint8_t *prev2 = (uint8_t *)ctx->frm2 + left + top * stride;
+    uint8_t *dst   = (uint8_t *)ctx->frm0;
+    uint8_t *prev1 = (uint8_t *)ctx->frm1;
+    uint8_t *prev2 = (uint8_t *)ctx->frm2;
     uint8_t auxcol[2];
     int tbl_pos = bytestream2_tell(&ctx->gb);
     int seq     = bytestream2_get_le16(&ctx->gb);
@@ -945,8 +943,8 @@ static int old_codec47(SANMVideoContext *ctx, int top,
     decoded_size = bytestream2_get_le32(&ctx->gb);
     bytestream2_skip(&ctx->gb, 8);
 
-    if (decoded_size > ctx->height * stride - left - top * stride) {
-        decoded_size = ctx->height * stride - left - top * stride;
+    if (decoded_size > ctx->height * stride) {
+        decoded_size = ctx->height * stride;
         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
     }
 
@@ -957,8 +955,8 @@ static int old_codec47(SANMVideoContext *ctx, int top,
     }
     if (!seq) {
         ctx->prev_seq = -1;
-        memset(prev1, auxcol[0], (ctx->height - top) * stride);
-        memset(prev2, auxcol[1], (ctx->height - top) * stride);
+        memset(prev1, auxcol[0], ctx->height * stride);
+        memset(prev2, auxcol[1], ctx->height * stride);
     }
 
     switch (compr) {
@@ -1289,6 +1287,14 @@ static int process_frame_obj(SANMVideoContext *ctx)
             av_log(ctx->avctx, AV_LOG_WARNING, "resizing too large fobj.\n");
         }
     }
+
+    if (codec == 37 || codec == 47 || codec == 48) {
+        /* these codecs work on full frames.  In SotE only, "top" is used
+         * to create a black bar at the top to center the  video inside
+         * the 640x480 game window.  We don't need/want that here.
+         */
+        left = top = 0;
+    }
     bytestream2_skip(&ctx->gb, 4);
 
     switch (codec) {
@@ -1296,9 +1302,9 @@ static int process_frame_obj(SANMVideoContext *ctx)
     case 3:
         return old_codec1(ctx, top, left, w, h);
     case 37:
-        return old_codec37(ctx, top, left, w, h);
+        return old_codec37(ctx, w, h);
     case 47:
-        return old_codec47(ctx, top, left, w, h);
+        return old_codec47(ctx, w, h);
     case 48:
         return old_codec48(ctx, w, h);
     default:
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 4/9] avcodec/sanm: fix codec3
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 2/9] avcodec/sanm: better frame size detection for old codecs Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 3/9] avcodec/sanm: disable left/top for fullscreen codecs Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 5/9] avcodec/sanm: FOBJ left/top are signed values Manuel Lauss
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

codec3 is codec1 which writes zero values instead of skipping them.
This fixes a lot of RA1 videos.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index b2923515b1..a512810987 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -556,7 +556,7 @@ static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
 }
 
 static int old_codec1(SANMVideoContext *ctx, int top,
-                      int left, int width, int height)
+                      int left, int width, int height, int opaque)
 {
     uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
     int i, j, len, flag, code, val, pos, end;
@@ -581,7 +581,7 @@ static int old_codec1(SANMVideoContext *ctx, int top,
                 return AVERROR_INVALIDDATA;
             if (flag) {
                 val = bytestream2_get_byteu(&ctx->gb);
-                if (val)
+                if (val || opaque)
                     memset(dst + pos, val, code);
                 pos += code;
             } else {
@@ -589,7 +589,7 @@ static int old_codec1(SANMVideoContext *ctx, int top,
                     return AVERROR_INVALIDDATA;
                 for (j = 0; j < code; j++) {
                     val = bytestream2_get_byteu(&ctx->gb);
-                    if (val)
+                    if (val || opaque)
                         dst[pos] = val;
                     pos++;
                 }
@@ -1300,7 +1300,7 @@ static int process_frame_obj(SANMVideoContext *ctx)
     switch (codec) {
     case 1:
     case 3:
-        return old_codec1(ctx, top, left, w, h);
+        return old_codec1(ctx, top, left, w, h, codec != 1);
     case 37:
         return old_codec37(ctx, w, h);
     case 47:
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 5/9] avcodec/sanm: FOBJ left/top are signed values
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
                   ` (2 preceding siblings ...)
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 4/9] avcodec/sanm: fix codec3 Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 6/9] avcodec/sanm: misc fixes Manuel Lauss
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

The left/top parameters of a FOBJ are signed values.  Adjust
codec1 code accordingly to not draw outside the buffer area.
Rebel Assault 1 makes heavy use of this.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index a512810987..310b1a429b 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -558,18 +558,18 @@ static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
 static int old_codec1(SANMVideoContext *ctx, int top,
                       int left, int width, int height, int opaque)
 {
-    uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
-    int i, j, len, flag, code, val, pos, end;
+    int i, j, len, flag, code, val, end, pxoff;
+    const int maxpxo = ctx->height * ctx->pitch;
+    uint8_t *dst = (uint8_t *)ctx->frm0;
 
     for (i = 0; i < height; i++) {
-        pos = 0;
-
         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
             return AVERROR_INVALIDDATA;
 
         len = bytestream2_get_le16u(&ctx->gb);
         end = bytestream2_tell(&ctx->gb) + len;
 
+        pxoff = left + ((top + i) * ctx->pitch);
         while (bytestream2_tell(&ctx->gb) < end) {
             if (bytestream2_get_bytes_left(&ctx->gb) < 2)
                 return AVERROR_INVALIDDATA;
@@ -577,25 +577,27 @@ static int old_codec1(SANMVideoContext *ctx, int top,
             code = bytestream2_get_byteu(&ctx->gb);
             flag = code & 1;
             code = (code >> 1) + 1;
-            if (pos + code > width)
-                return AVERROR_INVALIDDATA;
             if (flag) {
                 val = bytestream2_get_byteu(&ctx->gb);
-                if (val || opaque)
-                    memset(dst + pos, val, code);
-                pos += code;
+                if (val || opaque) {
+                    for (j = 0; j < code; j++) {
+                        if (pxoff >= 0 && pxoff < maxpxo)
+                            *(dst + pxoff) = val;
+                        pxoff++;
+                    }
+                } else
+                    pxoff += code;
             } else {
                 if (bytestream2_get_bytes_left(&ctx->gb) < code)
                     return AVERROR_INVALIDDATA;
                 for (j = 0; j < code; j++) {
                     val = bytestream2_get_byteu(&ctx->gb);
-                    if (val || opaque)
-                        dst[pos] = val;
-                    pos++;
+                    if ((pxoff >= 0 && pxoff < maxpxo) && (val || opaque))
+                        *(dst + pxoff) = val;
+                    pxoff++;
                 }
             }
         }
-        dst += ctx->pitch;
     }
     ctx->rotate_code = 0;
 
@@ -1234,8 +1236,8 @@ static int old_codec48(SANMVideoContext *ctx, int width, int height)
 static int process_frame_obj(SANMVideoContext *ctx)
 {
     uint16_t codec = bytestream2_get_le16u(&ctx->gb);
-    uint16_t left  = bytestream2_get_le16u(&ctx->gb);
-    uint16_t top   = bytestream2_get_le16u(&ctx->gb);
+    int16_t  left  = bytestream2_get_le16u(&ctx->gb);
+    int16_t  top   = bytestream2_get_le16u(&ctx->gb);
     uint16_t w     = bytestream2_get_le16u(&ctx->gb);
     uint16_t h     = bytestream2_get_le16u(&ctx->gb);
 
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 6/9] avcodec/sanm: misc fixes
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
                   ` (3 preceding siblings ...)
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 5/9] avcodec/sanm: FOBJ left/top are signed values Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 7/9] avcodec/sanm: codec2 decoder Manuel Lauss
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

- clear the front buffer with color 0 when a new frame starts.
  Fixes a lot of Rebel Assault 1 videos and Rebel Assault 2 space
  scenes (e.g. 08PLAY.SAN which consists only of codec1+21 objects
  which only ever touch parts of the buffer).
- for ANIMv1 (Rebel Assault 1): set palette index 0 to all zeroes.
  This fixes a lot of unwanted colors in e.g L1HANGAR.ANM, L2INTRO.ANM,
  a space scenes.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 310b1a429b..efed31b70c 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -1350,6 +1350,8 @@ static int process_xpal(SANMVideoContext *ctx, int size)
         if (size >= PALETTE_DELTA * 2 + 4 + PALETTE_SIZE * 3) {
             for (i = 0; i < PALETTE_SIZE; i++)
                 ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
+            if (ctx->subversion < 2)
+                ctx->pal[0] = 0;
         }
     }
     return 0;
@@ -1765,6 +1767,10 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     if (!ctx->version) {
         int to_store = 0;
 
+        /* clear the front buffer */
+        if (ctx->frm0_size)
+            memset(ctx->frm0, 0, ctx->frm0_size);
+
         while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
             uint32_t sig, size;
             int pos;
@@ -1786,6 +1792,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
                 }
                 for (i = 0; i < PALETTE_SIZE; i++)
                     ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
+                if (ctx->subversion < 2)
+                    ctx->pal[0] = 0;
                 break;
             case MKBETAG('F', 'O', 'B', 'J'):
                 if (size < 16)
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 7/9] avcodec/sanm: codec2 decoder
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
                   ` (4 preceding siblings ...)
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 6/9] avcodec/sanm: misc fixes Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 8/9] avcodec/sanm: codec23 decoder Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 9/9] avcodec/sanm: codec21 decoder Manuel Lauss
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

this codec consists of 4 byte packets: 2bytes delta-x, 1 byte delta-y
and 1 byte color to put at that spot.
Used in Rebel Assault 1 only.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index efed31b70c..8c0b76aed6 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -604,6 +604,24 @@ static int old_codec1(SANMVideoContext *ctx, int top,
     return 0;
 }
 
+static int old_codec2(SANMVideoContext *ctx, int top,
+                      int left, int width, int height)
+{
+    uint8_t *dst = (uint8_t *)ctx->frm0, col;
+    int16_t xpos = left, ypos = top;
+
+    while (bytestream2_get_bytes_left(&ctx->gb) > 3) {
+        xpos += bytestream2_get_le16u(&ctx->gb);
+        ypos += bytestream2_get_byteu(&ctx->gb);
+        col = bytestream2_get_byteu(&ctx->gb);
+        if (xpos >= 0 && ypos >= 0 &&
+            xpos < ctx->width && ypos < ctx->height) {
+                *(dst + xpos + ypos * ctx->pitch) = col;
+        }
+    }
+    return 0;
+}
+
 static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
                               int height, int stride, int x, int y)
 {
@@ -1303,6 +1321,8 @@ static int process_frame_obj(SANMVideoContext *ctx)
     case 1:
     case 3:
         return old_codec1(ctx, top, left, w, h, codec != 1);
+    case 2:
+        return old_codec2(ctx, top, left, w, h);
     case 37:
         return old_codec37(ctx, w, h);
     case 47:
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 8/9] avcodec/sanm: codec23 decoder
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
                   ` (5 preceding siblings ...)
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 7/9] avcodec/sanm: codec2 decoder Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 9/9] avcodec/sanm: codec21 decoder Manuel Lauss
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

This codec alternatingly skips and changes existing pixels.
A second 16bit parameter in the FOBJ header indicates how to do
the pixel changes: either by specifying a LUT in the codec datastream
or by adding a constant value to the pixel.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 8c0b76aed6..dbd78de0bc 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -292,6 +292,7 @@ typedef struct SANMVideoContext {
     int8_t p4x4glyphs[NGLYPHS][16];
     int8_t p8x8glyphs[NGLYPHS][64];
     uint8_t c47itbl[0x10000];
+    uint8_t c23lut[256];
 } SANMVideoContext;
 
 typedef struct SANMFrameHeader {
@@ -555,6 +556,62 @@ static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
     return 0;
 }
 
+static int old_codec23(SANMVideoContext *ctx, int top, int left, int width,
+                       int height, uint8_t param, uint16_t param2)
+{
+    const uint32_t maxpxo = ctx->height * ctx->pitch;
+    uint8_t *dst, lut[256], c;
+    int i, j, k, pc, sk;
+    int32_t pxoff;
+
+    if (ctx->subversion < 2) {
+        /* Rebel Assault 1: constant offset + 0xd0 */
+        for (i = 0; i < 256; i++)
+            lut[i] = (i + param + 0xd0) & 0xff;
+    } else if (param2 == 256) {
+        if (bytestream2_get_bytes_left(&ctx->gb) < 256)
+            return AVERROR_INVALIDDATA;
+        bytestream2_get_bufferu(&ctx->gb, ctx->c23lut, 256);
+    } else if (param2 < 256) {
+        for (i = 0; i < 256; i++)
+            lut[i] = (i + param2) & 0xff;
+    } else {
+        memcpy(lut, ctx->c23lut, 256);
+    }
+    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+        return 0;  /* some c23 frames just set up the LUT */
+
+    dst = (uint8_t *)ctx->frm0;
+    for (i = 0; i < height; i++) {
+        if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+            return 0;
+        pxoff = left + ((top + i) * ctx->pitch);
+        k = bytestream2_get_le16u(&ctx->gb);
+        sk = 1;
+        pc = 0;
+        while (k > 0 && pc <= width) {
+            if (bytestream2_get_bytes_left(&ctx->gb) < 1)
+                return AVERROR_INVALIDDATA;
+            j = bytestream2_get_byteu(&ctx->gb);
+            if (sk) {
+                pxoff += j;
+                pc += j;
+            } else {
+                while (j--) {
+                    if (pxoff >=0 && pxoff < maxpxo) {
+                        c = *(dst + pxoff);
+                        *(dst + pxoff) = lut[c];
+                    }
+                    pxoff++;
+                    pc++;
+                }
+            }
+            sk ^= 1;
+        }
+    }
+    return 0;
+}
+
 static int old_codec1(SANMVideoContext *ctx, int top,
                       int left, int width, int height, int opaque)
 {
@@ -1253,11 +1310,15 @@ static int old_codec48(SANMVideoContext *ctx, int width, int height)
 
 static int process_frame_obj(SANMVideoContext *ctx)
 {
-    uint16_t codec = bytestream2_get_le16u(&ctx->gb);
+    uint16_t parm2;
+    uint8_t  codec = bytestream2_get_byteu(&ctx->gb);
+    uint8_t  param = bytestream2_get_byteu(&ctx->gb);
     int16_t  left  = bytestream2_get_le16u(&ctx->gb);
     int16_t  top   = bytestream2_get_le16u(&ctx->gb);
     uint16_t w     = bytestream2_get_le16u(&ctx->gb);
     uint16_t h     = bytestream2_get_le16u(&ctx->gb);
+    bytestream2_skip(&ctx->gb, 2);
+    parm2 = bytestream2_get_le16u(&ctx->gb);
 
     if (w < 2 || h < 2 || w > 800 || h > 600) {
         av_log(ctx->avctx, AV_LOG_WARNING, "ignoring invalid fobj dimensions.\n");
@@ -1315,7 +1376,6 @@ static int process_frame_obj(SANMVideoContext *ctx)
          */
         left = top = 0;
     }
-    bytestream2_skip(&ctx->gb, 4);
 
     switch (codec) {
     case 1:
@@ -1323,6 +1383,8 @@ static int process_frame_obj(SANMVideoContext *ctx)
         return old_codec1(ctx, top, left, w, h, codec != 1);
     case 2:
         return old_codec2(ctx, top, left, w, h);
+    case 23:
+        return old_codec23(ctx, top, left, w, h, param, parm2);
     case 37:
         return old_codec37(ctx, w, h);
     case 47:
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [FFmpeg-devel] [PATCH 9/9] avcodec/sanm: codec21 decoder
  2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
                   ` (6 preceding siblings ...)
  2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 8/9] avcodec/sanm: codec23 decoder Manuel Lauss
@ 2025-03-11 15:03 ` Manuel Lauss
  7 siblings, 0 replies; 9+ messages in thread
From: Manuel Lauss @ 2025-03-11 15:03 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Manuel Lauss

similar to codec23, this one alternatingly skips and writes bytes.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index dbd78de0bc..edce76c7f4 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -612,6 +612,49 @@ static int old_codec23(SANMVideoContext *ctx, int top, int left, int width,
     return 0;
 }
 
+static int old_codec21(SANMVideoContext *ctx, int top, int left, int width,
+                       int height)
+{
+    const uint32_t maxpxo = ctx->height * ctx->pitch;
+    uint8_t *dst = (uint8_t *)ctx->frm0, c;
+    int i, j, k, pc, sk, pxoff;
+
+    dst = (uint8_t *)ctx->frm0;
+    for (i = 0; i < height; i++) {
+        if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+            return 0;
+        pxoff = left + ((top + i) * ctx->pitch);
+        k = bytestream2_get_le16u(&ctx->gb);
+        sk = 1;
+        pc = 0;
+        while (k > 0 && pc <= width) {
+            if (bytestream2_get_bytes_left(&ctx->gb) < 2)
+                return AVERROR_INVALIDDATA;
+            j = bytestream2_get_le16u(&ctx->gb);
+            k -= 2;
+            if (sk) {
+                pxoff += j;
+                pc += j;
+            } else {
+                if (bytestream2_get_bytes_left(&ctx->gb) < (j + 1))
+                    return AVERROR_INVALIDDATA;
+                do {
+                    c = bytestream2_get_byteu(&ctx->gb);
+                    if (pxoff >=0 && pxoff < maxpxo) {
+                        *(dst + pxoff) = c;
+                    }
+                    pxoff++;
+                    pc++;
+                    j--;
+                    k--;
+                } while (j > -1);
+            }
+            sk ^= 1;
+        }
+    }
+    return 0;
+}
+
 static int old_codec1(SANMVideoContext *ctx, int top,
                       int left, int width, int height, int opaque)
 {
@@ -1383,6 +1426,8 @@ static int process_frame_obj(SANMVideoContext *ctx)
         return old_codec1(ctx, top, left, w, h, codec != 1);
     case 2:
         return old_codec2(ctx, top, left, w, h);
+    case 21:
+        return old_codec21(ctx, top, left, w, h);
     case 23:
         return old_codec23(ctx, top, left, w, h, param, parm2);
     case 37:
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-03-11 15:05 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-03-11 15:03 [FFmpeg-devel] [PATCH 1/9] avcodec/sanm: codec37: reimplement comp4 Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 2/9] avcodec/sanm: better frame size detection for old codecs Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 3/9] avcodec/sanm: disable left/top for fullscreen codecs Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 4/9] avcodec/sanm: fix codec3 Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 5/9] avcodec/sanm: FOBJ left/top are signed values Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 6/9] avcodec/sanm: misc fixes Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 7/9] avcodec/sanm: codec2 decoder Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 8/9] avcodec/sanm: codec23 decoder Manuel Lauss
2025-03-11 15:03 ` [FFmpeg-devel] [PATCH 9/9] avcodec/sanm: codec21 decoder Manuel Lauss

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