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]