diff options
author | Zane van Iperen <zane@zanevaniperen.com> | 2020-01-26 03:36:50 +0000 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2020-01-26 10:23:54 +0100 |
commit | bf890ae0d7803492a729c2c8f2a5c907ade2a9f8 (patch) | |
tree | d6c58c078376c986aa74618930e26edaf13437dd /libavcodec | |
parent | 15d160cc0b23f531a3f7f3f4c9eb463b179227f3 (diff) | |
download | ffmpeg-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/Makefile | 1 | ||||
-rw-r--r-- | libavcodec/adpcm.c | 67 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 1 | ||||
-rw-r--r-- | libavcodec/codec_desc.c | 7 | ||||
-rw-r--r-- | libavcodec/version.h | 4 |
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, \ |