From 8a48d62c020d6361a0ae1d4a4124c0594ecfe669 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 25 Jan 2023 19:31:44 +0100 Subject: [PATCH 1/2] avcodec: add ADPCM XMD decoder Signed-off-by: Paul B Mahol --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 44 +++++++++++++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/codec_id.h | 1 + libavcodec/utils.c | 3 +++ 6 files changed, 57 insertions(+) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e691c8d180..286a0bf528 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -959,6 +959,7 @@ OBJS-$(CONFIG_ADPCM_THP_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_THP_LE_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_VIMA_DECODER) += vima.o adpcm_data.o OBJS-$(CONFIG_ADPCM_XA_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_XMD_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_ZORK_DECODER) += adpcm.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 841538b138..451696932d 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -324,6 +324,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_IMA_WAV: case AV_CODEC_ID_ADPCM_4XM: case AV_CODEC_ID_ADPCM_XA: + case AV_CODEC_ID_ADPCM_XMD: case AV_CODEC_ID_ADPCM_EA_R1: case AV_CODEC_ID_ADPCM_EA_R2: case AV_CODEC_ID_ADPCM_EA_R3: @@ -1043,6 +1044,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_XA: nb_samples = (buf_size / 128) * 224 / ch; break; + case AV_CODEC_ID_ADPCM_XMD: + nb_samples = buf_size / (21 * ch) * 32; + break; case AV_CODEC_ID_ADPCM_DTK: case AV_CODEC_ID_ADPCM_PSX: nb_samples = buf_size / (16 * ch) * 28; @@ -1553,6 +1557,45 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } bytestream2_seek(&gb, 0, SEEK_END); ) /* End of CASE */ + CASE(ADPCM_XMD, + int bytes_remaining, block = 0; + while (bytestream2_get_bytes_left(&gb) >= 21 * channels) { + for (int channel = 0; channel < channels; channel++) { + int16_t *out = samples_p[channel] + block * 32; + int16_t history[2]; + uint16_t scale; + + history[1] = sign_extend(bytestream2_get_le16(&gb), 16); + history[0] = sign_extend(bytestream2_get_le16(&gb), 16); + scale = bytestream2_get_le16(&gb); + + out[0] = history[1]; + out[1] = history[0]; + + for (int n = 0; n < 15; n++) { + unsigned byte = bytestream2_get_byte(&gb); + int32_t nibble[2]; + + nibble[0] = sign_extend(byte & 15, 4); + nibble[1] = sign_extend(byte >> 4, 4); + + out[2+n*2] = (nibble[0]*(scale<<14) + (history[0]*29336) - (history[1]*13136)) >> 14; + history[1] = history[0]; + history[0] = out[2+n*2]; + + out[2+n*2+1] = (nibble[1]*(scale<<14) + (history[0]*29336) - (history[1]*13136)) >> 14; + history[1] = history[0]; + history[0] = out[2+n*2+1]; + } + } + + block++; + } + bytes_remaining = bytestream2_get_bytes_left(&gb); + if (bytes_remaining > 0) { + bytestream2_skip(&gb, bytes_remaining); + } + ) /* End of CASE */ CASE(ADPCM_XA, int16_t *out0 = samples_p[0]; int16_t *out1 = samples_p[1]; @@ -2350,5 +2393,6 @@ ADPCM_DECODER(ADPCM_SWF, sample_fmts_s16, adpcm_swf, "ADPCM Sho ADPCM_DECODER(ADPCM_THP_LE, sample_fmts_s16p, adpcm_thp_le, "ADPCM Nintendo THP (little-endian)") ADPCM_DECODER(ADPCM_THP, sample_fmts_s16p, adpcm_thp, "ADPCM Nintendo THP") ADPCM_DECODER(ADPCM_XA, sample_fmts_s16p, adpcm_xa, "ADPCM CDROM XA") +ADPCM_DECODER(ADPCM_XMD, sample_fmts_s16p, adpcm_xmd, "ADPCM Konami XMD") ADPCM_DECODER(ADPCM_YAMAHA, sample_fmts_s16, adpcm_yamaha, "ADPCM Yamaha") ADPCM_DECODER(ADPCM_ZORK, sample_fmts_s16, adpcm_zork, "ADPCM Zork") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 74e1b00e96..95b8d935d3 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -696,6 +696,7 @@ extern const FFCodec ff_adpcm_thp_decoder; extern const FFCodec ff_adpcm_thp_le_decoder; extern const FFCodec ff_adpcm_vima_decoder; extern const FFCodec ff_adpcm_xa_decoder; +extern const FFCodec ff_adpcm_xmd_decoder; extern const FFCodec ff_adpcm_yamaha_encoder; extern const FFCodec ff_adpcm_yamaha_decoder; extern const FFCodec ff_adpcm_zork_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 6ecdf1002b..782a93218f 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2536,6 +2536,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Acorn Replay"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_XMD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_xmd", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Konami XMD"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ba3b432387..97d0aee86e 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -413,6 +413,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_CUNNING, AV_CODEC_ID_ADPCM_IMA_MOFLEX, AV_CODEC_ID_ADPCM_IMA_ACORN, + AV_CODEC_ID_ADPCM_XMD, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 808a7b8f5b..182ff64ee1 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -767,6 +767,9 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, case AV_CODEC_ID_ADPCM_MTAF: tmp = blocks * (ba - 16LL) * 2 / ch; break; + case AV_CODEC_ID_ADPCM_XMD: + tmp = blocks * 32; + break; } if (tmp) { if (tmp != (int)tmp) -- 2.39.1