diff options
author | Manuel Lauss <manuel.lauss@gmail.com> | 2024-11-08 09:55:03 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2024-11-28 14:31:15 +0100 |
commit | 1e2a72ae1da97133ba4e2c8dcc78e663a2e9f349 (patch) | |
tree | 7cbbf7bad381fbe14e893d0cdabecfc0fdb654a8 | |
parent | 44d32c8a23046d40b6be16b93073197efb082cf0 (diff) | |
download | ffmpeg-1e2a72ae1da97133ba4e2c8dcc78e663a2e9f349.tar.gz |
libavcodec/sanm: add codec47 interpolation table support
Some codec47 frames come with an interpolation table:
Combining 2 adjacent pixels into a 16bit value, this value can
then be used as index into the interpolation table to get a new
pixel value. This is used for subcodec 1, which encodes a key-
frame at half width and height, and makes these frame less blocky
appearing.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
-rw-r--r-- | libavcodec/sanm.c | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index 8b7c0d9556..022d4b347e 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -291,6 +291,7 @@ typedef struct SANMVideoContext { int8_t p4x4glyphs[NGLYPHS][16]; int8_t p8x8glyphs[NGLYPHS][64]; + uint8_t c47itbl[0x10000]; } SANMVideoContext; typedef struct SANMFrameHeader { @@ -856,6 +857,55 @@ static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, return 0; } +static void codec47_read_interptable(SANMVideoContext *ctx) +{ + uint8_t *p1, *p2, *itbl = ctx->c47itbl; + int i, j; + + for (i = 0; i < 256; i++) { + p1 = p2 = itbl + i; + for (j = 256 - i; j; j--) { + *p1 = *p2 = bytestream2_get_byte(&ctx->gb); + p1 += 1; + p2 += 256; + } + itbl += 256; + } +} + +static void codec47_comp1(SANMVideoContext *ctx, uint8_t *dst_in, int width, + int height, ptrdiff_t stride) +{ + uint8_t p1, *dst, *itbl = ctx->c47itbl; + uint16_t px; + int i, j; + + dst = dst_in + stride; + for (i = 0; i < height; i += 2) { + p1 = bytestream2_get_byte(&ctx->gb); + *dst++ = p1; + *dst++ = p1; + px = p1; + for (j = 2; j < width; j += 2) { + p1 = bytestream2_get_byte(&ctx->gb); + px = (px << 8) | p1; + *dst++ = itbl[px]; + *dst++ = p1; + } + dst += stride; + } + + memcpy(dst_in, dst_in + stride, width); + dst = dst_in + stride + stride; + for (i = 2; i < height - 1; i += 2) { + for (j = 0; j < width; j++) { + px = (*(dst - stride) << 8) | *(dst + stride); + *dst++ = itbl[px]; + } + dst += stride; + } +} + static int old_codec47(SANMVideoContext *ctx, int top, int left, int width, int height) { @@ -880,8 +930,11 @@ static int old_codec47(SANMVideoContext *ctx, int top, av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); } - if (skip & 1) - bytestream2_skip(&ctx->gb, 0x8080); + if (skip & 1) { + if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080) + return AVERROR_INVALIDDATA; + codec47_read_interptable(ctx); + } if (!seq) { ctx->prev_seq = -1; memset(prev1, 0, ctx->height * stride); @@ -900,15 +953,7 @@ static int old_codec47(SANMVideoContext *ctx, int top, case 1: if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) return AVERROR_INVALIDDATA; - for (j = 0; j < height; j += 2) { - for (i = 0; i < width; i += 2) { - dst[i] = - dst[i + 1] = - dst[stride + i] = - dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb); - } - dst += stride * 2; - } + codec47_comp1(ctx, dst, width, height, stride); break; case 2: if (seq == ctx->prev_seq + 1) { |