diff mbox series

[FFmpeg-devel,5/6] Add ADPCM IMA CRYO APC encoder

Message ID 44758a073268659c5c454ce922362669bed15b11.camel@haerdin.se
State New
Headers show
Series [FFmpeg-devel,1/6] doc/general_contents.texi: Add missing ADPCM IMA APC entry | expand

Checks

Context Check Description
yinshiyou/configure_loongarch64 warning Failed to apply patch
andriy/configure_x86 warning Failed to apply patch

Commit Message

Tomas Härdin Dec. 26, 2023, 3:53 p.m. UTC
Hopefully I got the testing right
diff mbox series

Patch

From 047ba1051d5e03b2a54d2aad514dd4501750bc71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= <git@haerdin.se>
Date: Tue, 26 Dec 2023 14:32:20 +0100
Subject: [PATCH 5/6] Add ADPCM IMA CRYO APC encoder

No trellis quantization yet
---
 Changelog                      |  1 +
 doc/general_contents.texi      |  2 +-
 libavcodec/adpcmenc.c          | 33 +++++++++++++++++++++++++++++++++
 libavcodec/allcodecs.c         |  1 +
 libavcodec/version.h           |  2 +-
 tests/fate/acodec.mak          |  2 ++
 tests/ref/acodec/adpcm-ima_apc |  4 ++++
 7 files changed, 43 insertions(+), 2 deletions(-)
 create mode 100644 tests/ref/acodec/adpcm-ima_apc

diff --git a/Changelog b/Changelog
index 344bf4d1cf..38ad342e09 100644
--- a/Changelog
+++ b/Changelog
@@ -4,6 +4,7 @@  releases are sorted from youngest to oldest.
 version <next>:
 - LEAD MCMP decoder
 - CRYO APC muxer
+- ADPCM IMA APC encoder
 
 version 6.1:
 - libaribcaption decoder
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index a43736e3a8..f02ea89b54 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -1169,7 +1169,7 @@  following image formats are supported:
 @item ADPCM IMA Acorn Replay @tab     @tab  X
 @item ADPCM IMA AMV          @tab  X  @tab  X
     @tab Used in AMV files
-@item ADPCM IMA APC          @tab     @tab  X
+@item ADPCM IMA APC          @tab  X  @tab  X
     @tab Codec used in games by Cryo Interactive
 @item ADPCM IMA Cunning Developments  @tab     @tab  X
 @item ADPCM IMA Electronic Arts EACS  @tab     @tab  X
diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c
index 63afffc58f..47dbec41fa 100644
--- a/libavcodec/adpcmenc.c
+++ b/libavcodec/adpcmenc.c
@@ -74,6 +74,7 @@  typedef struct ADPCMEncodeContext {
     TrellisNode *node_buf;
     TrellisNode **nodep_buf;
     uint8_t *trellis_hash;
+    int extradata_updated;
 } ADPCMEncodeContext;
 
 #define FREEZE_INTERVAL 128
@@ -157,6 +158,15 @@  static av_cold int adpcm_encode_init(AVCodecContext *avctx)
             bytestream_put_le16(&extradata, ff_adpcm_AdaptCoeff2[i] * 4);
         }
         ) /* End of CASE */
