[FFmpeg-cvslog] avcodec: add ADPCM XMD decoder

Paul B Mahol git at videolan.org
Mon Jan 30 22:05:20 EET 2023


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Wed Jan 25 19:31:44 2023 +0100| [280e6e93fc96afbbb73f1987eb3d603f8949ea30] | committer: Paul B Mahol

avcodec: add ADPCM XMD decoder

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=280e6e93fc96afbbb73f1987eb3d603f8949ea30
---

 Changelog               |  1 +
 libavcodec/Makefile     |  1 +
 libavcodec/adpcm.c      | 44 ++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/allcodecs.c  |  1 +
 libavcodec/codec_desc.c |  7 +++++++
 libavcodec/codec_id.h   |  1 +
 libavcodec/utils.c      |  3 +++
 libavcodec/version.h    |  2 +-
 8 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/Changelog b/Changelog
index a0f1ad7211..a0ba25257d 100644
--- a/Changelog
+++ b/Changelog
@@ -34,6 +34,7 @@ version <next>:
 - ssim360 video filter
 - ffmpeg CLI new options: -enc_stats_pre[_fmt], -enc_stats_post[_fmt]
 - hstack_vaapi, vstack_vaapi and xstack_vaapi filters
+- XMD ADPCM decoder
 
 
 version 5.1:
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index f0ffd0b961..629933d85c 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -959,6 +959,7 @@ OBJS-$(CONFIG_ADPCM_THP_DECODER)          += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_THP_LE_DECODER)       += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_VIMA_DECODER)         += vima.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_XA_DECODER)           += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_XMD_DECODER)          += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER)       += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER)       += adpcmenc.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_ZORK_DECODER)         += adpcm.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 841538b138..451696932d 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -324,6 +324,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
     case AV_CODEC_ID_ADPCM_IMA_WAV:
     case AV_CODEC_ID_ADPCM_4XM:
     case AV_CODEC_ID_ADPCM_XA:
+    case AV_CODEC_ID_ADPCM_XMD:
     case AV_CODEC_ID_ADPCM_EA_R1:
     case AV_CODEC_ID_ADPCM_EA_R2:
     case AV_CODEC_ID_ADPCM_EA_R3:
@@ -1043,6 +1044,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
     case AV_CODEC_ID_ADPCM_XA:
         nb_samples = (buf_size / 128) * 224 / ch;
         break;
+    case AV_CODEC_ID_ADPCM_XMD:
+        nb_samples = buf_size / (21 * ch) * 32;
+        break;
     case AV_CODEC_ID_ADPCM_DTK:
     case AV_CODEC_ID_ADPCM_PSX:
         nb_samples = buf_size / (16 * ch) * 28;
@@ -1553,6 +1557,45 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame,
         }
         bytestream2_seek(&gb, 0, SEEK_END);
         ) /* End of CASE */
+    CASE(ADPCM_XMD,
+        int bytes_remaining, block = 0;
+        while (bytestream2_get_bytes_left(&gb) >= 21 * channels) {
+            for (int channel = 0; channel < channels; channel++) {
+                int16_t *out = samples_p[channel] + block * 32;
+                int16_t history[2];
+                uint16_t scale;
+
+                history[1] = sign_extend(bytestream2_get_le16(&gb), 16);
+                history[0] = sign_extend(bytestream2_get_le16(&gb), 16);
+                scale = bytestream2_get_le16(&gb);
+
+                out[0] = history[1];
+                out[1] = history[0];
+
+                for (int n = 0; n < 15; n++) {
+                    unsigned byte = bytestream2_get_byte(&gb);
+                    int32_t nibble[2];
+
+                    nibble[0] = sign_extend(byte & 15, 4);
+                    nibble[1] = sign_extend(byte >> 4, 4);
+
+                    out[2+n*2] = (nibble[0]*(scale<<14) + (history[0]*29336) - (history[1]*13136)) >> 14;
+                    history[1] = history[0];
+                    history[0] = out[2+n*2];
+
+                    out[2+n*2+1] = (nibble[1]*(scale<<14) + (history[0]*29336) - (history[1]*13136)) >> 14;
+                    history[1] = history[0];
+                    history[0] = out[2+n*2+1];
+                }
+            }
+
+            block++;
+        }
+        bytes_remaining = bytestream2_get_bytes_left(&gb);
+        if (bytes_remaining > 0) {
+            bytestream2_skip(&gb, bytes_remaining);
+        }
+        ) /* End of CASE */
     CASE(ADPCM_XA,
         int16_t *out0 = samples_p[0];
         int16_t *out1 = samples_p[1];
@@ -2350,5 +2393,6 @@ ADPCM_DECODER(ADPCM_SWF,         sample_fmts_s16,  adpcm_swf,         "ADPCM Sho
 ADPCM_DECODER(ADPCM_THP_LE,      sample_fmts_s16p, adpcm_thp_le,      "ADPCM Nintendo THP (little-endian)")
 ADPCM_DECODER(ADPCM_THP,         sample_fmts_s16p, adpcm_thp,         "ADPCM Nintendo THP")
 ADPCM_DECODER(ADPCM_XA,          sample_fmts_s16p, adpcm_xa,          "ADPCM CDROM XA")
+ADPCM_DECODER(ADPCM_XMD,         sample_fmts_s16p, adpcm_xmd,         "ADPCM Konami XMD")
 ADPCM_DECODER(ADPCM_YAMAHA,      sample_fmts_s16,  adpcm_yamaha,      "ADPCM Yamaha")
 ADPCM_DECODER(ADPCM_ZORK,        sample_fmts_s16,  adpcm_zork,        "ADPCM Zork")
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f30047e17a..0deaea65b3 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -695,6 +695,7 @@ extern const FFCodec ff_adpcm_thp_decoder;
 extern const FFCodec ff_adpcm_thp_le_decoder;
 extern const FFCodec ff_adpcm_vima_decoder;
 extern const FFCodec ff_adpcm_xa_decoder;
+extern const FFCodec ff_adpcm_xmd_decoder;
 extern const FFCodec ff_adpcm_yamaha_encoder;
 extern const FFCodec ff_adpcm_yamaha_decoder;
 extern const FFCodec ff_adpcm_zork_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 50f9794e10..fbb6604f76 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2536,6 +2536,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_XMD,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_xmd",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM Konami XMD"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index cdf7eb79c3..3e84098f35 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -413,6 +413,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_XMD,
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 94f7ae6877..18a433b1af 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -769,6 +769,9 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba,
                 case AV_CODEC_ID_ADPCM_MTAF:
                     tmp = blocks * (ba - 16LL) * 2 / ch;
                     break;
+                case AV_CODEC_ID_ADPCM_XMD:
+                    tmp = blocks * 32;
+                    break;
                 }
                 if (tmp) {
                     if (tmp != (int)tmp)
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 752adc81f8..2ed4ef5547 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR  59
+#define LIBAVCODEC_VERSION_MINOR  60
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \



More information about the ffmpeg-cvslog mailing list