diff mbox series

[FFmpeg-devel,1/4] avcodec: add ADPCM IMA MOFLEX decoder

Message ID 20200828214833.27650-1-onemda@gmail.com
State Superseded
Headers show
Series [FFmpeg-devel,1/4] avcodec: add ADPCM IMA MOFLEX decoder
Related show

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Paul B Mahol Aug. 28, 2020, 9:48 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavcodec/Makefile     |  1 +
 libavcodec/adpcm.c      | 26 ++++++++++++++++++++++++++
 libavcodec/allcodecs.c  |  1 +
 libavcodec/codec_desc.c |  7 +++++++
 libavcodec/codec_id.h   |  1 +
 libavcodec/utils.c      |  2 ++
 6 files changed, 38 insertions(+)
diff mbox series

Patch

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index ca2e8a2530..191c4e0a7c 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -866,6 +866,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_MOFLEX_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
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 1366932352..71e37efde7 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -210,6 +210,7 @@  static av_cold int adpcm_decode_init(AVCodecContext * avctx)
     case AV_CODEC_ID_ADPCM_PSX:
     case AV_CODEC_ID_ADPCM_MTAF:
     case AV_CODEC_ID_ADPCM_ARGO:
+    case AV_CODEC_ID_ADPCM_IMA_MOFLEX:
         avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
         break;
     case AV_CODEC_ID_ADPCM_IMA_WS:
@@ -774,6 +775,7 @@  static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
         case AV_CODEC_ID_ADPCM_4XM:
         case AV_CODEC_ID_ADPCM_AGM:
         case AV_CODEC_ID_ADPCM_IMA_DAT4:
+        case AV_CODEC_ID_ADPCM_IMA_MOFLEX:
         case AV_CODEC_ID_ADPCM_IMA_ISS:     header_size = 4 * ch;      break;
         case AV_CODEC_ID_ADPCM_IMA_AMV:     header_size = 8;           break;
         case AV_CODEC_ID_ADPCM_IMA_SMJPEG:  header_size = 4 * ch;      break;
@@ -1298,6 +1300,29 @@  static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
             *samples++ = adpcm_ima_expand_nibble(&c->status[st], v2, 3);
         }
         break;
+    case AV_CODEC_ID_ADPCM_IMA_MOFLEX:
+        for (channel = 0; channel < avctx->channels; channel++) {
+            cs = &c->status[channel];
+            cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16);
+            cs->predictor  = sign_extend(bytestream2_get_le16u(&gb), 16);
+            if (cs->step_index > 88u){
+                av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n",
+                       channel, cs->step_index);
+                return AVERROR_INVALIDDATA;
+            }
+        }
+
+        for (int subframe = 0; subframe < nb_samples / 256; subframe++) {
+            for (channel = 0; channel < avctx->channels; channel++) {
+                samples = samples_p[channel] + 256 * subframe;
+                for (n = 0; n < 256; n += 2) {
+                    int v = bytestream2_get_byteu(&gb);
+                    *samples++ = adpcm_ima_expand_nibble(&c->status[channel], v & 0x0F, 3);
+                    *samples++ = adpcm_ima_expand_nibble(&c->status[channel], v >> 4  , 3);
+                }
+            }
+        }
+        break;
     case AV_CODEC_ID_ADPCM_IMA_DAT4:
         for (channel = 0; channel < avctx->channels; channel++) {
             cs = &c->status[channel];
@@ -2107,6 +2132,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_MOFLEX,  sample_fmts_s16p, adpcm_ima_moflex,  "ADPCM IMA MobiClip MOFLEX");
 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");
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 729d2fd9ad..084a289c9e 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -619,6 +619,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_moflex_decoder;
 extern AVCodec ff_adpcm_ima_mtf_decoder;
 extern AVCodec ff_adpcm_ima_oki_decoder;
 extern AVCodec ff_adpcm_ima_qt_encoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 0ae6aee63b..b5bc5c3c71 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2376,6 +2376,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Cunning Developments"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_ADPCM_IMA_MOFLEX,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_ima_moflex",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA MobiClip MOFLEX"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 896ecb0ce0..aac1174f28 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -388,6 +388,7 @@  enum AVCodecID {
     AV_CODEC_ID_ADPCM_IMA_ALP,
     AV_CODEC_ID_ADPCM_IMA_MTF,
     AV_CODEC_ID_ADPCM_IMA_CUNNING,
+    AV_CODEC_ID_ADPCM_IMA_MOFLEX,
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 14cb5cf1aa..187ce230b8 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -1664,6 +1664,8 @@  static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba,
         if (ch > 0 && ch < INT_MAX/16) {
             /* calc from frame_bytes and channels */
             switch (id) {
+            case AV_CODEC_ID_ADPCM_IMA_MOFLEX:
+                return (frame_bytes - 4 * ch) / (128 * ch) * 256;
             case AV_CODEC_ID_ADPCM_AFC:
                 return frame_bytes / (9 * ch) * 16;
             case AV_CODEC_ID_ADPCM_PSX: