[FFmpeg-devel] [PATCH 1/2] avcodec: add ADPCM IMA MTF decoder

Paul B Mahol onemda at gmail.com
Sat Mar 14 13:56:00 EET 2020


Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
 libavcodec/Makefile     |  1 +
 libavcodec/adpcm.c      | 33 +++++++++++++++++++++++++++++++++
 libavcodec/allcodecs.c  |  1 +
 libavcodec/avcodec.h    |  1 +
 libavcodec/codec_desc.c |  7 +++++++
 5 files changed, 43 insertions(+)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index a3326a45e7..b50a26907f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -843,6 +843,7 @@ OBJS-$(CONFIG_ADPCM_IMA_DK4_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_EA_EACS_DECODER)  += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_EA_SEAD_DECODER)  += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER)      += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_IMA_MTF_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER)       += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER)       += adpcmenc.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 4f5980f7d5..e9abddc43c 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -89,6 +89,11 @@ static const int8_t zork_index_table[8] = {
     -1, -1, -1, 1, 4, 7, 10, 12,
 };
 
+static const int8_t mtf_index_table[16] = {
+     8,  6,  4,  2, -1, -1, -1, -1,
+    -1, -1, -1, -1,  2,  4,  6,  8,
+};
+
 /* end of tables */
 
 typedef struct ADPCMDecodeContext {
@@ -304,6 +309,22 @@ static inline int16_t adpcm_ima_alp_expand_nibble(ADPCMChannelStatus *c, int8_t
     return (int16_t)c->predictor;
 }
 
+static inline int16_t adpcm_ima_mtf_expand_nibble(ADPCMChannelStatus *c, int nibble)
+{
+    int step_index, step, delta, predictor;
+
+    step = ff_adpcm_step_table[c->step_index];
+
+    delta = step * (2 * nibble - 15);
+    predictor = c->predictor + delta;
+
+    step_index = c->step_index + mtf_index_table[(unsigned)nibble];
+    c->predictor = av_clip_int16(predictor >> 4);
+    c->step_index = av_clip(step_index, 0, 88);
+
+    return (int16_t)c->predictor;
+}
+
 static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitContext *gb, int bps)
 {
     int nibble, step_index, predictor, sign, delta, diff, step, shift;
@@ -700,6 +721,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
     case AV_CODEC_ID_ADPCM_IMA_SSI:
     case AV_CODEC_ID_ADPCM_IMA_APM:
     case AV_CODEC_ID_ADPCM_IMA_ALP:
+    case AV_CODEC_ID_ADPCM_IMA_MTF:
         nb_samples = buf_size * 2 / ch;
         break;
     }
@@ -1956,6 +1978,16 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
             *samples++ = adpcm_zork_expand_nibble(&c->status[n % avctx->channels], v);
         }
         break;
+    case AV_CODEC_ID_ADPCM_IMA_MTF:
+        for (n = nb_samples / 2; n > 0; n--) {
+            for (channel = 0; channel < avctx->channels; channel++) {
+                int v = bytestream2_get_byteu(&gb);
+                *samples++  = adpcm_ima_mtf_expand_nibble(&c->status[channel], v >> 4);
+                samples[st] = adpcm_ima_mtf_expand_nibble(&c->status[channel], v & 0x0F);
+            }
+            samples += avctx->channels;
+        }
+        break;
     default:
         av_assert0(0); // unsupported codec_id should not happen
     }
@@ -2027,6 +2059,7 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_DK4,     sample_fmts_s16,  adpcm_ima_dk4,
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_EACS, sample_fmts_s16,  adpcm_ima_ea_eacs, "ADPCM IMA Electronic Arts EACS");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_SEAD, sample_fmts_s16,  adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_ISS,     sample_fmts_s16,  adpcm_ima_iss,     "ADPCM IMA Funcom ISS");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_MTF,     sample_fmts_s16,  adpcm_ima_mtf,     "ADPCM IMA Capcom's MT Framework");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_OKI,     sample_fmts_s16,  adpcm_ima_oki,     "ADPCM IMA Dialogic OKI");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_QT,      sample_fmts_s16p, adpcm_ima_qt,      "ADPCM IMA QuickTime");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_RAD,     sample_fmts_s16,  adpcm_ima_rad,     "ADPCM IMA Radical");
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f4cf180716..379c5f7b81 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -608,6 +608,7 @@ extern AVCodec ff_adpcm_ima_dk4_decoder;
 extern AVCodec ff_adpcm_ima_ea_eacs_decoder;
 extern AVCodec ff_adpcm_ima_ea_sead_decoder;
 extern AVCodec ff_adpcm_ima_iss_decoder;
+extern AVCodec ff_adpcm_ima_mtf_decoder;
 extern AVCodec ff_adpcm_ima_oki_decoder;
 extern AVCodec ff_adpcm_ima_qt_encoder;
 extern AVCodec ff_adpcm_ima_qt_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index aca3825fd3..9ac97a122b 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -553,6 +553,7 @@ enum AVCodecID {
     AV_CODEC_ID_ADPCM_ZORK,
     AV_CODEC_ID_ADPCM_IMA_APM,
     AV_CODEC_ID_ADPCM_IMA_ALP,
+    AV_CODEC_ID_ADPCM_IMA_MTF,
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 0f5ddd9a9f..df3671765a 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2332,6 +2332,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA High Voltage Software ALP"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_ADPCM_IMA_MTF,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_ima_mtf",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Capcom's MT Framework"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
-- 
2.17.1



More information about the ffmpeg-devel mailing list