You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
avcodec/sanm: codec23 decoder
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>
This commit is contained in:
@ -292,6 +292,7 @@ typedef struct SANMVideoContext {
|
|||||||
int8_t p4x4glyphs[NGLYPHS][16];
|
int8_t p4x4glyphs[NGLYPHS][16];
|
||||||
int8_t p8x8glyphs[NGLYPHS][64];
|
int8_t p8x8glyphs[NGLYPHS][64];
|
||||||
uint8_t c47itbl[0x10000];
|
uint8_t c47itbl[0x10000];
|
||||||
|
uint8_t c23lut[256];
|
||||||
} SANMVideoContext;
|
} SANMVideoContext;
|
||||||
|
|
||||||
typedef struct SANMFrameHeader {
|
typedef struct SANMFrameHeader {
|
||||||
@ -557,6 +558,62 @@ static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
|
|||||||
return 0;
|
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,
|
static int old_codec1(SANMVideoContext *ctx, int top,
|
||||||
int left, int width, int height, int opaque)
|
int left, int width, int height, int opaque)
|
||||||
{
|
{
|
||||||
@ -1258,11 +1315,15 @@ static int old_codec48(SANMVideoContext *ctx, int width, int height)
|
|||||||
|
|
||||||
static int process_frame_obj(SANMVideoContext *ctx)
|
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 left = bytestream2_get_le16u(&ctx->gb);
|
||||||
int16_t top = bytestream2_get_le16u(&ctx->gb);
|
int16_t top = bytestream2_get_le16u(&ctx->gb);
|
||||||
uint16_t w = bytestream2_get_le16u(&ctx->gb);
|
uint16_t w = bytestream2_get_le16u(&ctx->gb);
|
||||||
uint16_t h = 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 < 1 || h < 1 || w > 800 || h > 600 || left > 800 || top > 600) {
|
if (w < 1 || h < 1 || w > 800 || h > 600 || left > 800 || top > 600) {
|
||||||
av_log(ctx->avctx, AV_LOG_WARNING,
|
av_log(ctx->avctx, AV_LOG_WARNING,
|
||||||
@ -1316,7 +1377,6 @@ static int process_frame_obj(SANMVideoContext *ctx)
|
|||||||
h = ctx->height;
|
h = ctx->height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bytestream2_skip(&ctx->gb, 4);
|
|
||||||
|
|
||||||
/* on first FOBJ, when the codec is not one of the
|
/* 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), frm0 needs to be cleared.
|
||||||
@ -1333,6 +1393,8 @@ static int process_frame_obj(SANMVideoContext *ctx)
|
|||||||
return old_codec1(ctx, top, left, w, h, codec == 3);
|
return old_codec1(ctx, top, left, w, h, codec == 3);
|
||||||
case 2:
|
case 2:
|
||||||
return old_codec2(ctx, top, left, w, h);
|
return old_codec2(ctx, top, left, w, h);
|
||||||
|
case 23:
|
||||||
|
return old_codec23(ctx, top, left, w, h, param, parm2);
|
||||||
case 37:
|
case 37:
|
||||||
return old_codec37(ctx, w, h);
|
return old_codec37(ctx, w, h);
|
||||||
case 47:
|
case 47:
|
||||||
|
Reference in New Issue
Block a user