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.
Showing the changes to libavcodec (1 of 1 file). Show all
Unified · Split
| @@ -291,6 +291,7 @@ typedef struct SANMVideoContext { · 290 unmodified lines | ||
| 291 | 291 | |
| 292 | 292 | int8_t p4x4glyphs[NGLYPHS][16]; |
| 293 | 293 | int8_t p8x8glyphs[NGLYPHS][64]; |
| 294 | + uint8_t c47itbl[0x10000]; | |
| 294 | 295 | } SANMVideoContext; |
| 295 | 296 | |
| 296 | 297 | typedef struct SANMFrameHeader { |
| @@ -856,6 +857,55 @@ static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, · 559 unmodified lines | ||
| 856 | 857 | return 0; |
| 857 | 858 | } |
| 858 | 859 | |
| 860 | +static void codec47_read_interptable(SANMVideoContext *ctx) | |
| 861 | +{ | |
| 862 | + uint8_t *p1, *p2, *itbl = ctx->c47itbl; | |
| 863 | + int i, j; | |
| 864 | + | |
| 865 | + for (i = 0; i < 256; i++) { | |
| 866 | + p1 = p2 = itbl + i; | |
| 867 | + for (j = 256 - i; j; j--) { | |
| 868 | + *p1 = *p2 = bytestream2_get_byte(&ctx->gb); | |
| 869 | + p1 += 1; | |
| 870 | + p2 += 256; | |
| 871 | + } | |
| 872 | + itbl += 256; | |
| 873 | + } | |
| 874 | +} | |
| 875 | + | |
| 876 | +static void codec47_comp1(SANMVideoContext *ctx, uint8_t *dst_in, int width, | |
| 877 | + int height, ptrdiff_t stride) | |
| 878 | +{ | |
| 879 | + uint8_t p1, *dst, *itbl = ctx->c47itbl; | |
| 880 | + uint16_t px; | |
| 881 | + int i, j; | |
| 882 | + | |
| 883 | + dst = dst_in + stride; | |
| 884 | + for (i = 0; i < height; i += 2) { | |
| 885 | + p1 = bytestream2_get_byte(&ctx->gb); | |
| 886 | + *dst++ = p1; | |
| 887 | + *dst++ = p1; | |
| 888 | + px = p1; | |
| 889 | + for (j = 2; j < width; j += 2) { | |
| 890 | + p1 = bytestream2_get_byte(&ctx->gb); | |
| 891 | + px = (px << 8) | p1; | |
| 892 | + *dst++ = itbl[px]; | |
| 893 | + *dst++ = p1; | |
| 894 | + } | |
| 895 | + dst += stride; | |
| 896 | + } | |
| 897 | + | |
| 898 | + memcpy(dst_in, dst_in + stride, width); | |
| 899 | + dst = dst_in + stride + stride; | |
| 900 | + for (i = 2; i < height - 1; i += 2) { | |
| 901 | + for (j = 0; j < width; j++) { | |
| 902 | + px = (*(dst - stride) << 8) | *(dst + stride); | |
| 903 | + *dst++ = itbl[px]; | |
| 904 | + } | |
| 905 | + dst += stride; | |
| 906 | + } | |
| 907 | +} | |
| 908 | + | |
| 859 | 909 | static int old_codec47(SANMVideoContext *ctx, int top, |
| 860 | 910 | int left, int width, int height) |
| 861 | 911 | { |
| @@ -880,8 +930,11 @@ static int old_codec47(SANMVideoContext *ctx, int top, · 18 unmodified lines | ||
| 880 | 930 | av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); |
| 881 | 931 | } |
| 882 | 932 | |
| 883 | − if (skip & 1) | |
| 884 | − bytestream2_skip(&ctx->gb, 0x8080); | |
| 933 | + if (skip & 1) { | |
| 934 | + if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080) | |
| 935 | + return AVERROR_INVALIDDATA; | |
| 936 | + codec47_read_interptable(ctx); | |
| 937 | + } | |
| 885 | 938 | if (!seq) { |
| 886 | 939 | ctx->prev_seq = -1; |
| 887 | 940 | memset(prev1, 0, ctx->height * stride); |
| @@ -900,15 +953,7 @@ static int old_codec47(SANMVideoContext *ctx, int top, · 12 unmodified lines | ||
| 900 | 953 | case 1: |
| 901 | 954 | if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) |
| 902 | 955 | return AVERROR_INVALIDDATA; |
| 903 | − for (j = 0; j < height; j += 2) { | |
| 904 | − for (i = 0; i < width; i += 2) { | |
| 905 | − dst[i] = | |
| 906 | − dst[i + 1] = | |
| 907 | − dst[stride + i] = | |
| 908 | − dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb); | |
| 909 | − } | |
| 910 | − dst += stride * 2; | |
| 911 | − } | |
| 956 | + codec47_comp1(ctx, dst, width, height, stride); | |
| 912 | 957 | break; |
| 913 | 958 | case 2: |
| 914 | 959 | if (seq == ctx->prev_seq + 1) { |