From 32cc6a96f80b5406e8327d912c8fc38812e6a664 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= <tjoppen@acc.umu.se>
Date: Fri, 23 Nov 2018 15:15:02 +0100
Subject: [PATCH 3/3] Add ADPCM IMA CRYO APC encoder

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

diff --git a/Changelog b/Changelog
index f678feed65..e6ae0c1187 100644
--- a/Changelog
+++ b/Changelog
@@ -11,6 +11,7 @@ version <next>:
 - dhav demuxer
 - PCM-DVD encoder
 - CRYO APC muxer
+- ADPCM IMA CRYO APC encoder
 
 
 version 4.1:
diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c
index 668939c778..0d757d5b46 100644
--- a/libavcodec/adpcmenc.c
+++ b/libavcodec/adpcmenc.c
@@ -54,6 +54,7 @@ typedef struct ADPCMEncodeContext {
     TrellisNode *node_buf;
     TrellisNode **nodep_buf;
     uint8_t *trellis_hash;
+    int extradata_updated;
 } ADPCMEncodeContext;
 
 #define FREEZE_INTERVAL 128
@@ -124,6 +125,15 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx)
             bytestream_put_le16(&extradata, ff_adpcm_AdaptCoeff2[i] * 4);
         }
         break;
+    case AV_CODEC_ID_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  = BLKSIZE * 2 / avctx->channels;
+        avctx->block_align = BLKSIZE;
+        break;
     case AV_CODEC_ID_ADPCM_YAMAHA:
         avctx->frame_size  = BLKSIZE * 2 / avctx->channels;
         avctx->block_align = BLKSIZE;
@@ -491,6 +501,28 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
     dst = avpkt->data;
 
     switch(avctx->codec->id) {
+    case AV_CODEC_ID_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 (ch = 0; ch < avctx->channels; ch++) {
+                c->status[ch].prev_sample = samples[ch];
+                bytestream_put_le32(&side_data, c->status[ch].prev_sample);
+            }
+            c->extradata_updated = 1;
+        }
+        for (i = 0; i < frame->nb_samples*avctx->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;
+        }
+        break;
     case AV_CODEC_ID_ADPCM_IMA_WAV:
     {
         int blocks, j;
@@ -721,6 +753,7 @@ AVCodec ff_ ## name_ ## _encoder = {                        \
 
 ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_QT,  adpcm_ima_qt,  sample_fmts_p, "ADPCM IMA QuickTime");
 ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav, sample_fmts_p, "ADPCM IMA WAV");
+ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_APC, adpcm_ima_apc, sample_fmts,   "ADPCM IMA CRYO APC");
 ADPCM_ENCODER(AV_CODEC_ID_ADPCM_MS,      adpcm_ms,      sample_fmts,   "ADPCM Microsoft");
 ADPCM_ENCODER(AV_CODEC_ID_ADPCM_SWF,     adpcm_swf,     sample_fmts,   "ADPCM Shockwave Flash");
 ADPCM_ENCODER(AV_CODEC_ID_ADPCM_YAMAHA,  adpcm_yamaha,  sample_fmts,   "ADPCM Yamaha");
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index d70646e91a..873f236531 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -586,6 +586,7 @@ extern AVCodec ff_adpcm_g726_decoder;
 extern AVCodec ff_adpcm_g726le_encoder;
 extern AVCodec ff_adpcm_g726le_decoder;
 extern AVCodec ff_adpcm_ima_amv_decoder;
+extern AVCodec ff_adpcm_ima_apc_encoder;
 extern AVCodec ff_adpcm_ima_apc_decoder;
 extern AVCodec ff_adpcm_ima_dat4_decoder;
 extern AVCodec ff_adpcm_ima_dk3_decoder;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index f758093582..5677a7feba 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,8 +28,8 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  58
-#define LIBAVCODEC_VERSION_MINOR  41
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR  42
+#define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak
index 80d26de0f9..69bfa6940e 100644
--- a/tests/fate/acodec.mak
+++ b/tests/fate/acodec.mak
@@ -45,6 +45,7 @@ fate-acodec-pcm-u%le: FMT = nut
 fate-acodec-pcm-f%be: FMT = au
 
 FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_ADX,     ADX)  += adx
+FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_IMA_APC, APC)  += ima_apc
 FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_IMA_QT,  AIFF) += ima_qt
 FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_IMA_WAV, WAV)  += ima_wav
 FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_MS,      WAV)  += ms
@@ -58,6 +59,7 @@ fate-acodec-adpcm: $(FATE_ACODEC_ADPCM)
 fate-acodec-adpcm-%: CODEC = adpcm_$(@:fate-acodec-adpcm-%=%)
 
 fate-acodec-adpcm-adx:     FMT = adx
+fate-acodec-adpcm-ima_apc: FMT = apc
 fate-acodec-adpcm-ima_qt:  FMT = aiff
 fate-acodec-adpcm-ima_wav: FMT = wav
 fate-acodec-adpcm-ms:      FMT = wav
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.11.0

