The title "StarWars - Making Magic" consists of 640x480 codec3
frames, with a 320x240 codec48 video put on top of that at
random x/y offsets.

To support this, a new default buffer "fbuf", which holds the final
image to be presented, is added, since codec37/47/48 need their buffers
need to be private to themselves.  The decoded result is then copied to
the fbuf, honoring the x/y offsets if required.

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

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 63f5c2cc7f..0af0527ce6 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -274,9 +274,9 @@ typedef struct SANMVideoContext {
     int prev_seq;
 
     AVFrame *frame;
-    uint16_t *frm0, *frm1, *frm2;
+    uint16_t *fbuf, *frm0, *frm1, *frm2;
     uint8_t *stored_frame;
-    uint32_t frm0_size, frm1_size, frm2_size;
+    uint32_t fbuf_size, frm0_size, frm1_size, frm2_size;
     uint32_t stored_frame_size;
 
     uint8_t *rle_buf;
@@ -453,6 +453,7 @@ static void init_sizes(SANMVideoContext *ctx, int width, 
int height)
 
 static void destroy_buffers(SANMVideoContext *ctx)
 {
+    av_freep(&ctx->fbuf);
     av_freep(&ctx->frm0);
     av_freep(&ctx->frm1);
     av_freep(&ctx->frm2);
@@ -466,6 +467,7 @@ static void destroy_buffers(SANMVideoContext *ctx)
 
 static av_cold int init_buffers(SANMVideoContext *ctx)
 {
+    av_fast_padded_mallocz(&ctx->fbuf, &ctx->fbuf_size, ctx->buf_size);
     av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
     av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
     av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
@@ -674,7 +676,7 @@ static int old_codec4(SANMVideoContext *ctx, GetByteContext 
*gb, int top, int le
 {
     const uint16_t p = ctx->pitch;
     const uint32_t maxpxo = ctx->height * p;
-    uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->frm0;
+    uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->fbuf;
     int i, j, k, l, bit, ret;
     int32_t pxoff, pxo2;
 
@@ -805,7 +807,7 @@ static int old_codec23(SANMVideoContext *ctx, 
GetByteContext *gb, int top, int l
     if (bytestream2_get_bytes_left(gb) < 1)
         return 0;  /* some c23 frames just set up the LUT */
 
-    dst = (uint8_t *)ctx->frm0;
+    dst = (uint8_t *)ctx->fbuf;
     for (i = 0; i < height; i++) {
         if (bytestream2_get_bytes_left(gb) < 2)
             return 0;
@@ -840,10 +842,10 @@ static int old_codec21(SANMVideoContext *ctx, 
GetByteContext *gb, int top, int l
                        int width, int height)
 {
     const uint32_t maxpxo = ctx->height * ctx->pitch;
-    uint8_t *dst = (uint8_t *)ctx->frm0, c;
+    uint8_t *dst = (uint8_t *)ctx->fbuf, c;
     int i, j, k, pc, sk, pxoff;
 
-    dst = (uint8_t *)ctx->frm0;
+    dst = (uint8_t *)ctx->fbuf;
     for (i = 0; i < height; i++) {
         if (bytestream2_get_bytes_left(gb) < 2)
             return 0;
@@ -884,7 +886,7 @@ static int old_codec1(SANMVideoContext *ctx, GetByteContext 
*gb, int top,
 {
     int i, j, len, flag, code, val, end, pxoff;
     const int maxpxo = ctx->height * ctx->pitch;
-    uint8_t *dst = (uint8_t *)ctx->frm0;
+    uint8_t *dst = (uint8_t *)ctx->fbuf;
 
     for (i = 0; i < height; i++) {
         if (bytestream2_get_bytes_left(gb) < 2)
@@ -932,7 +934,7 @@ static int old_codec1(SANMVideoContext *ctx, GetByteContext 
*gb, int top,
 static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top,
                       int left, int width, int height)
 {
-    uint8_t *dst = (uint8_t *)ctx->frm0, col;
+    uint8_t *dst = (uint8_t *)ctx->fbuf, col;
     int16_t xpos = left, ypos = top;
 
     while (bytestream2_get_bytes_left(gb) > 3) {
@@ -949,7 +951,7 @@ static int old_codec2(SANMVideoContext *ctx, GetByteContext 
*gb, int top,
 
 static int old_codec20(SANMVideoContext *ctx, int w, int h)
 {
-    uint8_t *dst = (uint8_t *)ctx->frm0;
+    uint8_t *dst = (uint8_t *)ctx->fbuf;
 
     if (bytestream2_get_bytes_left(&ctx->gb) < w * h)
         return AVERROR_INVALIDDATA;
@@ -1008,10 +1010,10 @@ static int old_codec37(SANMVideoContext *ctx, int 
width, int height)
     ctx->rotate_code = 0;
 
     if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) {
-        FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
+        FFSWAP(uint16_t*, ctx->frm0, ctx->frm2);
     }
 
-    dst  = ((uint8_t*)ctx->frm1);
+    dst  = ((uint8_t*)ctx->frm0);
     prev = ((uint8_t*)ctx->frm2);
 
     if (mvoff > 2) {
@@ -1145,7 +1147,6 @@ static int old_codec37(SANMVideoContext *ctx, int width, 
int height)
         return AVERROR_PATCHWELCOME;
     }
 
-    memcpy(ctx->frm0, ctx->frm1, ctx->buf_size);
     return 0;
 }
 
@@ -1603,7 +1604,7 @@ static int process_frame_obj(SANMVideoContext *ctx, 
GetByteContext *gb)
     uint16_t w, h, parm2;
     uint8_t codec, param;
     int16_t left, top;
-    int fsc, sote;
+    int fsc, sote, ret;
 
     codec = bytestream2_get_byteu(gb);
     param = bytestream2_get_byteu(gb);
@@ -1687,12 +1688,12 @@ static int process_frame_obj(SANMVideoContext *ctx, 
GetByteContext *gb)
     }
 
     /* on first FOBJ, when the codec is not one of the
-     * full-buffer codecs (37/47/48), frm0 needs to be cleared.
+     * full-buffer codecs (37/47/48), fbuf needs to be cleared.
      */
     if (ctx->first_fob) {
         ctx->first_fob = 0;
         if (!fsc)
-            memset(ctx->frm0, 0, ctx->frm0_size);
+            memset(ctx->fbuf, 0, ctx->frm0_size);
     }
 
     switch (codec) {
@@ -1713,18 +1714,38 @@ static int process_frame_obj(SANMVideoContext *ctx, 
GetByteContext *gb)
     case 23:
         return old_codec23(ctx, gb, top, left, w, h, param, parm2);
     case 37:
-        return old_codec37(ctx, w, h);
+        ret = old_codec37(ctx, w, h); break;
     case 45:
         return 0;
     case 47:
-        return old_codec47(ctx, w, h);
+        ret = old_codec47(ctx, w, h); break;
     case 48:
-        return old_codec48(ctx, w, h);
+        ret = old_codec48(ctx, w, h); break;
     default:
         avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
         ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT;
         return 0;
     }
+    if (ret)
+        return ret;
+
+    /* copy the codec37/47/48 result to main buffer */
+    if ((w == ctx->width) && (h == ctx->height)) {
+        memcpy(ctx->fbuf, ctx->frm0, ctx->fbuf_size);
+    } else {
+        uint8_t *dst = (uint8_t *)ctx->fbuf + left + top * ctx->pitch;
+        const uint8_t *src = (uint8_t *)ctx->frm0;
+        int cw = FFMIN(w, ctx->width - left);
+        int ch = FFMIN(h, ctx->height - top);
+        if ((cw > 0) && (ch > 0) && (left > 0) && (top > 0)) {
+            for (int i = 0; i < ch; i++) {
+                memcpy(dst, src, cw);
+                dst += ctx->pitch;
+                src += w;
+            }
+        }
+    }
+    return 0;
 }
 
 static int process_ftch(SANMVideoContext *ctx, int size)
@@ -2196,7 +2217,7 @@ static void fill_frame(uint16_t *pbuf, int buf_size, 
uint16_t color)
 static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
 {
     uint8_t *dst;
-    const uint8_t *src = (uint8_t*) ctx->frm0;
+    const uint8_t *src = hdr ? (uint8_t *)ctx->frm0 : (uint8_t *)ctx->fbuf;
     int ret, height = ctx->height;
     ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 
1);
 
@@ -2279,7 +2300,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame 
*frame,
                             ret = AVERROR(ENOMEM);
                         }
                     } else {
-                        memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
+                        memcpy(ctx->stored_frame, ctx->fbuf, ctx->buf_size);
                     }
                 }
                 break;
@@ -2295,7 +2316,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame 
*frame,
                     if (ret = process_ftch(ctx, size))
                         return ret;
                 } else {
-                    memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
+                    memcpy(ctx->fbuf, ctx->stored_frame, ctx->buf_size);
                 }
                 have_img = 1;
                 break;
-- 
2.49.0

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

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

Reply via email to