From: Zane van Iperen <zane@zanevaniperen.com>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH] avcodec: add ADPCM IMA Ubisoft decoder
Date: Fri, 31 Dec 2021 17:09:29 +1000
Message-ID: <a2990a89-2cf8-d3c0-537d-bf15f4c3d38d@zanevaniperen.com> (raw)
In-Reply-To: <20211228053734.151556-1-zane@zanevaniperen.com>
Ping. Will apply (with the minor version bump I forgot) in a few days.
On 28/12/21 15:37, Zane van Iperen wrote:
> A simple, interleaved variant, but with initial state and
> extra, uncompressed samples. Found in Ubisoft soundbanks from
> early-2000's games (Splinter Cell, RS3, etc.)
>
> Signed-off-by: Zane van Iperen <zane@zanevaniperen.com>
> ---
> Changelog | 1 +
> doc/general_contents.texi | 1 +
> libavcodec/Makefile | 1 +
> libavcodec/adpcm.c | 69 +++++++++++++++++++++++++++++++++++++++
> libavcodec/allcodecs.c | 1 +
> libavcodec/codec_desc.c | 7 ++++
> libavcodec/codec_id.h | 1 +
> 7 files changed, 81 insertions(+)
>
> diff --git a/Changelog b/Changelog
> index edb4152d0f..58be0b9da5 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -44,6 +44,7 @@ version <next>:
> - yadif_videotoolbox filter
> - VideoToolbox ProRes encoder
> - anlmf audio filter
> +- ADPCM IMA Ubisoft decoder
>
>
> version 4.4:
> diff --git a/doc/general_contents.texi b/doc/general_contents.texi
> index df1692c8df..80506e8ab4 100644
> --- a/doc/general_contents.texi
> +++ b/doc/general_contents.texi
> @@ -1139,6 +1139,7 @@ following image formats are supported:
> @item ADPCM IMA High Voltage Software ALP @tab X @tab X
> @item ADPCM IMA QuickTime @tab X @tab X
> @item ADPCM IMA Simon & Schuster Interactive @tab X @tab X
> +@item ADPCM IMA Ubisoft @tab @tab X
> @item ADPCM IMA Ubisoft APM @tab X @tab X
> @item ADPCM IMA Loki SDL MJPEG @tab @tab X
> @item ADPCM IMA WAV @tab X @tab X
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 9577062eec..52839e1994 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -899,6 +899,7 @@ OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER) += adpcm.o adpcm_data.o
> OBJS-$(CONFIG_ADPCM_IMA_SSI_DECODER) += adpcm.o adpcm_data.o
> OBJS-$(CONFIG_ADPCM_IMA_SSI_ENCODER) += adpcmenc.o adpcm_data.o
> OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER) += adpcm.o adpcm_data.o
> +OBJS-$(CONFIG_ADPCM_IMA_UBISOFT_DECODER) += adpcm.o adpcm_data.o
> OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o
> OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o
> OBJS-$(CONFIG_ADPCM_IMA_WS_DECODER) += adpcm.o adpcm_data.o
> diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
> index cfde5f58b9..410fea8e21 100644
> --- a/libavcodec/adpcm.c
> +++ b/libavcodec/adpcm.c
> @@ -239,6 +239,7 @@ static const int8_t mtf_index_table[16] = {
> typedef struct ADPCMDecodeContext {
> ADPCMChannelStatus status[14];
> int vqa_version; /**< VQA version. Used for ADPCM_IMA_WS */
> + int extra_count; /**< Number of raw PCM samples to send */
> int has_status; /**< Status flag. Reset to 0 after a flush. */
> } ADPCMDecodeContext;
>
> @@ -301,6 +302,13 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
> if (avctx->bits_per_coded_sample != 4 || avctx->block_align != 17 * avctx->channels)
> return AVERROR_INVALIDDATA;
> break;
> + case AV_CODEC_ID_ADPCM_IMA_UBISOFT:
> + if (c->extra_count < 0)
> + return AVERROR_INVALIDDATA;
> +
> + if (c->extra_count > 0 && c->extra_count % avctx->channels != 0)
> + return AVERROR_INVALIDDATA;
> + break;
> case AV_CODEC_ID_ADPCM_ZORK:
> if (avctx->bits_per_coded_sample != 8)
> return AVERROR_INVALIDDATA;
> @@ -877,6 +885,10 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
> case AV_CODEC_ID_ADPCM_IMA_MTF:
> nb_samples = buf_size * 2 / ch;
> break;
> + /* simple 4-bit adpcm, with extra uncompressed samples */
> + case AV_CODEC_ID_ADPCM_IMA_UBISOFT:
> + nb_samples = (buf_size * 2 + s->extra_count) / ch;
> + break;
> }
> if (nb_samples)
> return nb_samples;
> @@ -1460,6 +1472,35 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
> *samples++ = adpcm_ima_qt_expand_nibble(&c->status[st], v & 0x0F);
> }
> ) /* End of CASE */
> + CASE(ADPCM_IMA_UBISOFT,
> + if (c->extra_count) {
> + int offset = avctx->extradata[0] == 6 ? 36 : 28;
> + nb_samples -= c->extra_count / avctx->channels;
> +
> + for (uint8_t *extra = avctx->extradata + offset; c->extra_count--; extra += 2) {
> + if (avctx->extradata[0] == 3)
> + *samples++ = AV_RB16(extra);
> + else
> + *samples++ = AV_RL16(extra);
> + }
> +
> + /* NB: This is enforced above. */
> + if (avctx->channels == 1) {
> + c->status[0].predictor = samples[-1];
> + } else {
> + c->status[0].predictor = samples[-2];
> + c->status[1].predictor = samples[-1];
> + }
> +
> + c->extra_count = 0;
> + }
> +
> + for (int n = nb_samples >> (1 - st); n > 0; n--) {
> + int v = bytestream2_get_byteu(&gb);
> + *samples++ = adpcm_ima_expand_nibble(&c->status[0], v >> 4, 3);
> + *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
> + }
> + ) /* End of CASE */
> CASE(ADPCM_IMA_APM,
> for (int n = nb_samples / 2; n > 0; n--) {
> for (int channel = 0; channel < avctx->channels; channel++) {
> @@ -2257,6 +2298,33 @@ static void adpcm_flush(AVCodecContext *avctx)
> if (avctx->extradata && avctx->extradata_size >= 2)
> c->vqa_version = AV_RL16(avctx->extradata);
> break;
> +
> + case AV_CODEC_ID_ADPCM_IMA_UBISOFT: {
> + if (avctx->extradata && avctx->extradata_size >= 28) {
> + uint8_t version = avctx->extradata[0];
> + uint32_t sample_offset = version == 6 ? 36 : 28;
> +
> + if (version == 3) {
> + c->extra_count = AV_RB16(avctx->extradata + 14);
> + c->status[0].predictor = AV_RB16(avctx->extradata + 16);
> + c->status[1].predictor = AV_RB16(avctx->extradata + 20);
> + } else {
> + c->extra_count = AV_RL16(avctx->extradata + 14);
> + c->status[0].predictor = AV_RL16(avctx->extradata + 16);
> + c->status[1].predictor = AV_RL16(avctx->extradata + 20);
> + }
> +
> + c->status[0].step_index = av_clip(avctx->extradata[18], 0, 88);
> + c->status[1].step_index = av_clip(avctx->extradata[22], 0, 88);
> +
> + c->extra_count = FFMIN(
> + c->extra_count,
> + (avctx->extradata_size - sample_offset) / 2 / sizeof(int16_t)
> + );
> + }
> + break;
> + }
> +
> default:
> /* Other codecs may want to handle this during decoding. */
> c->has_status = 0;
> @@ -2330,6 +2398,7 @@ ADPCM_DECODER(ADPCM_IMA_QT, sample_fmts_s16p, adpcm_ima_qt, "ADPCM IMA
> 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")
> ADPCM_DECODER(ADPCM_IMA_SMJPEG, sample_fmts_s16, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG")
> +ADPCM_DECODER(ADPCM_IMA_UBISOFT, sample_fmts_s16, adpcm_ima_ubisoft, "ADPCM IMA Ubisoft");
> ADPCM_DECODER(ADPCM_IMA_ALP, sample_fmts_s16, adpcm_ima_alp, "ADPCM IMA High Voltage Software ALP")
> ADPCM_DECODER(ADPCM_IMA_WAV, sample_fmts_s16p, adpcm_ima_wav, "ADPCM IMA WAV")
> ADPCM_DECODER(ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA Westwood")
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index d1e10197de..2a07888a8f 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -652,6 +652,7 @@ extern const AVCodec ff_adpcm_ima_rad_decoder;
> extern const AVCodec ff_adpcm_ima_ssi_decoder;
> extern const AVCodec ff_adpcm_ima_ssi_encoder;
> extern const AVCodec ff_adpcm_ima_smjpeg_decoder;
> +extern const AVCodec ff_adpcm_ima_ubisoft_decoder;
> extern const AVCodec ff_adpcm_ima_wav_encoder;
> extern const AVCodec ff_adpcm_ima_wav_decoder;
> extern const AVCodec ff_adpcm_ima_ws_encoder;
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index 0974ee03de..a892d8f853 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_UBISOFT,
> + .type = AVMEDIA_TYPE_AUDIO,
> + .name = "adpcm_ima_ubisoft",
> + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Ubisoft"),
> + .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..d7b47f88ce 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_UBISOFT,
>
> /* AMR */
> AV_CODEC_ID_AMR_NB = 0x12000,
_______________________________________________
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".
prev parent reply other threads:[~2021-12-31 7:09 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-28 5:37 Zane van Iperen
2021-12-31 7:09 ` Zane van Iperen [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a2990a89-2cf8-d3c0-537d-bf15f4c3d38d@zanevaniperen.com \
--to=zane@zanevaniperen.com \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git