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 | int8_t p4x4glyphs[NGLYPHS][16]; | 292 | int8_t p4x4glyphs[NGLYPHS][16]; |
| 293 | int8_t p8x8glyphs[NGLYPHS][64]; | 293 | int8_t p8x8glyphs[NGLYPHS][64]; |
| 294 | uint8_t c47itbl[0x10000]; | ||
| 294 | } SANMVideoContext; | 295 | } SANMVideoContext; |
| 295 | 296 | ||
| 296 | typedef struct SANMFrameHeader { | 297 | typedef struct SANMFrameHeader { |
| @@ -856,6 +857,55 @@ static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, · 559 unmodified lines | |||
| 856 | return 0; | 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 | static int old_codec47(SANMVideoContext *ctx, int top, | 909 | static int old_codec47(SANMVideoContext *ctx, int top, |
| 860 | int left, int width, int height) | 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 | av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); | 930 | av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); |
| 881 | } | 931 | } |
| 882 | 932 | ||
| 883 | if (skip & 1) | 933 | if (skip & 1) { |
| 884 | bytestream2_skip(&ctx->gb, 0x8080); | 934 | if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080) |
| 935 | return AVERROR_INVALIDDATA; | ||
| 936 | codec47_read_interptable(ctx); | ||
| 937 | } | ||
| 885 | if (!seq) { | 938 | if (!seq) { |
| 886 | ctx->prev_seq = -1; | 939 | ctx->prev_seq = -1; |
| 887 | memset(prev1, 0, ctx->height * stride); | 940 | memset(prev1, 0, ctx->height * stride); |
| @@ -900,15 +953,7 @@ static int old_codec47(SANMVideoContext *ctx, int top, · 12 unmodified lines | |||
| 900 | case 1: | 953 | case 1: |
| 901 | if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) | 954 | if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) |
| 902 | return AVERROR_INVALIDDATA; | 955 | return AVERROR_INVALIDDATA; |
| 903 | for (j = 0; j < height; j += 2) { | 956 | codec47_comp1(ctx, dst, width, height, stride); |
| 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 | } | ||
| 912 | break; | 957 | break; |
| 913 | case 2: | 958 | case 2: |
| 914 | if (seq == ctx->prev_seq + 1) { | 959 | if (seq == ctx->prev_seq + 1) { |