Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 64 +++++++++++++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++ libavcodec/codec_id.h | 1 + 5 files changed, 74 insertions(+)
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index cfc70a3eaf..150a734421 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -900,6 +900,7 @@ OBJS-$(CONFIG_ADPCM_IMA_DK3_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_DK4_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_EA_EACS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_EA_SEAD_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_HVQM4_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_MOFLEX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_MTF_DECODER) += adpcm.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index cfde5f58b9..f453628786 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -523,6 +523,49 @@ static inline int adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble) return c->predictor; } +static void decode_adpcm_ima_hvqm4(AVCodecContext *avctx, int16_t *outbuf, int samples_to_do, + int frame_format, GetByteContext *gb) +{ + ADPCMDecodeContext *c = avctx->priv_data; + int st = avctx->channels == 2; + unsigned tmp; + + for (int ch = 0; ch < avctx->channels; ch++) { + switch (frame_format) { + case 1: /* combined hist+index */ + tmp = bytestream2_get_be16(gb); + c->status[ch].predictor = sign_extend(tmp & 0xFF80, 16); + c->status[ch].step_index = tmp & 0x7f; + break; + case 2: /* no hist/index (continues from previous frame) */ + default: + break; + case 3: /* separate hist+index */ + tmp = bytestream2_get_be16(gb); + c->status[ch].predictor = sign_extend(tmp, 16); + c->status[ch].step_index = bytestream2_get_byte(gb); + break; + } + + c->status[ch].step_index = av_clip(c->status[ch].step_index, 0, 88); + } + + if (frame_format == 1 || frame_format == 3) { + for (int ch = 0; ch < avctx->channels; ch++) + *outbuf++ = (int16_t)c->status[st - ch].predictor; + samples_to_do--; + } + + for (int i = 0; i < samples_to_do; i++) { + uint8_t nibble = bytestream2_get_byte(gb); + + *outbuf++ = adpcm_ima_qt_expand_nibble(&c->status[st], nibble & 0xF); + *outbuf++ = adpcm_ima_qt_expand_nibble(&c->status[ 0], nibble >> 4); + } + + bytestream2_seek(gb, 0, SEEK_END); +} + static inline int16_t adpcm_ms_expand_nibble(ADPCMChannelStatus *c, int nibble) { int predictor; @@ -910,6 +953,20 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, *coded_samples -= *coded_samples % 28; nb_samples = (buf_size - 12) / 30 * 28; break; + case AV_CODEC_ID_ADPCM_IMA_HVQM4: + { + int frame_format = bytestream2_get_be16(gb); + int skip = 6; + + if (frame_format == 1) + skip += 2 * ch; + if (frame_format == 3) + skip += 3 * ch; + + nb_samples = (buf_size - skip) * 2 / ch; + bytestream2_seek(gb, 0, SEEK_SET); + } + break; case AV_CODEC_ID_ADPCM_IMA_EA_EACS: has_coded_samples = 1; *coded_samples = bytestream2_get_le32(gb); @@ -1453,6 +1510,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3); } ) /* End of CASE */ + CASE(ADPCM_IMA_HVQM4, + int format = bytestream2_get_be16(&gb); + + bytestream2_skip(&gb, 4); + decode_adpcm_ima_hvqm4(avctx, samples, nb_samples, format, &gb); + ) /* End of CASE */ CASE(ADPCM_IMA_SSI, for (int n = nb_samples >> (1 - st); n > 0; n--) { int v = bytestream2_get_byteu(&gb); @@ -2322,6 +2385,7 @@ ADPCM_DECODER(ADPCM_IMA_DK3, sample_fmts_s16, adpcm_ima_dk3, "ADPCM IMA ADPCM_DECODER(ADPCM_IMA_DK4, sample_fmts_s16, adpcm_ima_dk4, "ADPCM IMA Duck DK4") ADPCM_DECODER(ADPCM_IMA_EA_EACS, sample_fmts_s16, adpcm_ima_ea_eacs, "ADPCM IMA Electronic Arts EACS") ADPCM_DECODER(ADPCM_IMA_EA_SEAD, sample_fmts_s16, adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD") +ADPCM_DECODER(ADPCM_IMA_HVQM4, sample_fmts_s16, adpcm_ima_hvqm4, "ADPCM IMA HVQM4") ADPCM_DECODER(ADPCM_IMA_ISS, sample_fmts_s16, adpcm_ima_iss, "ADPCM IMA Funcom ISS") ADPCM_DECODER(ADPCM_IMA_MOFLEX, sample_fmts_s16p, adpcm_ima_moflex, "ADPCM IMA MobiClip MOFLEX") ADPCM_DECODER(ADPCM_IMA_MTF, sample_fmts_s16, adpcm_ima_mtf, "ADPCM IMA Capcom's MT Framework") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d1e10197de..89ba205a2f 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -642,6 +642,7 @@ extern const AVCodec ff_adpcm_ima_dk3_decoder; extern const AVCodec ff_adpcm_ima_dk4_decoder; extern const AVCodec ff_adpcm_ima_ea_eacs_decoder; extern const AVCodec ff_adpcm_ima_ea_sead_decoder; +extern const AVCodec ff_adpcm_ima_hvqm4_decoder; extern const AVCodec ff_adpcm_ima_iss_decoder; extern const AVCodec ff_adpcm_ima_moflex_decoder; extern const AVCodec ff_adpcm_ima_mtf_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 0974ee03de..6deba785dc 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2475,6 +2475,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_IMA_HVQM4, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_hvqm4", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM4"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ab265ec584..f3f262ec75 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -401,6 +401,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_IMA_HVQM4, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, -- 2.33.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".