aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorZane van Iperen <zane@zanevaniperen.com>2020-01-26 03:36:50 +0000
committerPaul B Mahol <onemda@gmail.com>2020-01-26 10:23:54 +0100
commitbf890ae0d7803492a729c2c8f2a5c907ade2a9f8 (patch)
treed6c58c078376c986aa74618930e26edaf13437dd /libavcodec
parent15d160cc0b23f531a3f7f3f4c9eb463b179227f3 (diff)
downloadffmpeg-bf890ae0d7803492a729c2c8f2a5c907ade2a9f8.tar.gz
avcodec: add decoder for argonaut games' adpcm codec
Adds support for the ADPCM variant used by some Argonaut Games' games, such as 'Croc! Legend of the Gobbos', and 'Croc 2'. Signed-off-by: Zane van Iperen <zane@zanevaniperen.com>
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/Makefile1
-rw-r--r--libavcodec/adpcm.c67
-rw-r--r--libavcodec/allcodecs.c1
-rw-r--r--libavcodec/avcodec.h1
-rw-r--r--libavcodec/codec_desc.c7
-rw-r--r--libavcodec/version.h4
6 files changed, 79 insertions, 2 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index c1f35b40d8..a2fbb910a0 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -817,6 +817,7 @@ OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o
OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_AGM_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_AICA_DECODER) += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_ARGO_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_DTK_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index ed16438e33..dad3da28d3 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -12,6 +12,7 @@
* EA ADPCM XAS decoder by Peter Ross (pross@xvid.org)
* MAXIS EA ADPCM decoder by Robert Marston (rmarston@gmail.com)
* THP ADPCM decoder by Marco Gerards (mgerards@xs4all.nl)
+ * Argonaut Games ADPCM decoder by Zane van Iperen (zane@zanevaniperen.com)
*
* This file is part of FFmpeg.
*
@@ -148,6 +149,10 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
if (avctx->extradata && avctx->extradata_size >= 2)
c->vqa_version = AV_RL16(avctx->extradata);
break;
+ case AV_CODEC_ID_ADPCM_ARGO:
+ if (avctx->bits_per_coded_sample != 4)
+ return AVERROR_INVALIDDATA;
+ break;
default:
break;
}
@@ -169,6 +174,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
case AV_CODEC_ID_ADPCM_DTK:
case AV_CODEC_ID_ADPCM_PSX:
case AV_CODEC_ID_ADPCM_MTAF:
+ case AV_CODEC_ID_ADPCM_ARGO:
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
break;
case AV_CODEC_ID_ADPCM_IMA_WS:
@@ -546,6 +552,11 @@ static void adpcm_swf_decode(AVCodecContext *avctx, const uint8_t *buf, int buf_
}
}
+static inline int16_t adpcm_argo_expand_nibble(int nibble, int shift, int16_t prev0, int16_t prev1)
+{
+ return ((8 * prev0) - (4 * prev1) + (nibble * (1 << shift))) >> 2;
+}
+
/**
* Get the number of samples that will be decoded from the packet.
* In one case, this is actually the maximum number of samples possible to
@@ -584,6 +595,11 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
return 0;
nb_samples = 64;
break;
+ case AV_CODEC_ID_ADPCM_ARGO:
+ if (buf_size < 17 * ch)
+ return 0;
+ nb_samples = 32;
+ break;
/* simple 4-bit adpcm */
case AV_CODEC_ID_ADPCM_CT:
case AV_CODEC_ID_ADPCM_IMA_APC:
@@ -1770,7 +1786,57 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
}
break;
+ case AV_CODEC_ID_ADPCM_ARGO:
+ /*
+ * The format of each block:
+ * uint8_t left_control;
+ * uint4_t left_samples[nb_samples];
+ * ---- and if stereo ----
+ * uint8_t right_control;
+ * uint4_t right_samples[nb_samples];
+ *
+ * Format of the control byte:
+ * MSB [SSSSDRRR] LSB
+ * S = (Shift Amount - 2)
+ * D = Decoder flag.
+ * R = Reserved
+ *
+ * Each block relies on the previous two samples of each channel.
+ * They should be 0 initially.
+ */
+ for (channel = 0; channel < avctx->channels; channel++) {
+ int control, shift, sample, nibble;
+
+ samples = samples_p[channel];
+ cs = c->status + channel;
+ /* Get the control byte and decode the samples, 2 at a time. */
+ control = bytestream2_get_byteu(&gb);
+ shift = (control >> 4) + 2;
+
+ for (n = 0; n < nb_samples / 2; n++) {
+ sample = bytestream2_get_byteu(&gb);
+
+ nibble = sign_extend(sample >> 4, 4);
+ if (control & 0x04)
+ *samples = adpcm_argo_expand_nibble(nibble, shift, cs->sample1, cs->sample2);
+ else
+ *samples = adpcm_argo_expand_nibble(nibble, shift, cs->sample1, cs->sample1);
+
+ cs->sample2 = cs->sample1;
+ cs->sample1 = *samples++;
+
+ nibble = sign_extend(sample >> 0, 4);
+ if (control & 0x04)
+ *samples = adpcm_argo_expand_nibble(nibble, shift, cs->sample1, cs->sample2);
+ else
+ *samples = adpcm_argo_expand_nibble(nibble, shift, cs->sample1, cs->sample1);
+
+ cs->sample2 = cs->sample1;
+ cs->sample1 = *samples++;
+ }
+ }
+ break;
default:
av_assert0(0); // unsupported codec_id should not happen
}
@@ -1824,6 +1890,7 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_4XM, sample_fmts_s16p, adpcm_4xm,
ADPCM_DECODER(AV_CODEC_ID_ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_AGM, sample_fmts_s16, adpcm_agm, "ADPCM AmuseGraphics Movie");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_AICA, sample_fmts_s16p, adpcm_aica, "ADPCM Yamaha AICA");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_ARGO, sample_fmts_s16p, adpcm_argo, "ADPCM Argonaut Games");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts");
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index ec7366144f..01a083d06b 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -582,6 +582,7 @@ extern AVCodec ff_adpcm_adx_decoder;
extern AVCodec ff_adpcm_afc_decoder;
extern AVCodec ff_adpcm_agm_decoder;
extern AVCodec ff_adpcm_aica_decoder;
+extern AVCodec ff_adpcm_argo_decoder;
extern AVCodec ff_adpcm_ct_decoder;
extern AVCodec ff_adpcm_dtk_decoder;
extern AVCodec ff_adpcm_ea_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 774ed1e641..0e7ca1db4d 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -545,6 +545,7 @@ enum AVCodecID {
AV_CODEC_ID_ADPCM_IMA_DAT4,
AV_CODEC_ID_ADPCM_MTAF,
AV_CODEC_ID_ADPCM_AGM,
+ AV_CODEC_ID_ADPCM_ARGO,
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 529b838e5b..32f573d58c 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2297,6 +2297,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("ADPCM AmuseGraphics Movie AGM"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_ADPCM_ARGO,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_argo",
+ .long_name = NULL_IF_CONFIG_SMALL("ADPCM Argonaut Games"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
/* AMR */
{
diff --git a/libavcodec/version.h b/libavcodec/version.h
index b438a09d6d..2fba26e8d0 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 66
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR 67
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \