PR #24687 opened by Peter Ross (pross)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24687
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24687.patch

Rhetorex ADPCM decoder and FATE test case.

```fate-samples
rhetorex/rhetorex-mono-4bit-8000.wav
```


>From 243cb14d50c3c77887e705dcccad23d58bb4e245 Mon Sep 17 00:00:00 2001
From: Peter Ross <[email protected]>
Date: Fri, 20 Jun 2025 21:18:00 +1000
Subject: [PATCH 1/2] avcodec/adpcm: Rhetorex decoder

---
 libavcodec/Makefile     |  1 +
 libavcodec/adpcm.c      | 63 +++++++++++++++++++++++++++++++++++++++++
 libavcodec/allcodecs.c  |  1 +
 libavcodec/codec_desc.c |  7 +++++
 libavcodec/codec_id.h   |  1 +
 libavformat/riff.c      |  1 +
 libavformat/riffdec.c   |  3 ++
 7 files changed, 77 insertions(+)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e2c60e9051..061a727486 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1022,6 +1022,7 @@ OBJS-$(CONFIG_ADPCM_MTAF_DECODER)         += adpcm.o 
adpcm_data.o
 OBJS-$(CONFIG_ADPCM_N64_DECODER)          += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_PSX_DECODER)          += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_PSXC_DECODER)         += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_RHETOREX_DECODER)     += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_SANYO_DECODER)        += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_SBPRO_3_DECODER)      += adpcm.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 74af2cb4d3..e035b50102 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -241,6 +241,29 @@ static const int8_t mtf_index_table[16] = {
     -1, -1, -1, -1,  2,  4,  6,  8,
 };
 
