[FFmpeg-devel] [PATCH 1/3] avcodec: add ADPCM IMA HVQM4 decoder

Paul B Mahol onemda at gmail.com
Sun Feb 13 21:51:29 EET 2022


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

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index cfc70a3eaf..150a734421 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -900,6 +900,7 @@ OBJS-$(CONFIG_ADPCM_IMA_DK3_DECODER)      += adpcm.o adpcm_data.o
 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_HVQM4_DECODER)    += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_MOFLEX_DECODER)   += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_MTF_DECODER)      += adpcm.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index cfde5f58b9..f453628786 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -523,6 +523,49 @@ static inline int adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble)
     return c->predictor;
 }
 
+static void decode_adpcm_ima_hvqm4(AVCodecContext *avctx, int16_t *outbuf, int samples_to_do,
+                                   int frame_format, GetByteContext *gb)
+{
+    ADPCMDecodeContext *c = avctx->priv_data;
+    int st = avctx->channels == 2;
+    unsigned tmp;
+
+    for (int ch = 0; ch < avctx->channels; ch++) {
+        switch (frame_format) {
+        case 1: /* combined hist+index */
+            tmp = bytestream2_get_be16(gb);
+            c->status[ch].predictor  = sign_extend(tmp & 0xFF80, 16);
+            c->status[ch].step_index = tmp & 0x7f;
+            break;
+        case 2:  /* no hist/index (continues from previous frame) */
+        default:
+            break;
+        case 3: /* separate hist+index */
+            tmp = bytestream2_get_be16(gb);
+            c->status[ch].predictor  = sign_extend(tmp, 16);
+            c->status[ch].step_index = bytestream2_get_byte(gb);
+            break;
+        }
+
+        c->status[ch].step_index = av_clip(c->status[ch].step_index, 0, 88);
+    }
+
+    if (frame_format == 1 || frame_format == 3) {
+        for (int ch = 0; ch < avctx->channels; ch++)
+            *outbuf++ = (int16_t)c->status[st - ch].predictor;
+        samples_to_do--;
+    }
+
+    for (int i = 0; i < samples_to_do; i++) {
+        uint8_t nibble = bytestream2_get_byte(gb);
+
+        *outbuf++ = adpcm_ima_qt_expand_nibble(&c->status[st], nibble & 0xF);
+        *outbuf++ = adpcm_ima_qt_expand_nibble(&c->status[ 0], nibble >>  4);
+    }
+
+    bytestream2_seek(gb, 0, SEEK_END);
+}
+
 static inline int16_t adpcm_ms_expand_nibble(ADPCMChannelStatus *c, int nibble)
 {
     int predictor;
@@ -910,6 +953,20 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
         *coded_samples -= *coded_samples % 28;
         nb_samples      = (buf_size - 12) / 30 * 28;
         break;
+    case AV_CODEC_ID_ADPCM_IMA_HVQM4:
+        {
+            int frame_format = bytestream2_get_be16(gb);
+            int skip = 6;
+
+            if (frame_format == 1)
+                skip += 2 * ch;
+            if (frame_format == 3)
+                skip += 3 * ch;
+
+            nb_samples = (buf_size - skip) * 2 / ch;
+            bytestream2_seek(gb, 0, SEEK_SET);
+        }
+        break;
     case AV_CODEC_ID_ADPCM_IMA_EA_EACS:
         has_coded_samples = 1;
         *coded_samples = bytestream2_get_le32(gb);
@@ -1453,6 +1510,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
             *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
         }
         ) /* End of CASE */
+    CASE(ADPCM_IMA_HVQM4,
+        int format = bytestream2_get_be16(&gb);
+
+        bytestream2_skip(&gb, 4);
+        decode_adpcm_ima_hvqm4(avctx, samples, nb_samples, format, &gb);
+        ) /* End of CASE */
     CASE(ADPCM_IMA_SSI,
         for (int n = nb_samples >> (1 - st); n > 0; n--) {
             int v = bytestream2_get_byteu(&gb);
@@ -2322,6 +2385,7 @@ ADPCM_DECODER(ADPCM_IMA_DK3,     sample_fmts_s16,  adpcm_ima_dk3,     "ADPCM IMA
 ADPCM_DECODER(ADPCM_IMA_DK4,     sample_fmts_s16,  adpcm_ima_dk4,     "ADPCM IMA Duck DK4")
 ADPCM_DECODER(ADPCM_IMA_EA_EACS, sample_fmts_s16,  adpcm_ima_ea_eacs, "ADPCM IMA Electronic Arts EACS")
 ADPCM_DECODER(ADPCM_IMA_EA_SEAD, sample_fmts_s16,  adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD")
+ADPCM_DECODER(ADPCM_IMA_HVQM4,   sample_fmts_s16,  adpcm_ima_hvqm4,   "ADPCM IMA HVQM4")
 ADPCM_DECODER(ADPCM_IMA_ISS,     sample_fmts_s16,  adpcm_ima_iss,     "ADPCM IMA Funcom ISS")
 ADPCM_DECODER(ADPCM_IMA_MOFLEX,  sample_fmts_s16p, adpcm_ima_moflex,  "ADPCM IMA MobiClip MOFLEX")
 ADPCM_DECODER(ADPCM_IMA_MTF,     sample_fmts_s16,  adpcm_ima_mtf,     "ADPCM IMA Capcom's MT Framework")
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index d1e10197de..89ba205a2f 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -642,6 +642,7 @@ extern const AVCodec ff_adpcm_ima_dk3_decoder;
 extern const AVCodec ff_adpcm_ima_dk4_decoder;
 extern const AVCodec ff_adpcm_ima_ea_eacs_decoder;
 extern const AVCodec ff_adpcm_ima_ea_sead_decoder;
+extern const AVCodec ff_adpcm_ima_hvqm4_decoder;
 extern const AVCodec ff_adpcm_ima_iss_decoder;
 extern const AVCodec ff_adpcm_ima_moflex_decoder;
 extern const AVCodec ff_adpcm_ima_mtf_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 0974ee03de..6deba785dc 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2475,6 +2475,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Acorn Replay"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_ADPCM_IMA_HVQM4,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_ima_hvqm4",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM4"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index ab265ec584..f3f262ec75 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -401,6 +401,7 @@ enum AVCodecID {
     AV_CODEC_ID_ADPCM_IMA_CUNNING,
     AV_CODEC_ID_ADPCM_IMA_MOFLEX,
     AV_CODEC_ID_ADPCM_IMA_ACORN,
+    AV_CODEC_ID_ADPCM_IMA_HVQM4,
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
-- 
2.33.0



More information about the ffmpeg-devel mailing list