avcodec: add ADPCM Silicon Graphics N64 decoder

(cherry picked from commit 13484237fdf19c9d927b8a64b81d00100a4178c3)
This commit is contained in:
Paul B Mahol 2024-11-25 13:01:16 +00:00 committed by michaelni
parent 648b5d017d
commit 5fc9c79f53
6 changed files with 104 additions and 0 deletions

View file

@ -1006,6 +1006,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_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.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_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_PSX_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_SANYO_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_2_DECODER) += adpcm.o adpcm_data.o

View file

@ -261,6 +261,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
switch(avctx->codec->id) { switch(avctx->codec->id) {
case AV_CODEC_ID_ADPCM_IMA_AMV: case AV_CODEC_ID_ADPCM_IMA_AMV:
case AV_CODEC_ID_ADPCM_N64:
max_channels = 1; max_channels = 1;
break; break;
case AV_CODEC_ID_ADPCM_SANYO: case AV_CODEC_ID_ADPCM_SANYO:
@ -352,6 +353,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
case AV_CODEC_ID_ADPCM_MTAF: case AV_CODEC_ID_ADPCM_MTAF:
case AV_CODEC_ID_ADPCM_ARGO: case AV_CODEC_ID_ADPCM_ARGO:
case AV_CODEC_ID_ADPCM_IMA_MOFLEX: case AV_CODEC_ID_ADPCM_IMA_MOFLEX:
case AV_CODEC_ID_ADPCM_N64:
avctx->sample_fmt = AV_SAMPLE_FMT_S16P; avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
break; break;
case AV_CODEC_ID_ADPCM_IMA_WS: case AV_CODEC_ID_ADPCM_IMA_WS:
@ -1095,6 +1097,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
return 0; return 0;
nb_samples = 64; nb_samples = 64;
break; break;
case AV_CODEC_ID_ADPCM_N64:
nb_samples = (buf_size / 9) * 16;
break;
/* simple 4-bit adpcm */ /* simple 4-bit adpcm */
case AV_CODEC_ID_ADPCM_CT: case AV_CODEC_ID_ADPCM_CT:
case AV_CODEC_ID_ADPCM_IMA_APC: case AV_CODEC_ID_ADPCM_IMA_APC:
@ -2493,6 +2498,89 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame,
bytestream2_seek(&gb, 0, SEEK_SET); bytestream2_seek(&gb, 0, SEEK_SET);
} }
) /* End of CASE */ ) /* 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, CASE(ADPCM_PSX,
for (int block = 0; block < avpkt->size / FFMAX(avctx->block_align, 16 * channels); block++) { 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); int nb_samples_per_block = 28 * FFMAX(avctx->block_align, 16 * channels) / (16 * channels);
@ -2741,6 +2829,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_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_MS, sample_fmts_both, adpcm_ms, "ADPCM Microsoft")
ADPCM_DECODER(ADPCM_MTAF, sample_fmts_s16p, adpcm_mtaf, "ADPCM MTAF") 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_PSX, sample_fmts_s16p, adpcm_psx, "ADPCM Playstation")
ADPCM_DECODER(ADPCM_SANYO, sample_fmts_s16p, adpcm_sanyo, "ADPCM Sanyo") 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_2, sample_fmts_s16, adpcm_sbpro_2, "ADPCM Sound Blaster Pro 2-bit")

View file

@ -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_encoder;
extern const FFCodec ff_adpcm_ms_decoder; extern const FFCodec ff_adpcm_ms_decoder;
extern const FFCodec ff_adpcm_mtaf_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_psx_decoder;
extern const FFCodec ff_adpcm_sanyo_decoder; extern const FFCodec ff_adpcm_sanyo_decoder;
extern const FFCodec ff_adpcm_sbpro_2_decoder; extern const FFCodec ff_adpcm_sbpro_2_decoder;

View file

@ -2648,6 +2648,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA PlayDate"), .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA PlayDate"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, .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 */ /* AMR */
{ {

View file

@ -429,6 +429,7 @@ enum AVCodecID {
AV_CODEC_ID_ADPCM_SANYO, AV_CODEC_ID_ADPCM_SANYO,
AV_CODEC_ID_ADPCM_IMA_HVQM4, AV_CODEC_ID_ADPCM_IMA_HVQM4,
AV_CODEC_ID_ADPCM_IMA_PDA, AV_CODEC_ID_ADPCM_IMA_PDA,
AV_CODEC_ID_ADPCM_N64,
/* AMR */ /* AMR */
AV_CODEC_ID_AMR_NB = 0x12000, AV_CODEC_ID_AMR_NB = 0x12000,

View file

@ -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; return (frame_bytes - 4 * ch) / (128 * ch) * 256;
case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_AFC:
return frame_bytes / (9 * ch) * 16; 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_PSX:
case AV_CODEC_ID_ADPCM_DTK: case AV_CODEC_ID_ADPCM_DTK:
frame_bytes /= 16 * ch; frame_bytes /= 16 * ch;