+    CASE(ADPCM_IMA_APC,
+        if (avctx->trellis) {
+            av_log(avctx, AV_LOG_ERROR, "trellis encoding not implemented for CRYO APC\n");
+            return AVERROR_PATCHWELCOME;
+        }
+        //extradata will be output in adpcm_encode_frame()
+        avctx->frame_size  = s->block_size * 2 / channels;
+        avctx->block_align = s->block_size;
+        ) /* End of CASE */
     CASE(ADPCM_YAMAHA,
         avctx->frame_size  = s->block_size * 2 / channels;
         avctx->block_align = s->block_size;
@@ -622,6 +632,28 @@  static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
     dst = avpkt->data;
 
     switch(avctx->codec->id) {
+    CASE(ADPCM_IMA_APC,
+        //initialize predictors using initial samples
+        if (!c->extradata_updated) {
+            uint8_t *side_data = av_packet_new_side_data(
+                avpkt, AV_PKT_DATA_NEW_EXTRADATA, 8);
+
+            if (!side_data) {
+                return AVERROR(ENOMEM);
+            }
+
+            for (int ch = 0; ch < channels; ch++) {
+                c->status[ch].prev_sample = samples[ch];
+                bytestream_put_le32(&side_data, c->status[ch].prev_sample);
+            }
+            c->extradata_updated = 1;
+        }
+        for (int i = 0; i < frame->nb_samples*channels/2; i++) {
+            uint8_t l = adpcm_ima_compress_sample(&c->status[0],  samples[2*i+0]);
+            uint8_t r = adpcm_ima_compress_sample(&c->status[st], samples[2*i+1]);
+            *dst++ = (l<<4) | r;
+        }
+        ) /* End of CASE */
     CASE(ADPCM_IMA_WAV,
         int blocks = (frame->nb_samples - 1) / 8;
 
@@ -1028,6 +1060,7 @@  ADPCM_ENCODER(ADPCM_IMA_QT,  adpcm_ima_qt,  sample_fmts_p, 0,
 ADPCM_ENCODER(ADPCM_IMA_SSI, adpcm_ima_ssi, sample_fmts,   AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Simon & Schuster Interactive")
 ADPCM_ENCODER(ADPCM_IMA_WAV, adpcm_ima_wav, sample_fmts_p, 0,                             "ADPCM IMA WAV")
 ADPCM_ENCODER(ADPCM_IMA_WS,  adpcm_ima_ws,  sample_fmts,   AV_CODEC_CAP_SMALL_LAST_FRAME, "ADPCM IMA Westwood")
+ADPCM_ENCODER(ADPCM_IMA_APC, adpcm_ima_apc, sample_fmts,   0,                             "ADPCM IMA CRYO APC")
 ADPCM_ENCODER(ADPCM_MS,      adpcm_ms,      sample_fmts,   0,                             "ADPCM Microsoft")
 ADPCM_ENCODER(ADPCM_SWF,     adpcm_swf,     sample_fmts,   0,                             "ADPCM Shockwave Flash")
 ADPCM_ENCODER(ADPCM_YAMAHA,  adpcm_yamaha,  sample_fmts,   0,                             "ADPCM Yamaha")
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 2662adb754..33bdd72d27 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -668,6 +668,7 @@  extern const FFCodec ff_adpcm_ima_amv_encoder;
 extern const FFCodec ff_adpcm_ima_alp_decoder;
 extern const FFCodec ff_adpcm_ima_alp_encoder;
 extern const FFCodec ff_adpcm_ima_apc_decoder;
+extern const FFCodec ff_adpcm_ima_apc_encoder;
 extern const FFCodec ff_adpcm_ima_apm_decoder;
 extern const FFCodec ff_adpcm_ima_apm_encoder;
 extern const FFCodec ff_adpcm_ima_cunning_decoder;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 2a08e42d7e..0ef6c991f3 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@ 
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR  33
+#define LIBAVCODEC_VERSION_MINOR  34
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak
index 7b09e3bd63..e7e3ae5ab8 100644
--- a/tests/fate/acodec.mak
+++ b/tests/fate/acodec.mak
@@ -48,6 +48,7 @@  fate-acodec-pcm-f%be: FMT = au
 
 FATE_ACODEC_ADPCM_RESAMPLE-$(call ENCDEC, ADPCM_ADX,  ADX)      += adx
 FATE_ACODEC_ADPCM_RESAMPLE-$(call ENCDEC, ADPCM_ARGO, ARGO_ASF) += argo
+FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_IMA_APC, APC)      += ima_apc
 FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_IMA_APM, APM)      += ima_apm
 FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_IMA_ALP, ALP)      += ima_alp
 FATE_ACODEC_ADPCM_RESAMPLE-$(call ENCDEC, ADPCM_IMA_QT,  AIFF)  += ima_qt
@@ -69,6 +70,7 @@  fate-acodec-adpcm-%: CODEC = adpcm_$(@:fate-acodec-adpcm-%=%)
 
 fate-acodec-adpcm-adx:     FMT = adx
 fate-acodec-adpcm-argo:    FMT = argo_asf
+fate-acodec-adpcm-ima_apc: FMT = apc
 fate-acodec-adpcm-ima_apm: FMT = apm
 fate-acodec-adpcm-ima_qt:  FMT = aiff
 fate-acodec-adpcm-ima_ssi: FMT = kvag
diff --git a/tests/ref/acodec/adpcm-ima_apc b/tests/ref/acodec/adpcm-ima_apc
new file mode 100644
index 0000000000..f168734c78
--- /dev/null
+++ b/tests/ref/acodec/adpcm-ima_apc
@@ -0,0 +1,4 @@ 
+45aca515c679bb0c315df766432d5630 *tests/data/fate/acodec-adpcm-ima_apc.apc
+265248 tests/data/fate/acodec-adpcm-ima_apc.apc
+03fc41cf61b7a160359147cd6363562a *tests/data/fate/acodec-adpcm-ima_apc.out.wav
+stddev:  904.04 PSNR: 37.21 MAXDIFF:34026 bytes:  1058400/  1060864
-- 
2.39.2