+static const int16_t rhetorex_step[128] = {
+       40,   130,   232,   350,   493,   673,   927,  1382,
+       60,   195,   348,   526,   740,  1010,  1391,  2074,
+       85,   277,   494,   745,  1048,  1431,  1971,  2938,
+      121,   391,   697,  1052,  1480,  2021,  2782,  4148,
+      176,   570,  1017,  1535,  2158,  2947,  4058,  6050,
+      257,   831,  1482,  2236,  3145,  4295,  5913,  8815,
+      373,  1206,  2151,  3245,  4564,  6232,  8579, 12791,
+      534,  1728,  3082,  4649,  6538,  8928, 12290, 18323,
+      782,  2527,  4507,  6798,  9560, 13055, 17971, 26793,
+     1115,  3603,  6426,  9692, 13631, 18614, 25623, 32767,
+     1620,  5233,  9334, 14078, 19799, 27036, 32767, 32767,
+     2361,  7630, 13608, 20526, 28866, 32767, 32767, 32767,
+     3447, 11136, 19860, 29955, 32767, 32767, 32767, 32767,
+     4865, 15717, 28031, 32767, 32767, 32767, 32767, 32767,
+     6888, 22255, 32767, 32767, 32767, 32767, 32767, 32767,
+   -10336, 32144,  5984,-24288,  4752, 24112, 24688,-26336,
+};
+
+static const int16_t rhetorex_index[8] = {
+      -83,   -55,   -27,   163,   374,   677,  1864,  3408,
+};
+
 /* end of tables */
 
 typedef struct ADPCMDecodeContext {
@@ -262,6 +285,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
     switch(avctx->codec->id) {
     case AV_CODEC_ID_ADPCM_IMA_AMV:
     case AV_CODEC_ID_ADPCM_N64:
+    case AV_CODEC_ID_ADPCM_RHETOREX:
         max_channels = 1;
         break;
     case AV_CODEC_ID_ADPCM_SANYO:
@@ -721,6 +745,34 @@ static inline int16_t 
adpcm_ct_expand_nibble(ADPCMChannelStatus *c, int8_t nibbl
     return (int16_t)c->predictor;
 }
 
+static inline int16_t adpcm_rhetorex_expand_nibble(ADPCMChannelStatus *c, 
uint16_t nibble)
+{
+    int delta, add, a, b;
+    int16_t sample;
+
+    delta = nibble & 7;
+    add = rhetorex_step[((c->step_index >> 8) & 0xF8) + delta];
+    if (nibble & 0x8)
+        add = -add;
+
+    sample = av_clip_int16(c->predictor + add);
+
+    a = (c->coeff1 << 15) + (add >> 1) * c->sample2;
+    c->coeff1 = av_clip_int16((a - ((a >> 7) & ~0xFF)) >> 15);
+
+    b = (c->coeff2 << 15) + (add >> 1) * c->sample1;
+    c->coeff2 = av_clip_int16((b - ((b >> 7) & ~0xFF) + 0x800000) >> 15);
+
+    c->predictor = av_clip_int16((c->coeff1 * c->sample1 + c->coeff2 * sample) 
>> 15);
+
+    c->sample2 = c->sample1;
+    c->sample1 = sample;
+
+    c->step_index = FFABS(64512 * c->step_index + (rhetorex_index[delta] << 
16)) >> 16;
+
+    return sample;
+}
+
 static inline int16_t adpcm_sbpro_expand_nibble(ADPCMChannelStatus *c, int8_t 
nibble, int size, int shift)
 {
     int sign, delta, diff;
@@ -1418,6 +1470,9 @@ static int get_nb_samples(AVCodecContext *avctx, 
GetByteContext *gb,
     case AV_CODEC_ID_ADPCM_PSXC:
         nb_samples = ((buf_size - 1) / ch) * 2;
         break;
+    case AV_CODEC_ID_ADPCM_RHETOREX:
+        nb_samples = buf_size * 2;
+        break;
     case AV_CODEC_ID_ADPCM_ARGO:
         nb_samples = buf_size / avctx->block_align * 32;
         break;
@@ -2825,6 +2880,13 @@ static int adpcm_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
         align_get_bits(&g);
         bytestream2_skip(&gb, get_bits_count(&g) / 8);
         ) /* End of CASE */
+    CASE(ADPCM_RHETOREX,
+        for (int i = 0; i < nb_samples / 2; i++) {
+            uint8_t byte = bytestream2_get_byteu(&gb);
+            *samples++ = adpcm_rhetorex_expand_nibble(c->status, byte >> 4);
+            *samples++ = adpcm_rhetorex_expand_nibble(c->status, byte);
+        }
+        ) /* End of CASE */
     CASE(ADPCM_ARGO,
         /*
          * The format of each block:
@@ -3015,6 +3077,7 @@ ADPCM_DECODER(ADPCM_MTAF,        adpcm_mtaf,        
"ADPCM MTAF")
 ADPCM_DECODER(ADPCM_N64,         adpcm_n64,         "ADPCM Silicon Graphics 
N64")
 ADPCM_DECODER(ADPCM_PSX,         adpcm_psx,         "ADPCM Playstation")
 ADPCM_DECODER(ADPCM_PSXC,        adpcm_psxc,        "ADPCM Playstation C")
+ADPCM_DECODER(ADPCM_RHETOREX,    adpcm_rhetorex,    "ADPCM Rhetorex")
 ADPCM_DECODER(ADPCM_SANYO,       adpcm_sanyo,       "ADPCM Sanyo")
 ADPCM_DECODER(ADPCM_SBPRO_2,     adpcm_sbpro_2,     "ADPCM Sound Blaster Pro 
2-bit")
 ADPCM_DECODER(ADPCM_SBPRO_3,     adpcm_sbpro_3,     "ADPCM Sound Blaster Pro 
2.6-bit")
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index ca20c76fe6..81536329d0 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -699,6 +699,7 @@ extern const FFCodec ff_adpcm_mtaf_decoder;
 extern const FFCodec ff_adpcm_n64_decoder;
 extern const FFCodec ff_adpcm_psx_decoder;
 extern const FFCodec ff_adpcm_psxc_decoder;
+extern const FFCodec ff_adpcm_rhetorex_decoder;
 extern const FFCodec ff_adpcm_sanyo_decoder;
 extern const FFCodec ff_adpcm_sbpro_2_decoder;
 extern const FFCodec ff_adpcm_sbpro_3_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index dc20b57df4..95704cc38a 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2698,6 +2698,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Acorn Escape"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_ADPCM_RHETOREX,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_rhetorex",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM Rhetorex"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 841aa28d20..5fe44bbf90 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -430,6 +430,7 @@ enum AVCodecID {
     AV_CODEC_ID_ADPCM_PSXC,
     AV_CODEC_ID_ADPCM_CIRCUS,
     AV_CODEC_ID_ADPCM_IMA_ESCAPE,
+    AV_CODEC_ID_ADPCM_RHETOREX,
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 21de951e3a..a4cde96806 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -564,6 +564,7 @@ const AVCodecTag ff_codec_wav_tags[] = {
     { AV_CODEC_ID_METASOUND,       0x0075 },
     { AV_CODEC_ID_G729,            0x0083 },
     { AV_CODEC_ID_AAC,             0x00ff },
+    { AV_CODEC_ID_ADPCM_RHETOREX,  0x0100 },
     { AV_CODEC_ID_G723_1,          0x0111 },
     { AV_CODEC_ID_ADPCM_SANYO,     0x0125 },
     { AV_CODEC_ID_SIPR,            0x0130 },
diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c
index ffa3fa1100..a132545706 100644
--- a/libavformat/riffdec.c
+++ b/libavformat/riffdec.c
@@ -255,6 +255,9 @@ int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb,
     if (par->codec_id == AV_CODEC_ID_ADPCM_G726 && par->sample_rate)
         par->bits_per_coded_sample = par->bit_rate / par->sample_rate;
 
+    if (par->codec_id == AV_CODEC_ID_ADPCM_RHETOREX && 
par->bits_per_coded_sample == 3)
+        par->sample_rate = par->sample_rate * 3 / 4;
+
     /* ignore WAVEFORMATEXTENSIBLE layout if different from channel count */
     if (channels != par->ch_layout.nb_channels) {
         av_channel_layout_uninit(&par->ch_layout);
-- 
2.52.0


>From be03e681ed19e5beeaaf0db2c3164e5ea4d43eae Mon Sep 17 00:00:00 2001
From: Peter Ross <[email protected]>
Date: Sat, 28 Jun 2025 10:17:32 +1000
Subject: [PATCH 2/2] tests/fate: Rhetorex ADPCM test case

---
 tests/fate/audio.mak    |  3 +++
 tests/ref/fate/rhetorex | 45 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 tests/ref/fate/rhetorex

diff --git a/tests/fate/audio.mak b/tests/fate/audio.mak
index 60d9b229ac..f1b80da3f2 100644
--- a/tests/fate/audio.mak
+++ b/tests/fate/audio.mak
@@ -87,6 +87,9 @@ fate-on2avc: CMD = framecrc -i 
$(TARGET_SAMPLES)/vp7/potter-40.vp7 -frames 30 -v
 FATE_SAMPLES_AUDIO-$(call FRAMECRC, PAF, PAF_AUDIO) += fate-paf-audio
 fate-paf-audio: CMD = framecrc -i $(TARGET_SAMPLES)/paf/hod1-partial.paf -vn
 
+FATE_SAMPLES_AUDIO-$(call FRAMECRC, WAV, ADPCM_RHETOREX) += fate-rhetorex
+fate-rhetorex: CMD = framecrc -i 
$(TARGET_SAMPLES)/rhetorex/rhetorex-mono-4bit-8000.wav
+
 FATE_SAMPLES_AUDIO-$(call FRAMECRC, VMD, VMDAUDIO, ARESAMPLE_FILTER) += 
fate-sierra-vmd-audio
 fate-sierra-vmd-audio: CMD = framecrc -i $(TARGET_SAMPLES)/vmd/12.vmd -vn -af 
aresample
 
diff --git a/tests/ref/fate/rhetorex b/tests/ref/fate/rhetorex
new file mode 100644
index 0000000000..6d1adac607
--- /dev/null
+++ b/tests/ref/fate/rhetorex
@@ -0,0 +1,45 @@
+#tb 0: 1/8000
+#media_type 0: audio
+#codec_id 0: pcm_s16le
+#sample_rate 0: 8000
+#channel_layout_name 0: mono
+0,          0,          0,      512,     1024, 0x8eb9f551
+0,        512,        512,      512,     1024, 0xdfe243c6
+0,       1024,       1024,      512,     1024, 0x2507ee8d
+0,       1536,       1536,      512,     1024, 0x35bdf8de
+0,       2048,       2048,      512,     1024, 0xdbb714be
+0,       2560,       2560,      512,     1024, 0x7ae51702
+0,       3072,       3072,      512,     1024, 0x5da616f0
+0,       3584,       3584,      512,     1024, 0x5502ff8b
+0,       4096,       4096,      512,     1024, 0x5c2d0550
+0,       4608,       4608,      512,     1024, 0x2054f93d
+0,       5120,       5120,      512,     1024, 0xca7efde9
+0,       5632,       5632,      512,     1024, 0x0801ec51
+0,       6144,       6144,      512,     1024, 0xc04600be
+0,       6656,       6656,      512,     1024, 0x89711604
+0,       7168,       7168,      512,     1024, 0x96fb0e93
+0,       7680,       7680,      512,     1024, 0xc085e949
+0,       8192,       8192,      512,     1024, 0xe2e6fb97
+0,       8704,       8704,      512,     1024, 0x6093f2cc
+0,       9216,       9216,      512,     1024, 0xf9b80ca4
+0,       9728,       9728,      512,     1024, 0x9a46f10b
+0,      10240,      10240,      512,     1024, 0xfdade14e
+0,      10752,      10752,      512,     1024, 0x49f3f1c7
+0,      11264,      11264,      512,     1024, 0x141ff60f
+0,      11776,      11776,      512,     1024, 0xa3720f99
+0,      12288,      12288,      512,     1024, 0x75a601cb
+0,      12800,      12800,      512,     1024, 0xa9931362
+0,      13312,      13312,      512,     1024, 0x241cfd4d
+0,      13824,      13824,      512,     1024, 0x12142acd
+0,      14336,      14336,      512,     1024, 0x905727f9
+0,      14848,      14848,      512,     1024, 0x7f940c1f
+0,      15360,      15360,      512,     1024, 0x25540182
+0,      15872,      15872,      512,     1024, 0x3990e961
+0,      16384,      16384,      512,     1024, 0x1b97066b
+0,      16896,      16896,      512,     1024, 0xac79ff32
+0,      17408,      17408,      512,     1024, 0x5b20eb00
+0,      17920,      17920,      512,     1024, 0x6566022a
+0,      18432,      18432,      512,     1024, 0x934ce6ed
+0,      18944,      18944,      512,     1024, 0x10d3fd0f
+0,      19456,      19456,      512,     1024, 0x10d3fd0f
+0,      19968,      19968,      512,     1024, 0x10d3fd0f
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to