1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-11-29 05:57:37 +02:00

avcodec/sanm: codec20 left/top offset support

Add left/top offsets and clipping to codec20 (raw images),
use it for the copying of codec37/47/48 images to main buffer.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
This commit is contained in:
Manuel Lauss
2025-10-01 21:45:09 +02:00
parent a108be2ba3
commit 0eb58e40cb

View File

@@ -1031,21 +1031,67 @@ static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top,
return 0;
}
static int old_codec20(SANMVideoContext *ctx, GetByteContext *gb, int w, int h)
static int old_codec20(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
const int w, const int h)
{
uint8_t *dst = (uint8_t *)ctx->fbuf;
int hh = h, ww = w;
if (bytestream2_get_bytes_left(gb) < w * h)
return AVERROR_INVALIDDATA;
if (((left + w) < 0) || (left >= ctx->width) || ((top + h) < 0)
|| (top >= ctx->height) || (w < 1) || (h < 1))
return 0;
if (w == ctx->pitch) {
bytestream2_get_bufferu(gb, dst, w * h);
if (top < 0) {
int ts = -top * w;
if (bytestream2_get_bytes_left(gb) < ts)
return AVERROR_INVALIDDATA;
bytestream2_skip(gb, ts);
hh += top;
top = 0;
}
if (hh < 1)
return 0;
if ((left == 0) && (w == ctx->pitch)) {
int ba = bytestream2_get_bytes_left(gb); /* bytes available */
int bd = w * FFMIN(ctx->height - top, hh); /* bytes drawable */
ba = FFMIN(ba, bd);
if (ba)
bytestream2_get_bufferu(gb, dst + (top * ctx->pitch), ba);
} else {
for (int i = 0; i < h; i++) {
bytestream2_get_bufferu(gb, dst, w);
dst += ctx->pitch;
if ((top + hh) >= ctx->height) {
hh = ctx->height - top;
hh = FFMIN(hh, ctx->height);
}
if (left < 0) {
if (bytestream2_get_bytes_left(gb) < -left)
return AVERROR_INVALIDDATA;
bytestream2_skip(gb, -left);
ww += left;
left = 0;
}
if ((left + ww) >= ctx->width) {
ww = ctx->width - left;
ww = FFMIN(ww, ctx->width);
}
if ((ww > 0) && (hh > 0)) {
int sz = bytestream2_get_bytes_left(gb);
const int d = w - ww;
dst += left + (top * ctx->pitch);
while ((hh--) && (sz >= ww)) {
bytestream2_get_bufferu(gb, dst, ww);
sz -= ww;
dst += ctx->pitch;
if (d > 0) {
int c = FFMIN(d, sz);
bytestream2_skip(gb, c);
sz -= c;
}
}
}
}
return 0;
}
@@ -1838,8 +1884,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
}
}
} else {
if (((w > ctx->width) || (h > ctx->height) || (w * h > ctx->buf_size))
&& (fsc || codec == 20)) {
if (((w > ctx->width) || (h > ctx->height) || (w * h > ctx->buf_size)) && fsc) {
/* 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, while the rest is
@@ -1877,7 +1922,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
case 34:
return old_codec4(ctx, gb, top, left, w, h, param, parm2, codec);
case 20:
return old_codec20(ctx, gb, w, h);
return old_codec20(ctx, gb, top, left, w, h);
case 21:
return old_codec21(ctx, gb, top, left, w, h);
case 23:
@@ -1902,22 +1947,9 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
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 {
const uint8_t *src = (uint8_t *)ctx->frm0;
const int cw = FFMIN(w, ctx->width - left);
const int ch = FFMIN(h, ctx->height - top);
if ((cw > 0) && (ch > 0) && (left >= 0) && (top >= 0)) {
uint8_t *dst = (uint8_t *)ctx->fbuf + left + top * ctx->pitch;
for (int i = 0; i < ch; i++) {
memcpy(dst, src, cw);
dst += ctx->pitch;
src += w;
}
}
}
return 0;
GetByteContext rc;
bytestream2_init(&rc, (const uint8_t *)ctx->frm0, w * h);
return old_codec20(ctx, &rc, top, left, w, h);
}
static int process_ftch(SANMVideoContext *ctx, int size)