[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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.