From 6516a25f04edc90b8dbc8b7f48120b08b7517ae2 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 1 Dec 2012 14:52:22 +0000 Subject: [PATCH] ADPCM IMA WAV 2, 3 and 5 bits decoder Signed-off-by: Paul B Mahol --- libavcodec/adpcm.c | 53 +++++++++++++++++++++++++++++++++++++---- libavcodec/adpcm_data.c | 23 +++++++++++++++++- libavcodec/adpcm_data.h | 4 ++++ libavcodec/utils.c | 4 +++- 4 files changed, 77 insertions(+), 7 deletions(-) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 1259bd4df6..dbbb358b44 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -118,10 +118,8 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) c->status[0].step = c->status[1].step = 511; break; case AV_CODEC_ID_ADPCM_IMA_WAV: - if (avctx->bits_per_coded_sample != 4) { - av_log(avctx, AV_LOG_ERROR, "Only 4-bit ADPCM IMA WAV files are supported\n"); - return -1; - } + if (avctx->bits_per_coded_sample < 2 || avctx->bits_per_coded_sample > 5) + return AVERROR_INVALIDDATA; break; case AV_CODEC_ID_ADPCM_IMA_APC: if (avctx->extradata && avctx->extradata_size >= 8) { @@ -188,6 +186,29 @@ static inline short adpcm_ima_expand_nibble(ADPCMChannelStatus *c, char nibble, return (short)c->predictor; } +static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitContext *gb, int bps) +{ + int nibble, step_index, predictor, sign, delta, diff, step, shift; + + shift = bps - 1; + nibble = get_bits_le(gb, bps), + step = ff_adpcm_step_table[c->step_index]; + step_index = c->step_index + ff_adpcm_index_tables[bps - 2][nibble]; + step_index = av_clip(step_index, 0, 88); + + sign = nibble & (1 << shift); + delta = nibble & ((1 << shift) - 1); + diff = ((2 * delta + 1) * step) >> shift; + 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 int adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble, int shift) { int step_index; @@ -557,10 +578,14 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, nb_samples = (buf_size - 4 * ch) * 2 / ch; break; case AV_CODEC_ID_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]; if (avctx->block_align > 0) buf_size = FFMIN(buf_size, avctx->block_align); - nb_samples = 1 + (buf_size - 4 * ch) / (4 * ch) * 8; + nb_samples = 1 + (buf_size - 4 * ch) / (bsize * ch) * bsamples; break; + } case AV_CODEC_ID_ADPCM_MS: if (avctx->block_align > 0) buf_size = FFMIN(buf_size, avctx->block_align); @@ -720,6 +745,23 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, } } + if (avctx->bits_per_coded_sample != 4) { + int samples_per_block = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2]; + GetBitContext g; + + init_get_bits8(&g, gb.buffer, bytestream2_get_bytes_left(&gb)); + for (n = 0; n < (nb_samples - 1) / samples_per_block; n++) { + for (i = 0; i < avctx->channels; i++) { + cs = &c->status[i]; + samples = &samples_p[i][1 + n * samples_per_block]; + for (m = 0; m < samples_per_block; m++) { + samples[m] = adpcm_ima_wav_expand_nibble(cs, &g, + avctx->bits_per_coded_sample); + } + } + } + bytestream2_skip(&gb, avctx->block_align - avctx->channels * 4); + } else { for (n = 0; n < (nb_samples - 1) / 8; n++) { for (i = 0; i < avctx->channels; i++) { cs = &c->status[i]; @@ -731,6 +773,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, } } } + } break; case AV_CODEC_ID_ADPCM_4XM: for (i = 0; i < avctx->channels; i++) diff --git a/libavcodec/adpcm_data.c b/libavcodec/adpcm_data.c index 0625fc9464..1d3e579a89 100644 --- a/libavcodec/adpcm_data.c +++ b/libavcodec/adpcm_data.c @@ -27,12 +27,33 @@ /* ff_adpcm_step_table[] and ff_adpcm_index_table[] are from the ADPCM reference source */ -/* This is the index table: */ +static const int8_t adpcm_index_table2[4] = { + -1, 2, + -1, 2, +}; + +static const int8_t adpcm_index_table3[8] = { + -1, -1, 1, 2, + -1, -1, 1, 2, +}; + const int8_t ff_adpcm_index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8, }; +static const int8_t adpcm_index_table5[32] = { + -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16, + -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16, +}; + +const int8_t const *ff_adpcm_index_tables[4] = { + &adpcm_index_table2[0], + &adpcm_index_table3[0], + &ff_adpcm_index_table[0], + &adpcm_index_table5[0], +}; + /** * This is the step table. Note that many programs use slight deviations from * this table, but such deviations are negligible: diff --git a/libavcodec/adpcm_data.h b/libavcodec/adpcm_data.h index 0ebb7c3f04..a14d520885 100644 --- a/libavcodec/adpcm_data.h +++ b/libavcodec/adpcm_data.h @@ -28,6 +28,10 @@ #include +static const uint8_t ff_adpcm_ima_block_sizes[4] = { 4, 12, 4, 20 }; +static const uint8_t ff_adpcm_ima_block_samples[4] = { 16, 32, 8, 32 }; + +extern const int8_t const *ff_adpcm_index_tables[4]; extern const int8_t ff_adpcm_index_table[16]; extern const int16_t ff_adpcm_step_table[89]; extern const int16_t ff_adpcm_oki_step_table[49]; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index f26e260d3d..d77b5ec661 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -2899,7 +2899,9 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) int blocks = frame_bytes / ba; switch (avctx->codec_id) { case AV_CODEC_ID_ADPCM_IMA_WAV: - return blocks * (1 + (ba - 4 * ch) / (4 * ch) * 8); + if (bps < 2 || bps > 5) + return 0; + return blocks * (1 + (ba - 4 * ch) / (bps * ch) * 8); case AV_CODEC_ID_ADPCM_IMA_DK3: return blocks * (((ba - 16) * 2 / 3 * 4) / ch); case AV_CODEC_ID_ADPCM_IMA_DK4: