From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id A0F944BADA for ; Sun, 24 Aug 2025 03:02:10 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id D244968027E; Sun, 24 Aug 2025 06:01:50 +0300 (EEST) Received: from 0f4167fb2350 (code.ffmpeg.org [188.245.149.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 3FBFE6802A4 for ; Sun, 24 Aug 2025 06:01:48 +0300 (EEST) MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] =?utf-8?q?=5BPATCH=5D_A_few_new_decoders_and_a_pa?= =?utf-8?q?rser_from_almpeg_=28PR_=2320325=29?= X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: michaelni via ffmpeg-devel Reply-To: FFmpeg development discussions and patches Cc: michaelni Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Message-Id: <20250824030150.D244968027E@ffbox0-bg.ffmpeg.org> Date: Sun, 24 Aug 2025 06:01:50 +0300 (EEST) Archived-At: List-Archive: List-Post: PR #20325 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20325 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20325.patch These are taken from before the switch to GPLv3+ If people prefer, we can merge the GPLv3+ switch for these modules too and put them under --enable-gpl and --enable-v3 >From 560ebf42e09e4e378c420908f2eed81d893f9df6 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 18 Nov 2024 19:04:23 +0000 Subject: [PATCH 01/15] avcodec: add AHX decoder (cherry picked from commit 039dc23d185214b8b0ef2bbccae197ceb5ad42a2) --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/bitstream_filters.c | 1 + libavcodec/bsf/Makefile | 1 + libavcodec/bsf/ahx_to_mp2.c | 62 ++++++++++++++++++++++++++++++ libavcodec/codec_desc.c | 7 ++++ libavcodec/codec_id.h | 1 + libavcodec/mpegaudiodec_float.c | 18 +++++++++ libavcodec/mpegaudiodec_template.c | 3 +- 9 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 libavcodec/bsf/ahx_to_mp2.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 3d036de4b6..e1cce1275b 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -219,6 +219,7 @@ OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o OBJS-$(CONFIG_AC3_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += g729dec.o lsp.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o OBJS-$(CONFIG_AGM_DECODER) += agm.o jpegquanttables.o +OBJS-$(CONFIG_AHX_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_AIC_DECODER) += aic.o OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o OBJS-$(CONFIG_ALAC_ENCODER) += alacenc.o alac_data.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index f5ec2e01e8..017d100848 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -434,6 +434,7 @@ extern const FFCodec ff_ac3_decoder; extern const FFCodec ff_ac3_fixed_encoder; extern const FFCodec ff_ac3_fixed_decoder; extern const FFCodec ff_acelp_kelvin_decoder; +extern const FFCodec ff_ahx_decoder; extern const FFCodec ff_alac_encoder; extern const FFCodec ff_alac_decoder; extern const FFCodec ff_als_decoder; diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index c277bc1a71..b4b852c7e6 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -25,6 +25,7 @@ #include "bsf_internal.h" extern const FFBitStreamFilter ff_aac_adtstoasc_bsf; +extern const FFBitStreamFilter ff_ahx_to_mp2_bsf; extern const FFBitStreamFilter ff_apv_metadata_bsf; extern const FFBitStreamFilter ff_av1_frame_merge_bsf; extern const FFBitStreamFilter ff_av1_frame_split_bsf; diff --git a/libavcodec/bsf/Makefile b/libavcodec/bsf/Makefile index 8e2e6f7b14..48a2f85ac7 100644 --- a/libavcodec/bsf/Makefile +++ b/libavcodec/bsf/Makefile @@ -3,6 +3,7 @@ clean:: OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += bsf/aac_adtstoasc.o OBJS-$(CONFIG_APV_METADATA_BSF) += bsf/apv_metadata.o +OBJS-$(CONFIG_AHX_TO_MP2_BSF) += bsf/ahx_to_mp2.o OBJS-$(CONFIG_AV1_FRAME_MERGE_BSF) += bsf/av1_frame_merge.o OBJS-$(CONFIG_AV1_FRAME_SPLIT_BSF) += bsf/av1_frame_split.o OBJS-$(CONFIG_AV1_METADATA_BSF) += bsf/av1_metadata.o diff --git a/libavcodec/bsf/ahx_to_mp2.c b/libavcodec/bsf/ahx_to_mp2.c new file mode 100644 index 0000000000..eae71fe5ee --- /dev/null +++ b/libavcodec/bsf/ahx_to_mp2.c @@ -0,0 +1,62 @@ +/* + * AHX to MP2 bitstream filter + * Copyright (c) 2024 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AHX to MP2 bitstream filter. + */ + +#include "libavutil/intreadwrite.h" +#include "bsf.h" +#include "bsf_internal.h" + +static av_cold int init(AVBSFContext *ctx) +{ + ctx->par_out->codec_id = AV_CODEC_ID_MP2; + + return 0; +} + +static int filter(AVBSFContext *ctx, AVPacket *pkt) +{ + int ret; + + ret = ff_bsf_get_packet_ref(ctx, pkt); + if (ret < 0) + return ret; + + if (pkt->size < 1044) { + ret = av_grow_packet(pkt, 1044-pkt->size); + if (ret < 0) { + av_packet_unref(pkt); + return ret; + } + } + + return 0; +} + +const FFBitStreamFilter ff_ahx_to_mp2_bsf = { + .p.name = "ahx_to_mp2", + .p.codec_ids = (const enum AVCodecID []){ AV_CODEC_ID_AHX, AV_CODEC_ID_NONE }, + .init = init, + .filter = filter, +}; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index a065556e51..284d1861c4 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3495,6 +3495,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("G.728"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_AHX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ahx", + .long_name = NULL_IF_CONFIG_SMALL("CRI AHX"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index c4842e61ff..455bc4b839 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -556,6 +556,7 @@ enum AVCodecID { AV_CODEC_ID_QOA, AV_CODEC_ID_LC3, AV_CODEC_ID_G728, + AV_CODEC_ID_AHX, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/mpegaudiodec_float.c b/libavcodec/mpegaudiodec_float.c index 05e2e399e4..232e2fa201 100644 --- a/libavcodec/mpegaudiodec_float.c +++ b/libavcodec/mpegaudiodec_float.c @@ -103,6 +103,24 @@ const FFCodec ff_mp2float_decoder = { CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT), }; #endif +#if CONFIG_AHX_DECODER +const FFCodec ff_ahx_decoder = { + .p.name = "ahx", + CODEC_LONG_NAME("CRI AHX"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AHX, + .priv_data_size = sizeof(MPADecodeContext), + .init = decode_init, + FF_CODEC_DECODE_CB(decode_frame), + .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | + AV_CODEC_CAP_DR1, + .flush = flush, + .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE }, + .bsfs = "ahx_to_mp2", +}; +#endif #if CONFIG_MP3FLOAT_DECODER const FFCodec ff_mp3float_decoder = { .p.name = "mp3float", diff --git a/libavcodec/mpegaudiodec_template.c b/libavcodec/mpegaudiodec_template.c index d7c5210eb8..005e9ba2fa 100644 --- a/libavcodec/mpegaudiodec_template.c +++ b/libavcodec/mpegaudiodec_template.c @@ -1604,7 +1604,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (ret >= 0) { s->frame->nb_samples = avctx->frame_size; *got_frame_ptr = 1; - avctx->sample_rate = s->sample_rate; + if (avctx->codec_id != AV_CODEC_ID_AHX) + avctx->sample_rate = s->sample_rate; //FIXME maybe move the other codec info stuff from above here too } else { av_log(avctx, AV_LOG_ERROR, "Error while decoding MPEG audio frame.\n"); -- 2.49.1 >From 8a11b844ff4fb4596be42ac9714060f718426212 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 19 Nov 2024 09:20:52 +0000 Subject: [PATCH 02/15] avcodec: add AHX parser (cherry picked from commit ddcb47c4c512bf49b22cc6b2d07fade0f96377e3) --- libavcodec/Makefile | 1 + libavcodec/ahx_parser.c | 78 +++++++++++++++++++++++++++++++++++++++++ libavcodec/parsers.c | 1 + 3 files changed, 80 insertions(+) create mode 100644 libavcodec/ahx_parser.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e1cce1275b..3005e4a31a 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1217,6 +1217,7 @@ OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o OBJS-$(CONFIG_AC3_PARSER) += aac_ac3_parser.o ac3tab.o \ ac3_channel_layout_tab.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o +OBJS-$(CONFIG_AHX_PARSER) += ahx_parser.o OBJS-$(CONFIG_AMR_PARSER) += amr_parser.o OBJS-$(CONFIG_APV_PARSER) += apv_parser.o OBJS-$(CONFIG_AV1_PARSER) += av1_parser.o av1_parse.o diff --git a/libavcodec/ahx_parser.c b/libavcodec/ahx_parser.c new file mode 100644 index 0000000000..4be037f666 --- /dev/null +++ b/libavcodec/ahx_parser.c @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AHX audio parser + * + * Splits packets into individual blocks. + */ + +#include "libavutil/intreadwrite.h" +#include "parser.h" + +typedef struct AHXParseContext { + ParseContext pc; + uint32_t header; + int size; +} AHXParseContext; + +static int ahx_parse(AVCodecParserContext *s1, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + AHXParseContext *s = s1->priv_data; + ParseContext *pc = &s->pc; + uint32_t state = pc->state; + int next = END_NOT_FOUND; + + for (int i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + s->size++; + if (s->size == 4 && !s->header) + s->header = state; + if (s->size > 4 && state == s->header) { + next = i - 3; + s->size = 0; + break; + } + } + pc->state = state; + + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + s1->duration = 1152; + s1->key_frame = 1; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +const AVCodecParser ff_ahx_parser = { + .codec_ids = { AV_CODEC_ID_AHX }, + .priv_data_size = sizeof(AHXParseContext), + .parser_parse = ahx_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index b12c48f79f..42b40643f9 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -24,6 +24,7 @@ extern const AVCodecParser ff_aac_parser; extern const AVCodecParser ff_aac_latm_parser; extern const AVCodecParser ff_ac3_parser; extern const AVCodecParser ff_adx_parser; +extern const AVCodecParser ff_ahx_parser; extern const AVCodecParser ff_amr_parser; extern const AVCodecParser ff_apv_parser; extern const AVCodecParser ff_av1_parser; -- 2.49.1 >From 87faa2fa9048f6edd6ed45f285e9dcfa735600b9 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sun, 1 Aug 2021 21:12:55 +0200 Subject: [PATCH 03/15] avcodec: add ADPCM IMA HVQM4 decoder Signed-off-by: Paul B Mahol (cherry picked from commit bae3cecfa6f1fbc765d95d84ef4a377aedbca8bb) --- 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 3005e4a31a..6311cd1821 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -984,6 +984,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_HVMQ4_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 4c15be6207..bc3b0c9730 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -544,6 +544,49 @@ int16_t ff_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->ch_layout.nb_channels == 2; + unsigned tmp; + + for (int ch = 0; ch < avctx->ch_layout.nb_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->ch_layout.nb_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++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], nibble & 0xF); + *outbuf++ = ff_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; @@ -1100,6 +1143,20 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, *coded_samples -= *coded_samples % 28; nb_samples = (buf_size - 12) / (ch == 2 ? 30 : 15) * 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); @@ -1686,6 +1743,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, *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); @@ -2636,6 +2699,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 017d100848..b81dda8161 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -677,6 +677,7 @@ extern const FFCodec ff_adpcm_ima_dk3_decoder; extern const FFCodec ff_adpcm_ima_dk4_decoder; extern const FFCodec ff_adpcm_ima_ea_eacs_decoder; extern const FFCodec ff_adpcm_ima_ea_sead_decoder; +extern const FFCodec ff_adpcm_ima_hvqm4_decoder; extern const FFCodec ff_adpcm_ima_iss_decoder; extern const FFCodec ff_adpcm_ima_moflex_decoder; extern const FFCodec ff_adpcm_ima_mtf_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 284d1861c4..101aabb11c 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2634,6 +2634,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Sanyo"), .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 455bc4b839..ee964184a5 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -427,6 +427,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_XMD, AV_CODEC_ID_ADPCM_IMA_XBOX, AV_CODEC_ID_ADPCM_SANYO, + AV_CODEC_ID_ADPCM_IMA_HVQM4, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, -- 2.49.1 >From 2f541e6f871d801c2b5bb465aea057ffb48e1b0e Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 13 May 2024 10:20:06 +0200 Subject: [PATCH 04/15] avcodec: add ADPCM IMA PDA decoder (cherry picked from commit ab9f7513d55cfd87d1a1ce22d02abffbfb9bb296) --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 25 +++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/codec_id.h | 1 + libavcodec/utils.c | 1 + 6 files changed, 36 insertions(+) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 6311cd1821..5a325bf174 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -988,6 +988,7 @@ OBJS-$(CONFIG_ADPCM_IMA_HVMQ4_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 +OBJS-$(CONFIG_ADPCM_IMA_PDA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index bc3b0c9730..55e48d193d 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1207,6 +1207,11 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, buf_size = FFMIN(buf_size, avctx->block_align); nb_samples = (buf_size - 4 * ch) * 2 / ch; break; + case AV_CODEC_ID_ADPCM_IMA_PDA: + if (avctx->block_align > 0) + buf_size = FFMIN(buf_size, avctx->block_align); + nb_samples = (buf_size - 4 * ch) * 2 / ch; + break; CASE(ADPCM_IMA_WAV, int bsize = ff_adpcm_ima_block_sizes[avctx->bits_per_coded_sample - 2]; int bsamples = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2]; @@ -2202,6 +2207,25 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_IMA_PDA, + for (int i = 0; i < channels; i++) { + c->status[i].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); + c->status[i].step_index = bytestream2_get_byteu(&gb); + bytestream2_skipu(&gb, 1); + if (c->status[i].step_index > 88u) { + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index = %i\n", + c->status[i].step_index); + return AVERROR_INVALIDDATA; + } + } + + for (int n = nb_samples >> (1 - st); n > 0; n--) { + int v = bytestream2_get_byteu(&gb); + + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[0 ], v >> 4 ); + *samples++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], v & 0xf); + } + ) /* End of CASE */ CASE(ADPCM_IMA_SMJPEG, for (int i = 0; i < channels; i++) { c->status[i].predictor = sign_extend(bytestream2_get_be16u(&gb), 16); @@ -2704,6 +2728,7 @@ ADPCM_DECODER(ADPCM_IMA_ISS, sample_fmts_s16, adpcm_ima_iss, "ADPCM IMA 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") ADPCM_DECODER(ADPCM_IMA_OKI, sample_fmts_s16, adpcm_ima_oki, "ADPCM IMA Dialogic OKI") +ADPCM_DECODER(ADPCM_IMA_PDA, sample_fmts_s16, adpcm_ima_pda, "ADPCM IMA PlayDate") ADPCM_DECODER(ADPCM_IMA_QT, sample_fmts_s16p, adpcm_ima_qt, "ADPCM IMA QuickTime") ADPCM_DECODER(ADPCM_IMA_RAD, sample_fmts_s16, adpcm_ima_rad, "ADPCM IMA Radical") ADPCM_DECODER(ADPCM_IMA_SSI, sample_fmts_s16, adpcm_ima_ssi, "ADPCM IMA Simon & Schuster Interactive") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b81dda8161..2fb3b0c2ea 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -682,6 +682,7 @@ extern const FFCodec ff_adpcm_ima_iss_decoder; extern const FFCodec ff_adpcm_ima_moflex_decoder; extern const FFCodec ff_adpcm_ima_mtf_decoder; extern const FFCodec ff_adpcm_ima_oki_decoder; +extern const FFCodec ff_adpcm_ima_pda_decoder; extern const FFCodec ff_adpcm_ima_qt_encoder; extern const FFCodec ff_adpcm_ima_qt_decoder; extern const FFCodec ff_adpcm_ima_rad_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 101aabb11c..4128bf2ecb 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2641,6 +2641,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM4"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_PDA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_pda", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA PlayDate"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ee964184a5..6e4b215bf1 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -428,6 +428,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_XBOX, AV_CODEC_ID_ADPCM_SANYO, AV_CODEC_ID_ADPCM_IMA_HVQM4, + AV_CODEC_ID_ADPCM_IMA_PDA, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index cfa35d0e04..735edaf7a6 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -675,6 +675,7 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, case AV_CODEC_ID_ADPCM_IMA_ACORN: case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_ISS: + case AV_CODEC_ID_ADPCM_IMA_PDA: return (frame_bytes - 4 * ch) * 2 / ch; case AV_CODEC_ID_ADPCM_IMA_SMJPEG: return (frame_bytes - 4) * 2 / ch; -- 2.49.1 >From 56e5c562a00260dd56e54cabb6a3c181bc5c737b Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 25 Nov 2024 13:01:16 +0000 Subject: [PATCH 05/15] avcodec: add ADPCM Silicon Graphics N64 decoder (cherry picked from commit 13484237fdf19c9d927b8a64b81d00100a4178c3) --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 89 +++++++++++++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 ++++ libavcodec/codec_id.h | 1 + libavcodec/utils.c | 5 +++ 6 files changed, 104 insertions(+) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 5a325bf174..3af81c368e 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1004,6 +1004,7 @@ OBJS-$(CONFIG_ADPCM_IMA_XBOX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MTAF_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_N64_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_PSX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SANYO_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER) += adpcm.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 55e48d193d..49bc2e9e70 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -259,6 +259,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) switch(avctx->codec->id) { case AV_CODEC_ID_ADPCM_IMA_AMV: + case AV_CODEC_ID_ADPCM_N64: max_channels = 1; break; case AV_CODEC_ID_ADPCM_SANYO: @@ -350,6 +351,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_MTAF: case AV_CODEC_ID_ADPCM_ARGO: case AV_CODEC_ID_ADPCM_IMA_MOFLEX: + case AV_CODEC_ID_ADPCM_N64: avctx->sample_fmt = AV_SAMPLE_FMT_S16P; break; case AV_CODEC_ID_ADPCM_IMA_WS: @@ -1093,6 +1095,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, return 0; nb_samples = 64; break; + case AV_CODEC_ID_ADPCM_N64: + nb_samples = (buf_size / 9) * 16; + break; /* simple 4-bit adpcm */ case AV_CODEC_ID_ADPCM_CT: case AV_CODEC_ID_ADPCM_IMA_APC: @@ -2491,6 +2496,89 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, bytestream2_seek(&gb, 0, SEEK_SET); } ) /* End of CASE */ + CASE(ADPCM_N64, + ADPCMChannelStatus *cs = &c->status[0]; + int coefs[8*2*8] = { 0 }; + + if (avctx->extradata) { + int version, order, entries; + GetByteContext cb; + + bytestream2_init(&cb, avctx->extradata, avctx->extradata_size); + + version = bytestream2_get_be16(&cb); + order = bytestream2_get_be16(&cb); + entries = bytestream2_get_be16(&cb); + if (version != 1 || order != 2 || entries > 8) + return AVERROR_INVALIDDATA; + + for (int n = 0; n < order * entries * 8; n++) + coefs[n] = sign_extend(bytestream2_get_be16(&cb), 16); + } + + for (int block = 0; block < avpkt->size / 9; block++) { + int scale, index, codes[16]; + int16_t hist[8] = { 0 }; + const int order = 2; + int16_t out[16]; + + hist[6] = cs->sample2; + hist[7] = cs->sample1; + + samples = samples_p[0] + block * 16; + + scale = (buf[0] >> 4) & 0xF; + index = (buf[0] >> 0) & 0xF; + scale = 1 << scale; + index = FFMIN(index, 8); + + for (int i = 0, j = 0; i < 16; i += 2, j++) { + int n0 = (buf[j+1] >> 4) & 0xF; + int n1 = (buf[j+1] >> 0) & 0xF; + + if (n0 & 8) + n0 = n0 - 16; + if (n1 & 8) + n1 = n1 - 16; + + codes[i+0] = n0 * scale; + codes[i+1] = n1 * scale; + } + + for (int j = 0; j < 2; j++) { + int *sf_codes = &codes[j*8]; + int16_t *sf_out = &out[j*8]; + + for (int i = 0; i < 8; i++) { + int sample, delta = 0; + + for (int o = 0; o < order; o++) + delta += coefs[o*8 + i] * hist[(8 - order) + o]; + + for (int k = i-1; k > -1; k--) { + for (int o = 1; o < order; o++) + delta += sf_codes[(i-1) - k] * coefs[(o*8) + k]; + } + + sample = sf_codes[i] * 2048; + sample = (sample + delta) / 2048; + sample = av_clip_int16(sample); + sf_out[i] = sample; + } + + for (int i = 8 - order; i < 8; i++) + hist[i] = sf_out[i]; + } + + memcpy(samples, out, sizeof(out)); + + cs->sample2 = hist[6]; + cs->sample1 = hist[7]; + + buf += 9; + } + bytestream2_seek(&gb, 0, SEEK_END); + ) /* End of CASE */ CASE(ADPCM_PSX, for (int block = 0; block < avpkt->size / FFMAX(avctx->block_align, 16 * channels); block++) { int nb_samples_per_block = 28 * FFMAX(avctx->block_align, 16 * channels) / (16 * channels); @@ -2739,6 +2827,7 @@ ADPCM_DECODER(ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA ADPCM_DECODER(ADPCM_IMA_XBOX, sample_fmts_s16p, adpcm_ima_xbox, "ADPCM IMA Xbox") ADPCM_DECODER(ADPCM_MS, sample_fmts_both, adpcm_ms, "ADPCM Microsoft") ADPCM_DECODER(ADPCM_MTAF, sample_fmts_s16p, adpcm_mtaf, "ADPCM MTAF") +ADPCM_DECODER(ADPCM_N64, sample_fmts_s16p, adpcm_n64, "ADPCM Silicon Graphics N64") ADPCM_DECODER(ADPCM_PSX, sample_fmts_s16p, adpcm_psx, "ADPCM Playstation") ADPCM_DECODER(ADPCM_SANYO, sample_fmts_s16p, adpcm_sanyo, "ADPCM Sanyo") ADPCM_DECODER(ADPCM_SBPRO_2, sample_fmts_s16, adpcm_sbpro_2, "ADPCM Sound Blaster Pro 2-bit") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 2fb3b0c2ea..f3a252e241 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -697,6 +697,7 @@ extern const FFCodec ff_adpcm_ima_xbox_decoder; extern const FFCodec ff_adpcm_ms_encoder; extern const FFCodec ff_adpcm_ms_decoder; extern const FFCodec ff_adpcm_mtaf_decoder; +extern const FFCodec ff_adpcm_n64_decoder; extern const FFCodec ff_adpcm_psx_decoder; extern const FFCodec ff_adpcm_sanyo_decoder; extern const FFCodec ff_adpcm_sbpro_2_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 4128bf2ecb..b758e43f33 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2648,6 +2648,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA PlayDate"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_N64, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_n64", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Silicon Graphics N64"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 6e4b215bf1..8930b2957e 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -429,6 +429,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_SANYO, AV_CODEC_ID_ADPCM_IMA_HVQM4, AV_CODEC_ID_ADPCM_IMA_PDA, + AV_CODEC_ID_ADPCM_N64, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 735edaf7a6..c5230e646a 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -665,6 +665,11 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, return (frame_bytes - 4 * ch) / (128 * ch) * 256; case AV_CODEC_ID_ADPCM_AFC: return frame_bytes / (9 * ch) * 16; + case AV_CODEC_ID_ADPCM_N64: + frame_bytes /= 9 * ch; + if (frame_bytes > INT_MAX / 16) + return 0; + return frame_bytes * 16; case AV_CODEC_ID_ADPCM_PSX: case AV_CODEC_ID_ADPCM_DTK: frame_bytes /= 16 * ch; -- 2.49.1 >From dc13da259d28d93cb329f19480076ed0e1967171 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 25 Nov 2024 19:34:44 +0000 Subject: [PATCH 06/15] avcodec/adpcm: fix overflow in mono ADPCM IMA HVQM4 (cherry picked from commit 6a9b0f7272a0725abbe6f887f766fb5f1f119a66) --- libavcodec/adpcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 49bc2e9e70..3f4c392939 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -579,7 +579,7 @@ static void decode_adpcm_ima_hvqm4(AVCodecContext *avctx, int16_t *outbuf, int s samples_to_do--; } - for (int i = 0; i < samples_to_do; i++) { + for (int i = 0; i < samples_to_do; i += 1+(!st)) { uint8_t nibble = bytestream2_get_byte(gb); *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], nibble & 0xF); -- 2.49.1 >From ac1fbf530503e893946974aed5b0390686eba9f6 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 25 Nov 2024 19:06:53 +0000 Subject: [PATCH 07/15] avcodec: add ADPCM IMA HVQM2 decoder (cherry picked from commit 480e36592d5fc27a47e378d62570824613f26b7b) --- libavcodec/Makefile | 3 ++- libavcodec/adpcm.c | 47 +++++++++++++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 ++++++ libavcodec/codec_id.h | 1 + 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 3af81c368e..0cf8c80b2e 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -984,7 +984,8 @@ 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_HVMQ4_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_HVQM2_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 3f4c392939..a131088b7c 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -546,6 +546,43 @@ int16_t ff_adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble) return c->predictor; } +static void decode_adpcm_ima_hvqm2(AVCodecContext *avctx, int16_t *outbuf, int samples_to_do, + int frame_format, GetByteContext *gb) +{ + ADPCMDecodeContext *c = avctx->priv_data; + int st = avctx->ch_layout.nb_channels == 2; + uint8_t nibble; + + for (int ch = 0; ch < avctx->ch_layout.nb_channels; ch++) { + unsigned tmp; + + switch (frame_format) { + case 0: /* combined hist+index */ + tmp = bytestream2_get_be16(gb); + c->status[ch].predictor = sign_extend(tmp & 0xFF80, 16); + c->status[ch].step_index = tmp & 0x7f; + *outbuf++ = c->status[ch].predictor; + samples_to_do--; + break; + default: + break; + } + + c->status[ch].step_index = av_clip(c->status[ch].step_index, 0, 88); + } + + for (int i = 0; i < samples_to_do; i++) { + if (!(i&1)) { + nibble = bytestream2_get_byte(gb); + *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[st], nibble >> 4); + } else { + *outbuf++ = ff_adpcm_ima_qt_expand_nibble(&c->status[ 0], nibble & 0xF); + } + } + + bytestream2_seek(gb, 0, SEEK_END); +} + static void decode_adpcm_ima_hvqm4(AVCodecContext *avctx, int16_t *outbuf, int samples_to_do, int frame_format, GetByteContext *gb) { @@ -1148,6 +1185,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, *coded_samples -= *coded_samples % 28; nb_samples = (buf_size - 12) / (ch == 2 ? 30 : 15) * 28; break; + case AV_CODEC_ID_ADPCM_IMA_HVQM2: + nb_samples = ((bytestream2_peek_be64(gb) >> 16) & 0xFFFF); + break; case AV_CODEC_ID_ADPCM_IMA_HVQM4: { int frame_format = bytestream2_get_be16(gb); @@ -1753,6 +1793,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3); } ) /* End of CASE */ + CASE(ADPCM_IMA_HVQM2, + int format = bytestream2_get_be16(&gb); + + bytestream2_skip(&gb, 4); + decode_adpcm_ima_hvqm2(avctx, samples, nb_samples, format, &gb); + ) /* End of CASE */ CASE(ADPCM_IMA_HVQM4, int format = bytestream2_get_be16(&gb); @@ -2811,6 +2857,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_HVQM2, sample_fmts_s16, adpcm_ima_hvqm2, "ADPCM IMA HVQM2") 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") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index f3a252e241..5891c04211 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -677,6 +677,7 @@ extern const FFCodec ff_adpcm_ima_dk3_decoder; extern const FFCodec ff_adpcm_ima_dk4_decoder; extern const FFCodec ff_adpcm_ima_ea_eacs_decoder; extern const FFCodec ff_adpcm_ima_ea_sead_decoder; +extern const FFCodec ff_adpcm_ima_hvqm2_decoder; extern const FFCodec ff_adpcm_ima_hvqm4_decoder; extern const FFCodec ff_adpcm_ima_iss_decoder; extern const FFCodec ff_adpcm_ima_moflex_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index b758e43f33..ea22c0a668 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2655,6 +2655,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Silicon Graphics N64"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_HVQM2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_hvqm2", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM2"), + .props = AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 8930b2957e..cc22f24ba9 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -430,6 +430,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_HVQM4, AV_CODEC_ID_ADPCM_IMA_PDA, AV_CODEC_ID_ADPCM_N64, + AV_CODEC_ID_ADPCM_IMA_HVQM2, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, -- 2.49.1 >From e35ac402c2a9f477b68a038086d72de9c7ea75e3 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sun, 15 Dec 2024 13:48:11 +0000 Subject: [PATCH 08/15] avcodec/adpcm: explicitly clear 4 upper bits for PSX when sign extending (cherry picked from commit 49f6621d88392e21360efc1fb99d1241fa3ce469) --- libavcodec/adpcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index a131088b7c..eccb574cd7 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -2651,7 +2651,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, scale = sign_extend(byte >> 4, 4); } else { byte = bytestream2_get_byteu(&gb); - scale = sign_extend(byte, 4); + scale = sign_extend(byte & 0xF, 4); } if (flag < 0x07) { -- 2.49.1 >From 37dd4362116f66306954527ece6ff38b39738ce3 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 21 Jan 2025 17:29:45 +0000 Subject: [PATCH 09/15] avcodec: add ADPCM IMA Magix decoder (cherry picked from commit 2ec3ad2122484ce2c84f6ba055c5ebc1661c5b14) --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 24 ++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/codec_id.h | 1 + libavcodec/utils.c | 1 + 6 files changed, 35 insertions(+) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 0cf8c80b2e..6ab6313412 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -988,6 +988,7 @@ OBJS-$(CONFIG_ADPCM_IMA_HVQM2_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_MAGIX_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_MTF_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_PDA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index eccb574cd7..c641f4bef4 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1161,6 +1161,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_AGM: case AV_CODEC_ID_ADPCM_IMA_ACORN: case AV_CODEC_ID_ADPCM_IMA_DAT4: + case AV_CODEC_ID_ADPCM_IMA_MAGIX: case AV_CODEC_ID_ADPCM_IMA_MOFLEX: case AV_CODEC_ID_ADPCM_IMA_ISS: header_size = 4 * ch; break; case AV_CODEC_ID_ADPCM_IMA_SMJPEG: header_size = 4 * ch; break; @@ -1724,6 +1725,28 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((bytestream2_tell(&gb) & 1)) bytestream2_skip(&gb, 1); ) /* End of CASE */ + CASE(ADPCM_IMA_MAGIX, + for (int channel = 0; channel < channels; channel++) { + ADPCMChannelStatus *cs = &c->status[channel]; + cs->predictor = sign_extend(bytestream2_get_le16u(&gb), 16); + cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16); + if (cs->step_index > 88u){ + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n", + channel, cs->step_index); + return AVERROR_INVALIDDATA; + } + } + + for (int m = 0; m < avctx->block_align-8; m += 8) { + uint32_t v0 = bytestream2_get_le32u(&gb); + uint32_t v1 = bytestream2_get_le32u(&gb); + + for (int n = 8; n > 0; n--, v0 >>= 4, v1 >>= 4, samples += 2) { + samples[0] = adpcm_ima_expand_nibble(&c->status[0], v0 & 15, 3); + samples[1] = adpcm_ima_expand_nibble(&c->status[1], v1 & 15, 3); + } + } + ) /* End of CASE */ CASE(ADPCM_IMA_ISS, for (int channel = 0; channel < channels; channel++) { ADPCMChannelStatus *cs = &c->status[channel]; @@ -2860,6 +2883,7 @@ ADPCM_DECODER(ADPCM_IMA_EA_SEAD, sample_fmts_s16, adpcm_ima_ea_sead, "ADPCM IMA ADPCM_DECODER(ADPCM_IMA_HVQM2, sample_fmts_s16, adpcm_ima_hvqm2, "ADPCM IMA HVQM2") 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_MAGIX, sample_fmts_s16, adpcm_ima_magix, "ADPCM IMA Magix") 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") ADPCM_DECODER(ADPCM_IMA_OKI, sample_fmts_s16, adpcm_ima_oki, "ADPCM IMA Dialogic OKI") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 5891c04211..9064e470d3 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -680,6 +680,7 @@ extern const FFCodec ff_adpcm_ima_ea_sead_decoder; extern const FFCodec ff_adpcm_ima_hvqm2_decoder; extern const FFCodec ff_adpcm_ima_hvqm4_decoder; extern const FFCodec ff_adpcm_ima_iss_decoder; +extern const FFCodec ff_adpcm_ima_magix_decoder; extern const FFCodec ff_adpcm_ima_moflex_decoder; extern const FFCodec ff_adpcm_ima_mtf_decoder; extern const FFCodec ff_adpcm_ima_oki_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index ea22c0a668..421ecf6926 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2662,6 +2662,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA HVQM2"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_MAGIX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_magix", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Magix"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index cc22f24ba9..c69e81582a 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -431,6 +431,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_PDA, AV_CODEC_ID_ADPCM_N64, AV_CODEC_ID_ADPCM_IMA_HVQM2, + AV_CODEC_ID_ADPCM_IMA_MAGIX, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index c5230e646a..039315a2ce 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -465,6 +465,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_ADPCM_IMA_APC: case AV_CODEC_ID_ADPCM_IMA_APM: case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: + case AV_CODEC_ID_ADPCM_IMA_MAGIX: case AV_CODEC_ID_ADPCM_IMA_OKI: case AV_CODEC_ID_ADPCM_IMA_WS: case AV_CODEC_ID_ADPCM_IMA_SSI: -- 2.49.1 >From 9970be5a6ddb9d2cb589d9381b19fa92db8672bb Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 19 Feb 2025 20:24:39 +0000 Subject: [PATCH 10/15] avcodec/adpcm: fix non-4bit adpcm ima wav decoding (cherry picked from commit f4e05abeded46515bd7b4248fc7d65df82d9af2a) --- libavcodec/adpcm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index c641f4bef4..a1906ac26c 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -509,7 +509,9 @@ static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitC sign = nibble & (1 << shift); delta = av_zero_extend(nibble, shift); - diff = ((2 * delta + 1) * step) >> shift; + diff = step >> shift; + for (int i = 0; i < shift; i++) + diff += (step >> (shift-1-i)) * !!(delta & (1 << i)); predictor = c->predictor; if (sign) predictor -= diff; else predictor += diff; -- 2.49.1 >From cc38ce87b3fb06a8fb75c0fc51fb87b3e57d196b Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 24 Feb 2025 12:19:03 +0000 Subject: [PATCH 11/15] avcodec: add ADPCM PSXC audio decoder (cherry picked from commit a4055b5cc6d77c26867948e24de6bdfd5c0e6a3b) --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 44 +++++++++++++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/codec_id.h | 1 + libavcodec/utils.c | 5 +++++ 6 files changed, 59 insertions(+) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 6ab6313412..08c5240a4c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1008,6 +1008,7 @@ OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.o adpcm_data.o OBJS-$(CONFIG_ADPCM_MTAF_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_N64_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_PSX_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_PSXC_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SANYO_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_SBPRO_3_DECODER) += adpcm.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index a1906ac26c..9381bdcf2a 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -290,6 +290,11 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) avctx->block_align % (16 * avctx->ch_layout.nb_channels)) return AVERROR_INVALIDDATA; break; + case AV_CODEC_ID_ADPCM_PSXC: + max_channels = 8; + if (avctx->ch_layout.nb_channels <= 0) + return AVERROR_INVALIDDATA; + break; case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_THP: case AV_CODEC_ID_ADPCM_THP_LE: @@ -347,6 +352,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_DTK: case AV_CODEC_ID_ADPCM_PSX: + case AV_CODEC_ID_ADPCM_PSXC: case AV_CODEC_ID_ADPCM_SANYO: case AV_CODEC_ID_ADPCM_MTAF: case AV_CODEC_ID_ADPCM_ARGO: @@ -1351,6 +1357,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_PSX: nb_samples = buf_size / (16 * ch) * 28; break; + case AV_CODEC_ID_ADPCM_PSXC: + nb_samples = ((buf_size - 1) / ch) * 2; + break; case AV_CODEC_ID_ADPCM_ARGO: nb_samples = buf_size / avctx->block_align * 32; break; @@ -2691,6 +2700,40 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_PSXC, + for (int block = 0; block < avpkt->size / avctx->block_align; block++) { + int nb_samples_per_block = ((avctx->block_align - 1) / channels) * 2; + for (int channel = 0; channel < channels; channel++) { + int filter, shift, byte; + + samples = samples_p[channel] + block * nb_samples_per_block; + av_assert0((block + 1) * nb_samples_per_block <= nb_samples); + + filter = bytestream2_get_byteu(&gb); + shift = filter & 0xf; + filter = filter >> 4; + if (filter >= FF_ARRAY_ELEMS(xa_adpcm_table)) + return AVERROR_INVALIDDATA; + + for (int n = 0; n < nb_samples_per_block; n++) { + int sample = 0, scale; + + if (n & 1) { + scale = sign_extend(byte >> 4, 4); + } else { + byte = bytestream2_get_byteu(&gb); + scale = sign_extend(byte & 0xF, 4); + } + + scale = scale * (1 << 12); + sample = (int)((scale >> shift) + (c->status[channel].sample1 * xa_adpcm_table[filter][0] + c->status[channel].sample2 * xa_adpcm_table[filter][1]) / 64); + *samples++ = av_clip_int16(sample); + c->status[channel].sample2 = c->status[channel].sample1; + c->status[channel].sample1 = sample; + } + } + } + ) /* End of CASE */ CASE(ADPCM_SANYO, int (*expand)(ADPCMChannelStatus *c, int bits); GetBitContext g; @@ -2902,6 +2945,7 @@ ADPCM_DECODER(ADPCM_MS, sample_fmts_both, adpcm_ms, "ADPCM Mic ADPCM_DECODER(ADPCM_MTAF, sample_fmts_s16p, adpcm_mtaf, "ADPCM MTAF") ADPCM_DECODER(ADPCM_N64, sample_fmts_s16p, adpcm_n64, "ADPCM Silicon Graphics N64") ADPCM_DECODER(ADPCM_PSX, sample_fmts_s16p, adpcm_psx, "ADPCM Playstation") +ADPCM_DECODER(ADPCM_PSXC, sample_fmts_s16p, adpcm_psxc, "ADPCM Playstation C") ADPCM_DECODER(ADPCM_SANYO, sample_fmts_s16p, adpcm_sanyo, "ADPCM Sanyo") ADPCM_DECODER(ADPCM_SBPRO_2, sample_fmts_s16, adpcm_sbpro_2, "ADPCM Sound Blaster Pro 2-bit") ADPCM_DECODER(ADPCM_SBPRO_3, sample_fmts_s16, adpcm_sbpro_3, "ADPCM Sound Blaster Pro 2.6-bit") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 9064e470d3..67e02ef7bb 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -701,6 +701,7 @@ extern const FFCodec ff_adpcm_ms_decoder; extern const FFCodec ff_adpcm_mtaf_decoder; extern const FFCodec ff_adpcm_n64_decoder; extern const FFCodec ff_adpcm_psx_decoder; +extern const FFCodec ff_adpcm_psxc_decoder; extern const FFCodec ff_adpcm_sanyo_decoder; extern const FFCodec ff_adpcm_sbpro_2_decoder; extern const FFCodec ff_adpcm_sbpro_3_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 421ecf6926..1493f34730 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2669,6 +2669,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Magix"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_PSXC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_psxc", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Playstation C"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index c69e81582a..975ebbe880 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -432,6 +432,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_N64, AV_CODEC_ID_ADPCM_IMA_HVQM2, AV_CODEC_ID_ADPCM_IMA_MAGIX, + AV_CODEC_ID_ADPCM_PSXC, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 039315a2ce..b65e10827e 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -677,6 +677,11 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, if (frame_bytes > INT_MAX / 28) return 0; return frame_bytes * 28; + case AV_CODEC_ID_ADPCM_PSXC: + frame_bytes = (frame_bytes - 1) / ch; + if (frame_bytes > INT_MAX / 2) + return 0; + return frame_bytes * 2; case AV_CODEC_ID_ADPCM_4XM: case AV_CODEC_ID_ADPCM_IMA_ACORN: case AV_CODEC_ID_ADPCM_IMA_DAT4: -- 2.49.1 >From c1bb24c3f29b1bf78ec36e0d5270ed22e9d901a5 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 28 Feb 2025 16:05:05 +0000 Subject: [PATCH 12/15] avcodec: add ADPCM Circus decoder (cherry picked from commit cdd3d794c7e01e4d6f485e7b975a4b9107d3f2fd) --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 31 +++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/codec_id.h | 1 + libavcodec/utils.c | 1 + 6 files changed, 42 insertions(+) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 08c5240a4c..1e6e00b154 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -956,6 +956,7 @@ 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_ARGO_ENCODER) += adpcm.o adpcm_data.o adpcmenc.o +OBJS-$(CONFIG_ADPCM_CIRCUS_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 9381bdcf2a..76404bcf08 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -738,6 +738,27 @@ static inline int16_t adpcm_mtaf_expand_nibble(ADPCMChannelStatus *c, uint8_t ni return c->predictor; } +static inline int16_t adpcm_circus_expand_nibble(ADPCMChannelStatus *c, uint8_t nibble) +{ + int32_t sample = c->predictor; + int32_t scale = c->step; + int32_t code = sign_extend(nibble, 8); + + sample += code * (1 << scale); + if (code == 0) { + scale--; + } else if (code == 127 || code == -128) { + scale++; + } + scale = av_clip(scale, 0, 8); + sample = av_clip_int16(sample); + + c->predictor = sample; + c->step = scale; + + return sample; +} + static inline int16_t adpcm_zork_expand_nibble(ADPCMChannelStatus *c, uint8_t nibble) { int16_t index = c->step_index; @@ -1363,6 +1384,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_ARGO: nb_samples = buf_size / avctx->block_align * 32; break; + case AV_CODEC_ID_ADPCM_CIRCUS: case AV_CODEC_ID_ADPCM_ZORK: nb_samples = buf_size / ch; break; @@ -2794,6 +2816,14 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } ) /* End of CASE */ + CASE(ADPCM_CIRCUS, + for (int n = 0; n < nb_samples; n++) { + for (int ch = 0; ch < channels; ch++) { + int v = bytestream2_get_byteu(&gb); + *samples++ = adpcm_circus_expand_nibble(&c->status[ch], v); + } + } + ) /* End of CASE */ CASE(ADPCM_ZORK, for (int n = 0; n < nb_samples * channels; n++) { int v = bytestream2_get_byteu(&gb); @@ -2907,6 +2937,7 @@ ADPCM_DECODER(ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nin ADPCM_DECODER(ADPCM_AGM, sample_fmts_s16, adpcm_agm, "ADPCM AmuseGraphics Movie") ADPCM_DECODER(ADPCM_AICA, sample_fmts_s16p, adpcm_aica, "ADPCM Yamaha AICA") ADPCM_DECODER(ADPCM_ARGO, sample_fmts_s16p, adpcm_argo, "ADPCM Argonaut Games") +ADPCM_DECODER(ADPCM_CIRCUS, sample_fmts_s16, adpcm_circus, "ADPCM Circus") ADPCM_DECODER(ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology") ADPCM_DECODER(ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK") ADPCM_DECODER(ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 67e02ef7bb..77a13d9b0c 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -649,6 +649,7 @@ extern const FFCodec ff_adpcm_agm_decoder; extern const FFCodec ff_adpcm_aica_decoder; extern const FFCodec ff_adpcm_argo_decoder; extern const FFCodec ff_adpcm_argo_encoder; +extern const FFCodec ff_adpcm_circus_decoder; extern const FFCodec ff_adpcm_ct_decoder; extern const FFCodec ff_adpcm_dtk_decoder; extern const FFCodec ff_adpcm_ea_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 1493f34730..30793a2a26 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2676,6 +2676,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Playstation C"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_CIRCUS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_circus", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Circus"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 975ebbe880..feb4d61708 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -433,6 +433,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_HVQM2, AV_CODEC_ID_ADPCM_IMA_MAGIX, AV_CODEC_ID_ADPCM_PSXC, + AV_CODEC_ID_ADPCM_CIRCUS, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index b65e10827e..d89e886a08 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -488,6 +488,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_CBD2_DPCM: case AV_CODEC_ID_DERF_DPCM: case AV_CODEC_ID_WADY_DPCM: + case AV_CODEC_ID_ADPCM_CIRCUS: return 8; case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_S16BE_PLANAR: -- 2.49.1 >From da35b4f120683790e5c1dbaf2998d1b46dc5b6aa Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 8 Mar 2025 19:40:46 +0000 Subject: [PATCH 13/15] avcodec: add ADPCM IMA Escape audio decoder (cherry picked from commit 4a663e78c4421da226e7d480d6767de803ee2122) --- libavcodec/Makefile | 1 + libavcodec/adpcm.c | 32 ++++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/codec_id.h | 1 + libavformat/rpl.c | 2 +- 6 files changed, 43 insertions(+), 1 deletion(-) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 1e6e00b154..6c2412df0d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -985,6 +985,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_ESCAPE_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_HVQM2_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 diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 76404bcf08..c782ed007e 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -418,6 +418,29 @@ static inline int16_t adpcm_agm_expand_nibble(ADPCMChannelStatus *c, int8_t nibb return pred; } +static inline int16_t adpcm_ima_escape_expand_nibble(ADPCMChannelStatus *c, int8_t nibble) +{ + int step_index; + int predictor; + int sign, delta, diff, step; + + step = ff_adpcm_step_table[c->step_index]; + step_index = c->step_index + ff_adpcm_index_table[(unsigned)nibble]; + step_index = av_clip(step_index, 0, 88); + + sign = nibble & 8; + delta = nibble & 7; + diff = (delta * step) >> 2; + predictor = c->predictor; + if (sign) predictor -= diff; + else predictor += diff; + + c->predictor = av_clip_int16(predictor); + c->step_index = step_index; + + return (int16_t)c->predictor; +} + static inline int16_t adpcm_ima_expand_nibble(ADPCMChannelStatus *c, int8_t nibble, int shift) { int step_index; @@ -1169,6 +1192,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_IMA_APC: case AV_CODEC_ID_ADPCM_IMA_CUNNING: case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: + case AV_CODEC_ID_ADPCM_IMA_ESCAPE: case AV_CODEC_ID_ADPCM_IMA_OKI: case AV_CODEC_ID_ADPCM_IMA_WS: case AV_CODEC_ID_ADPCM_YAMAHA: @@ -2013,6 +2037,13 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, bytestream2_skip(&gb, bytes_remaining); } ) /* End of CASE */ + CASE(ADPCM_IMA_ESCAPE, + for (int n = nb_samples >> (1 - st); n > 0; n--) { + int byte = bytestream2_get_byteu(&gb); + *samples++ = adpcm_ima_escape_expand_nibble(&c->status[0], byte >> 4); + *samples++ = adpcm_ima_escape_expand_nibble(&c->status[st], byte & 0xF); + } + ) /* End of CASE */ CASE(ADPCM_IMA_EA_EACS, for (int i = 0; i <= st; i++) { c->status[i].step_index = bytestream2_get_le32u(&gb); @@ -2956,6 +2987,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_ESCAPE, sample_fmts_s16, adpcm_ima_escape, "ADPCM IMA Acorn Escape") ADPCM_DECODER(ADPCM_IMA_HVQM2, sample_fmts_s16, adpcm_ima_hvqm2, "ADPCM IMA HVQM2") 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") diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 77a13d9b0c..ae48c414e8 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -678,6 +678,7 @@ extern const FFCodec ff_adpcm_ima_dk3_decoder; extern const FFCodec ff_adpcm_ima_dk4_decoder; extern const FFCodec ff_adpcm_ima_ea_eacs_decoder; extern const FFCodec ff_adpcm_ima_ea_sead_decoder; +extern const FFCodec ff_adpcm_ima_escape_decoder; extern const FFCodec ff_adpcm_ima_hvqm2_decoder; extern const FFCodec ff_adpcm_ima_hvqm4_decoder; extern const FFCodec ff_adpcm_ima_iss_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 30793a2a26..526a85e262 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2683,6 +2683,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Circus"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_ESCAPE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_escape", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Acorn Escape"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index feb4d61708..8c98ac6335 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -434,6 +434,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_MAGIX, AV_CODEC_ID_ADPCM_PSXC, AV_CODEC_ID_ADPCM_CIRCUS, + AV_CODEC_ID_ADPCM_IMA_ESCAPE, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavformat/rpl.c b/libavformat/rpl.c index b30d769efb..781dabf7ba 100644 --- a/libavformat/rpl.c +++ b/libavformat/rpl.c @@ -250,7 +250,7 @@ static int rpl_read_header(AVFormatContext *s) // are all unsigned. ast->codecpar->codec_id = AV_CODEC_ID_PCM_U8; } else if (ast->codecpar->bits_per_coded_sample == 4) { - ast->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_EA_SEAD; + ast->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_ESCAPE; } break; } -- 2.49.1 >From 5ea4971647978ff29d12ed89ee8106ee6ff795ac Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 17 Mar 2025 21:01:16 +0000 Subject: [PATCH 14/15] avcodec/adpcm: improve decooding output for 4-bit ADPCM IMA WAV (cherry picked from commit f11422f1a6251e2b3c42b4044efbc722b863778d) --- libavcodec/adpcm.c | 4 ++-- tests/ref/acodec/adpcm-ima_wav | 4 ++-- tests/ref/acodec/adpcm-ima_wav-trellis | 4 ++-- tests/ref/fate/adpcm-ima_wav-stereo | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index c782ed007e..13003db760 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1549,8 +1549,8 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, samples = &samples_p[i][1 + n * 8]; for (int m = 0; m < 8; m += 2) { int v = bytestream2_get_byteu(&gb); - samples[m ] = adpcm_ima_expand_nibble(cs, v & 0x0F, 3); - samples[m + 1] = adpcm_ima_expand_nibble(cs, v >> 4 , 3); + samples[m ] = ff_adpcm_ima_qt_expand_nibble(cs, v & 0x0F); + samples[m + 1] = ff_adpcm_ima_qt_expand_nibble(cs, v >> 4); } } } diff --git a/tests/ref/acodec/adpcm-ima_wav b/tests/ref/acodec/adpcm-ima_wav index 44ca53a565..b2cc518b1e 100644 --- a/tests/ref/acodec/adpcm-ima_wav +++ b/tests/ref/acodec/adpcm-ima_wav @@ -1,4 +1,4 @@ af0b82a719762cc6e1a952a6081231cf *tests/data/fate/acodec-adpcm-ima_wav.wav 267324 tests/data/fate/acodec-adpcm-ima_wav.wav -78a2af1c895792d0c221d127bdd48ece *tests/data/fate/acodec-adpcm-ima_wav.out.wav -stddev: 903.51 PSNR: 37.21 MAXDIFF:34026 bytes: 1058400/ 1061748 +a57d7b0ca564b5fed4bf78fc9f91d8e2 *tests/data/fate/acodec-adpcm-ima_wav.out.wav +stddev: 903.56 PSNR: 37.21 MAXDIFF:34029 bytes: 1058400/ 1061748 diff --git a/tests/ref/acodec/adpcm-ima_wav-trellis b/tests/ref/acodec/adpcm-ima_wav-trellis index 29c28edddf..008d1e4b62 100644 --- a/tests/ref/acodec/adpcm-ima_wav-trellis +++ b/tests/ref/acodec/adpcm-ima_wav-trellis @@ -1,4 +1,4 @@ 6f0df0f3275f833c341d63b9054caebb *tests/data/fate/acodec-adpcm-ima_wav-trellis.wav 267324 tests/data/fate/acodec-adpcm-ima_wav-trellis.wav -26a9b280c14737b159c56e60181f1170 *tests/data/fate/acodec-adpcm-ima_wav-trellis.out.wav -stddev: 710.03 PSNR: 39.30 MAXDIFF:25944 bytes: 1058400/ 1061748 +1af83218cde84bd7cd2297c04ef97f79 *tests/data/fate/acodec-adpcm-ima_wav-trellis.out.wav +stddev: 710.09 PSNR: 39.30 MAXDIFF:25941 bytes: 1058400/ 1061748 diff --git a/tests/ref/fate/adpcm-ima_wav-stereo b/tests/ref/fate/adpcm-ima_wav-stereo index cb6a481999..2a36800951 100644 --- a/tests/ref/fate/adpcm-ima_wav-stereo +++ b/tests/ref/fate/adpcm-ima_wav-stereo @@ -1 +1 @@ -1ee96f1efc09251a732621049dc5b66e +b4697f4f64c12afb37acfebd5f7a756c -- 2.49.1 >From 02ea6cf9a8fb678bb36322b9b71d5a8d43427440 Mon Sep 17 00:00:00 2001 From: asivery Date: Sat, 15 Jun 2024 07:47:40 +0200 Subject: [PATCH 15/15] avformat/aeadec, avcodec/atrac1: Fix 8 and 4-channel ATRAC1 support Signed-off-by: asivery (cherry picked from commit 81cdf42222961c2959f1ede2d86fea0d1dcbbfcb) --- libavcodec/atrac1.c | 12 ++++++------ libavformat/aeadec.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libavcodec/atrac1.c b/libavcodec/atrac1.c index f0bef9b9e6..b708c31897 100644 --- a/libavcodec/atrac1.c +++ b/libavcodec/atrac1.c @@ -49,7 +49,7 @@ #define AT1_SU_SAMPLES 512 ///< number of samples in a sound unit #define AT1_FRAME_SIZE AT1_SU_SIZE * 2 #define AT1_SU_MAX_BITS AT1_SU_SIZE * 8 -#define AT1_MAX_CHANNELS 2 +#define AT1_MAX_CHANNELS 8 #define AT1_QMF_BANDS 3 #define IDX_LOW_BAND 0 @@ -339,7 +339,7 @@ static av_cold int atrac1_decode_init(AVCodecContext *avctx) AVFloatDSPContext *fdsp; int channels = avctx->ch_layout.nb_channels; float scale = -1.0 / (1 << 15); - int ret; + int ret, ch; avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; @@ -380,10 +380,10 @@ static av_cold int atrac1_decode_init(AVCodecContext *avctx) q->bands[2] = q->high; /* Prepare the mdct overlap buffers */ - q->SUs[0].spectrum[0] = q->SUs[0].spec1; - q->SUs[0].spectrum[1] = q->SUs[0].spec2; - q->SUs[1].spectrum[0] = q->SUs[1].spec1; - q->SUs[1].spectrum[1] = q->SUs[1].spec2; + for (ch = 0; ch < AT1_MAX_CHANNELS; ch++) { + q->SUs[ch].spectrum[0] = q->SUs[ch].spec1; + q->SUs[ch].spectrum[1] = q->SUs[ch].spec2; + } return 0; } diff --git a/libavformat/aeadec.c b/libavformat/aeadec.c index be18e7b725..0a3d09a89d 100644 --- a/libavformat/aeadec.c +++ b/libavformat/aeadec.c @@ -84,7 +84,7 @@ static int aea_read_header(AVFormatContext *s) st->codecpar->sample_rate = 44100; st->codecpar->bit_rate = 146000 * channels; - if (channels != 1 && channels != 2) { + if (channels < 1 || channels > 8) { av_log(s, AV_LOG_ERROR, "Channels %d not supported!\n", channels); return AVERROR_INVALIDDATA; } -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".