Commit 060b019b5f for ffmpeg
commit 060b019b5f73d50b06038c813e32d5297df658bf
Author: Peter Ross <pross@xvid.org>
Date: Fri Jun 20 21:18:00 2025 +1000
avcodec/adpcm: Rhetorex ADPCM decoder
diff --git a/Changelog b/Changelog
index 1cfa9db1b6..56ecd0b5d6 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ version <next>:
- NVIDIA optical flow accelerated interpolation filter (vf_fruc_vulkan)
- H.264 data partitioning support
- DSD (dsd_msbf) encoder
+- Rhetorex ADPCM decoder
version 9.0:
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index b041518093..509317c83a 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -1346,6 +1346,7 @@ following image formats are supported:
@item ADPCM Nintendo THP @tab @tab X
@item ADPCM Playstation @tab @tab X
@item ADPCM QT IMA @tab X @tab X
+@item ADPCM Rhetorex @tab @tab X
@item ADPCM Sanyo @tab @tab X
@item ADPCM SEGA CRI ADX @tab X @tab X
@tab Used in Sega Dreamcast games.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 21522f315f..7785638c77 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..a53a4c7c57 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 = 32768 * c->coeff1 + (add >> 1) * c->sample2;
+ c->coeff1 = av_clip_int16((a - ((a >> 7) & ~0xFF)) >> 15);
+
+ b = 32768 * c->coeff2 + (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 + 65536 * rhetorex_index[delta]) >> 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 c8bde3d5b2..37dafd47f4 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/libavcodec/utils.c b/libavcodec/utils.c
index cb6cf2d6a1..f87fc13873 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -479,6 +479,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id)
case AV_CODEC_ID_ADPCM_G722:
case AV_CODEC_ID_ADPCM_YAMAHA:
case AV_CODEC_ID_ADPCM_AICA:
+ case AV_CODEC_ID_ADPCM_RHETOREX:
return 4;
case AV_CODEC_ID_DSD_LSBF:
case AV_CODEC_ID_DSD_MSBF: