[PATCH] avcodec: add VDEC Huffman+DPCM video decoder
aadjiman--- via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
Adds a native decoder for the VDEC codec used in AVI files produced by VIDEC capture hardware. The codec uses a two-stage pipeline: a 9/13-bit Huffman decode (patent fig. 4-3) followed by DPCM reconstruction (patent fig. 4-6) as described in US patent 5,675,382. Output resolution is inferred from pixel count since the container advertises 2x the encoded dimensions. Based on the Python reference implementation at: https://github.com/a-d-j-i/videc2 Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Signed-off-by: adji <[email protected]> --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 + libavcodec/codec_id.h | 1 + libavcodec/vdecdec.c | 447 ++++++++++++++++++++++++++++++++++++++++ libavformat/riff.c | 1 + 6 files changed, 458 insertions(+) create mode 100644 libavcodec/vdecdec.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ffbacc2ed3..27b0aeee03 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -891,6 +891,7 @@ OBJS-$(CONFIG_ZLIB_DECODER) += lcldec.o OBJS-$(CONFIG_ZLIB_ENCODER) += lclenc.o OBJS-$(CONFIG_ZMBV_DECODER) += zmbv.o OBJS-$(CONFIG_ZMBV_ENCODER) += zmbvenc.o +OBJS-$(CONFIG_VDEC_DECODER) += vdecdec.o # (AD)PCM decoders/encoders OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 314cb230a4..0106bcea38 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -428,6 +428,7 @@ extern const FFCodec ff_zlib_encoder; extern const FFCodec ff_zlib_decoder; extern const FFCodec ff_zmbv_encoder; extern const FFCodec ff_zmbv_decoder; +extern const FFCodec ff_vdec_decoder; /* audio codecs */ extern const FFCodec ff_aac_encoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 7a16d002b9..b6999eada3 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2017,6 +2017,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, .mime_types= MT("image/webp"), }, + { + .id = AV_CODEC_ID_VDEC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vdec", + .long_name = NULL_IF_CONFIG_SMALL("VDEC Huffman+DPCM video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* various PCM "codecs" */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 1aad9ba0e9..13442fb543 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -333,6 +333,7 @@ enum AVCodecID { AV_CODEC_ID_PRORES_RAW, AV_CODEC_ID_JPEGXS, AV_CODEC_ID_WEBP_ANIM, + AV_CODEC_ID_VDEC, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/vdecdec.c b/libavcodec/vdecdec.c new file mode 100644 index 0000000000..1934e53b3b --- /dev/null +++ b/libavcodec/vdecdec.c @@ -0,0 +1,447 @@ +/* + * VDEC video decoder + * Huffman + DPCM compression as described in US patent 5,675,382 + * https://patentimages.storage.googleapis.com/e5/59/90/dbb789f1f1bdb5/US5675382.pdf + * + * Based on the Python reference implementation: + * https://github.com/a-d-j-i/videc2 + */ + +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "get_bits.h" +#include "libavutil/mem.h" + +/* 9-bit Huffman table (patent fig. 4-3a). + * Entry format: bits[15:11]=nbits, bits[8:6]=b, bits[5:3]=g, bits[2:0]=r. + * Keys 0x000–0x03F (top 3 bits == 0) are never dispatched here; + * those go to table_430b instead, so those entries are 0x0000. */ +static const uint16_t table_430a[512] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x401b, 0x401b, 0x4058, 0x4058, 0x4050, 0x4050, 0x4094, 0x4094, + 0x4052, 0x4052, 0x4081, 0x4081, 0x40c0, 0x40c0, 0x4003, 0x4003, + 0x401d, 0x401d, 0x405d, 0x405d, 0x4054, 0x4054, 0x40db, 0x40db, + 0x405b, 0x405b, 0x4082, 0x4082, 0x4014, 0x4014, 0x400b, 0x400b, + 0x38d9, 0x38d9, 0x38d9, 0x38d9, 0x384b, 0x384b, 0x384b, 0x384b, + 0x3859, 0x3859, 0x3859, 0x3859, 0x3842, 0x3842, 0x3842, 0x3842, + 0x38c8, 0x38c8, 0x38c8, 0x38c8, 0x38c9, 0x38c9, 0x38c9, 0x38c9, + 0x3812, 0x3812, 0x3812, 0x3812, 0x3892, 0x3892, 0x3892, 0x3892, + 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, + 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, + 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, + 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, + 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, + 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, + 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, + 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, + 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, + 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, + 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, + 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, + 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, + 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, + 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, + 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, + 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, + 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, + 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, + 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, + 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, + 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, + 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, + 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, +}; + +/* 13-bit Huffman table (patent fig. 4-3b). + * Only keys 0x0000–0x03FF are reachable (top 3 bits must all be 0). */ +static const uint16_t table_430b[1024] = { + 0x69f7, 0x69f6, 0x69f3, 0x69f1, 0x69e7, 0x69e6, 0x69e3, 0x69de, + 0x69d7, 0x69d6, 0x69d5, 0x69d3, 0x69cf, 0x69ce, 0x69c7, 0x69c6, + 0x69c5, 0x69c3, 0x69c2, 0x69a7, 0x699f, 0x699e, 0x6997, 0x6996, + 0x698e, 0x698d, 0x6987, 0x6986, 0x6984, 0x697e, 0x6957, 0x6947, + 0x693f, 0x692f, 0x690f, 0x6907, 0x68bf, 0x68be, 0x68b7, 0x687e, + 0x687c, 0x687a, 0x6847, 0x683e, 0x683a, 0x6838, 0x69f4, 0x69e5, + 0x69e4, 0x69df, 0x69dc, 0x69d4, 0x69d1, 0x69cc, 0x69ca, 0x69c4, + 0x69b8, 0x69aa, 0x698f, 0x698c, 0x698b, 0x6985, 0x694f, 0x691f, + 0x6917, 0x68e7, 0x68a7, 0x6897, 0x6887, 0x6857, 0x683c, 0x6837, + 0x69f5, 0x69ee, 0x69e2, 0x69cd, 0x69cb, 0x69c1, 0x69bf, 0x699d, + 0x699a, 0x698a, 0x6983, 0x6981, 0x6976, 0x693e, 0x68fe, 0x68d7, + 0x68c7, 0x68b8, 0x6877, 0x683f, 0x683d, 0x6817, 0x69fe, 0x69d2, + 0x699c, 0x6995, 0x6991, 0x6989, 0x6982, 0x697c, 0x694e, 0x6946, + 0x68cf, 0x68ce, 0x68b5, 0x68b3, 0x688f, 0x6876, 0x6867, 0x684f, + 0x6827, 0x69ec, 0x69ea, 0x69e1, 0x69da, 0x69b1, 0x69af, 0x69a5, + 0x699b, 0x6993, 0x6970, 0x6967, 0x6956, 0x693d, 0x6935, 0x6927, + 0x68f7, 0x68bb, 0x688e, 0x6875, 0x6835, 0x69fc, 0x69f0, 0x69be, + 0x69bd, 0x69b3, 0x695f, 0x6945, 0x690e, 0x68bd, 0x68bc, 0x68ba, + 0x68ae, 0x686e, 0x6836, 0x680f, 0x680e, 0x69f8, 0x69bb, 0x69ac, + 0x69a3, 0x6988, 0x6953, 0x68fc, 0x68f6, 0x68df, 0x6878, 0x6871, + 0x683b, 0x6833, 0x6807, 0x69c0, 0x695e, 0x693b, 0x6937, 0x685e, + 0x69ef, 0x69e0, 0x69b9, 0x6906, 0x68fa, 0x68c6, 0x6886, 0x6831, + 0x682e, 0x681e, 0x69ba, 0x69b7, 0x69ab, 0x6955, 0x692e, 0x692a, + 0x687b, 0x6870, 0x6839, 0x69f2, 0x6999, 0x6998, 0x6978, 0x6960, + 0x689f, 0x69dd, 0x69a1, 0x693c, 0x6873, 0x69db, 0x6972, 0x6965, + 0x6943, 0x693a, 0x6933, 0x68f3, 0x6879, 0x682c, 0x69bc, 0x6974, + 0x6951, 0x6931, 0x6928, 0x691e, 0x6916, 0x687d, 0x6874, 0x684e, + 0x681f, 0x69e8, 0x69ae, 0x69ad, 0x697a, 0x690c, 0x68f4, 0x6896, + 0x6830, 0x69d0, 0x69a9, 0x6977, 0x692c, 0x68ee, 0x689e, 0x69eb, + 0x6994, 0x6961, 0x6939, 0x68ff, 0x68f8, 0x68f5, 0x68de, 0x68b1, + 0x68aa, 0x6872, 0x6971, 0x68f1, 0x682a, 0x69b5, 0x6938, 0x685f, + 0x6806, 0x69fa, 0x6966, 0x69ff, 0x696e, 0x68ac, 0x68f2, 0x68f0, + 0x68b9, 0x6846, 0x69ed, 0x697f, 0x6962, 0x686c, 0x6963, 0x68c5, + 0x687f, 0x686a, 0x6973, 0x6915, 0x68ef, 0x69d8, 0x69d9, 0x69a6, + 0x68fd, 0x6992, 0x6964, 0x695c, 0x69f9, 0x690a, 0x6950, 0x68b6, + 0x6834, 0x69fd, 0x69a8, 0x6952, 0x68fb, 0x691c, 0x68a8, 0x686f, + 0x68f9, 0x68ea, 0x69c8, 0x692b, 0x6980, 0x696f, 0x692d, 0x696a, + 0x6941, 0x69fb, 0x69c9, 0x6975, 0x6905, 0x696c, 0x68ec, 0x69e9, + 0x6918, 0x68af, 0x6832, 0x694c, 0x6929, 0x68d6, 0x68a6, 0x6904, + 0x69a2, 0x6823, 0x697b, 0x6936, 0x691a, 0x6855, 0x6816, 0x69b0, + 0x6861, 0x6821, 0x68d5, 0x69b6, 0x6942, 0x68a5, 0x68a9, 0x697d, + 0x6925, 0x68b0, 0x6828, 0x6909, 0x6895, 0x6845, 0x68ab, 0x68a1, + 0x681c, 0x6979, 0x6921, 0x6926, 0x6815, 0x69b4, 0x68b2, 0x688c, + 0x6863, 0x694d, 0x6930, 0x6908, 0x68e0, 0x69b2, 0x6903, 0x690d, + 0x6923, 0x68b4, 0x68e6, 0x6856, 0x6913, 0x69a4, 0x682f, 0x695a, + 0x690b, 0x68a3, 0x6825, 0x6885, 0x6829, 0x68e1, 0x681a, 0x69a0, + 0x689a, 0x6944, 0x68dc, 0x6860, 0x6853, 0x68d3, 0x6826, 0x6901, + 0x6932, 0x6968, 0x6919, 0x6868, 0x685c, 0x695d, 0x682b, 0x689c, + 0x68e8, 0x6954, 0x6865, 0x6934, 0x691d, 0x6990, 0x694a, 0x691b, + 0x68e2, 0x68cc, 0x6805, 0x68e3, 0x680c, 0x6911, 0x6911, 0x6911, + 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, + 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, + 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, + 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, + 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, + 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, + 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, + 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, + 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, + 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, + 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, + 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, + 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, + 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, + 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, + 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, + 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, + 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, + 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, + 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, + 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, + 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, + 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, + 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, + 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, + 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, + 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, + 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, + 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, + 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, + 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, + 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, + 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, + 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, + 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, + 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, + 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, + 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, + 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, + 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, + 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, + 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, + 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, + 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, + 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, + 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, + 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, + 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, + 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, + 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, + 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, + 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, + 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, + 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, + 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, + 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, + 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, + 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, + 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, + 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, + 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, + 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, + 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, + 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, + 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, + 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, + 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, + 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, + 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, + 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, + 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, + 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, + 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, + 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, + 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, + 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, + 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, +}; + +/* DPCM reconstruction tables (patent fig. 4-6a/b). + * Index: category (0–7) + predictor (0–31) * 8. + * Output: reconstructed pixel value 0–31. */ +static const uint8_t table_460a[256] = { + 0x00, 0x01, 0x03, 0x08, 0x0d, 0x12, 0x17, 0x1d, + 0x01, 0x02, 0x04, 0x09, 0x0e, 0x13, 0x18, 0x1d, + 0x02, 0x03, 0x01, 0x05, 0x0a, 0x0f, 0x16, 0x1c, + 0x03, 0x04, 0x01, 0x06, 0x0b, 0x10, 0x16, 0x1c, + 0x04, 0x05, 0x02, 0x07, 0x0c, 0x11, 0x17, 0x1d, + 0x05, 0x06, 0x03, 0x08, 0x0d, 0x12, 0x17, 0x1d, + 0x06, 0x07, 0x04, 0x09, 0x0e, 0x13, 0x18, 0x1d, + 0x07, 0x08, 0x05, 0x0a, 0x01, 0x0f, 0x15, 0x1c, + 0x08, 0x09, 0x06, 0x0b, 0x01, 0x10, 0x16, 0x1d, + 0x09, 0x0a, 0x07, 0x0c, 0x02, 0x11, 0x16, 0x1c, + 0x0a, 0x0b, 0x08, 0x0d, 0x02, 0x12, 0x17, 0x1d, + 0x0b, 0x0c, 0x09, 0x0e, 0x03, 0x13, 0x18, 0x1d, + 0x0c, 0x0d, 0x0a, 0x0f, 0x05, 0x15, 0x01, 0x1c, + 0x0d, 0x0e, 0x0b, 0x10, 0x06, 0x15, 0x01, 0x1c, + 0x0e, 0x0f, 0x0c, 0x11, 0x07, 0x16, 0x02, 0x1c, + 0x0f, 0x10, 0x0d, 0x12, 0x08, 0x17, 0x02, 0x1d, + 0x10, 0x11, 0x0e, 0x13, 0x09, 0x18, 0x03, 0x1d, + 0x11, 0x12, 0x0f, 0x14, 0x09, 0x19, 0x02, 0x1e, + 0x12, 0x13, 0x10, 0x15, 0x0a, 0x1a, 0x03, 0x1e, + 0x13, 0x14, 0x11, 0x16, 0x0c, 0x1c, 0x07, 0x01, + 0x14, 0x15, 0x12, 0x17, 0x0d, 0x1c, 0x08, 0x02, + 0x15, 0x16, 0x13, 0x18, 0x0e, 0x1d, 0x08, 0x02, + 0x16, 0x17, 0x14, 0x19, 0x0f, 0x1e, 0x09, 0x02, + 0x17, 0x18, 0x15, 0x1a, 0x10, 0x1e, 0x0a, 0x03, + 0x18, 0x19, 0x16, 0x1b, 0x11, 0x1e, 0x0b, 0x03, + 0x19, 0x1a, 0x17, 0x1c, 0x12, 0x0d, 0x07, 0x02, + 0x1a, 0x1b, 0x18, 0x1d, 0x13, 0x0e, 0x08, 0x02, + 0x1b, 0x1c, 0x19, 0x1e, 0x14, 0x0f, 0x09, 0x02, + 0x1c, 0x1d, 0x1a, 0x15, 0x10, 0x0b, 0x06, 0x01, + 0x1d, 0x1e, 0x1b, 0x16, 0x11, 0x0c, 0x07, 0x02, + 0x1e, 0x1f, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x02, + 0x1f, 0x1e, 0x1b, 0x17, 0x12, 0x0d, 0x08, 0x02, +}; + +static const uint8_t table_460b[256] = { + 0x00, 0x01, 0x04, 0x08, 0x0d, 0x12, 0x17, 0x1d, + 0x01, 0x00, 0x03, 0x08, 0x0d, 0x12, 0x17, 0x1d, + 0x02, 0x01, 0x04, 0x09, 0x0e, 0x13, 0x18, 0x1d, + 0x03, 0x02, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, + 0x04, 0x03, 0x06, 0x01, 0x0b, 0x10, 0x16, 0x1d, + 0x05, 0x04, 0x07, 0x02, 0x0c, 0x11, 0x17, 0x1d, + 0x06, 0x05, 0x08, 0x03, 0x0d, 0x12, 0x18, 0x1d, + 0x07, 0x06, 0x09, 0x04, 0x0e, 0x01, 0x14, 0x1c, + 0x08, 0x07, 0x0a, 0x05, 0x0f, 0x01, 0x15, 0x1c, + 0x09, 0x08, 0x0b, 0x06, 0x10, 0x01, 0x16, 0x1d, + 0x0a, 0x09, 0x0c, 0x07, 0x11, 0x02, 0x17, 0x1d, + 0x0b, 0x0a, 0x0d, 0x08, 0x12, 0x03, 0x17, 0x1d, + 0x0c, 0x0b, 0x0e, 0x09, 0x13, 0x03, 0x18, 0x1e, + 0x0d, 0x0c, 0x0f, 0x0a, 0x15, 0x05, 0x1c, 0x01, + 0x0e, 0x0d, 0x10, 0x0b, 0x16, 0x06, 0x1d, 0x01, + 0x0f, 0x0e, 0x11, 0x0c, 0x16, 0x07, 0x1c, 0x02, + 0x10, 0x0f, 0x12, 0x0d, 0x17, 0x08, 0x1d, 0x02, + 0x11, 0x10, 0x13, 0x0e, 0x18, 0x09, 0x1d, 0x03, + 0x12, 0x11, 0x14, 0x0f, 0x19, 0x0a, 0x1e, 0x03, + 0x13, 0x12, 0x15, 0x10, 0x1a, 0x0a, 0x1e, 0x03, + 0x14, 0x13, 0x16, 0x11, 0x1c, 0x0c, 0x07, 0x02, + 0x15, 0x14, 0x17, 0x12, 0x1d, 0x0d, 0x08, 0x02, + 0x16, 0x15, 0x18, 0x13, 0x1d, 0x0e, 0x09, 0x03, + 0x17, 0x16, 0x19, 0x14, 0x1e, 0x0f, 0x09, 0x02, + 0x18, 0x17, 0x1a, 0x15, 0x1e, 0x10, 0x0a, 0x03, + 0x19, 0x18, 0x1b, 0x16, 0x11, 0x0c, 0x07, 0x02, + 0x1a, 0x19, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x02, + 0x1b, 0x1a, 0x1d, 0x18, 0x13, 0x0e, 0x08, 0x02, + 0x1c, 0x1b, 0x1e, 0x19, 0x14, 0x0f, 0x09, 0x03, + 0x1d, 0x1c, 0x1e, 0x1a, 0x15, 0x10, 0x09, 0x03, + 0x1e, 0x1d, 0x1b, 0x16, 0x11, 0x0c, 0x07, 0x02, + 0x1f, 0x1e, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x02, +}; + +/* Replicate seg3:0x5918 — 32-entry blue-channel gain LUT. + * Maps reconstructed 5-bit value (0..31) → gain-adjusted 5-bit value (0..31). */ +static void build_gain_lut(uint8_t lut[32], uint8_t gain_byte) +{ + uint32_t step = 0x300U * (uint32_t)gain_byte + (5U << 16); + uint32_t acc = 0; + for (int i = 0; i < 32; i++) { + acc += step; + lut[i] = FFMIN(acc >> 19, 31); + } +} + +static av_cold int vdec_decode_init(AVCodecContext *avctx) +{ + avctx->pix_fmt = AV_PIX_FMT_RGB24; + return 0; +} + +static int vdec_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *avpkt) +{ + const uint8_t *buf = avpkt->data; + int size = avpkt->size; + uint8_t gain_lut[32]; + uint8_t *codes = NULL; + uint8_t *recon = NULL; + GetBitContext gb; + int ret; + + if (size < 2) { + av_log(avctx, AV_LOG_ERROR, "packet too small (%d bytes)\n", size); + return AVERROR_INVALIDDATA; + } + + /* Header: buf[0]+1 bytes to skip (type tag + gain byte + optional padding). + * buf[1] is always the blue-channel gain register. */ + int skip = buf[0] + 1; + if (size <= skip) { + av_log(avctx, AV_LOG_ERROR, "header overruns packet\n"); + return AVERROR_INVALIDDATA; + } + + build_gain_lut(gain_lut, buf[1]); + + ret = init_get_bits8(&gb, buf + skip, size - skip); + if (ret < 0) + return ret; + + /* Step 1 — Huffman decode all codes. Dimensions are inferred from the + * bitstream after decoding, so the container size is ignored entirely. + * 640×480 is the largest known VDEC resolution. */ + int max_codes = 640 * 480; + codes = av_malloc(max_codes * 3); + if (!codes) + return AVERROR(ENOMEM); + + int n_decoded = 0; + while (n_decoded < max_codes) { + uint16_t v; + if (get_bits_left(&gb) >= 13 && show_bits(&gb, 3) == 0) { + v = table_430b[show_bits(&gb, 13)]; + } else if (get_bits_left(&gb) >= 9) { + v = table_430a[show_bits(&gb, 9)]; + } else { + break; + } + int nbits = (v >> 11) & 0x1f; + if (nbits == 0) + break; + codes[n_decoded * 3] = v & 0x7; + codes[n_decoded * 3 + 1] = (v >> 3) & 0x7; + codes[n_decoded * 3 + 2] = (v >> 6) & 0x7; + n_decoded++; + skip_bits(&gb, nbits); + } + + if (n_decoded == 0) { + av_log(avctx, AV_LOG_ERROR, "no pixels decoded\n"); + ret = AVERROR_INVALIDDATA; + goto end; + } + + /* Infer encoded dimensions from pixel count (always 4:3 aspect ratio). + * The AVI container reports 2× the encoded size in each dimension, so the + * packet contains pixels for one of: 160×120, 320×240, or 640×480. */ + int enc_w, enc_h; + if (n_decoded <= 48000) { enc_w = 160; enc_h = 120; } + else if (n_decoded <= 192000) { enc_w = 320; enc_h = 240; } + else { enc_w = 640; enc_h = 480; } + + ret = ff_set_dimensions(avctx, enc_w, enc_h); + if (ret < 0) + goto end; + + /* Step 2 — DPCM reconstruction + write to output frame. */ + recon = av_malloc(enc_w * enc_h * 3); + if (!recon) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) + goto end; + + int n = enc_w * enc_h; + for (int i = 0; i < n; i++) { + int col = i % enc_w; + int row = i / enc_w; + int carry = (row + col + 1) & 1; + + int lr = col > 0 ? recon[(i - 1) * 3] : 16; + int lg = col > 0 ? recon[(i - 1) * 3 + 1] : 16; + int lb = col > 0 ? recon[(i - 1) * 3 + 2] : 16; + int ar = row > 0 ? recon[(i - enc_w) * 3] : 16; + int ag = row > 0 ? recon[(i - enc_w) * 3 + 1] : 16; + int ab = row > 0 ? recon[(i - enc_w) * 3 + 2] : 16; + + int pr = (lr + ar + carry) >> 1; + int pg = (lg + ag + carry) >> 1; + int pb = (lb + ab + carry) >> 1; + + const uint8_t *tbl = carry ? table_460b : table_460a; + recon[i * 3] = tbl[codes[i * 3] + pr * 8]; + recon[i * 3 + 1] = tbl[codes[i * 3 + 1] + pg * 8]; + recon[i * 3 + 2] = tbl[codes[i * 3 + 2] + pb * 8]; + + /* Codec bit layout: bits 0-2 = Blue, bits 3-5 = Green, bits 6-8 = Red. + * Gain LUT is applied to the Red channel. */ + uint8_t b5 = recon[i * 3]; + uint8_t g5 = recon[i * 3 + 1]; + uint8_t r5 = gain_lut[recon[i * 3 + 2]]; + uint8_t *dst = frame->data[0] + row * frame->linesize[0] + col * 3; + dst[0] = (r5 << 3) | (r5 >> 2); + dst[1] = (g5 << 3) | (g5 >> 2); + dst[2] = (b5 << 3) | (b5 >> 2); + } + + *got_frame = 1; + ret = avpkt->size; +end: + av_freep(&codes); + av_freep(&recon); + return ret; +} + +const FFCodec ff_vdec_decoder = { + .p.name = "vdec", + CODEC_LONG_NAME("VDEC Huffman+DPCM video"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VDEC, + .init = vdec_decode_init, + FF_CODEC_DECODE_CB(vdec_decode_frame), + .p.capabilities = AV_CODEC_CAP_DR1, +}; \ No newline at end of file diff --git a/libavformat/riff.c b/libavformat/riff.c index fc79d0ac21..a11e5a059d 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -382,6 +382,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_TRUEMOTION2RT,MKTAG('T', 'R', '2', '0') }, { AV_CODEC_ID_CSCD, MKTAG('C', 'S', 'C', 'D') }, { AV_CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') }, + { AV_CODEC_ID_VDEC, MKTAG('V', 'D', 'E', 'C') }, { AV_CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') }, { AV_CODEC_ID_CAVS, MKTAG('C', 'A', 'V', 'S') }, { AV_CODEC_ID_AVS2, MKTAG('A', 'V', 'S', '2') }, -- 2.39.5 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]