[FFmpeg-devel] [PATCH] ADPCM IMA WAV 2, 3 and 5 bits decoder
Paul B Mahol
onemda at gmail.com
Tue Jul 2 23:30:44 CEST 2013
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
Fixes #625.
Stereo files on that ticket do not match specification and lacks sanity,
as samples are most likely incorrectly interleaved.
---
libavcodec/Makefile | 2 +-
libavcodec/adpcm.c | 31 ++++++++++++++++++++++++++-----
libavcodec/adpcm_data.c | 23 ++++++++++++++++++++++-
libavcodec/adpcm_data.h | 4 ++++
libavcodec/adpcm_ima.c | 26 ++++++++++++++++++++++++++
libavcodec/adpcm_ima.h | 4 ++++
libavcodec/utils.c | 5 +++--
7 files changed, 86 insertions(+), 9 deletions(-)
create mode 100644 libavcodec/adpcm_ima.c
create mode 100644 libavcodec/adpcm_ima.h
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index c6cd41b..99a9563 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -597,7 +597,7 @@ OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER) += adpcm.o adpcm_data.o
-OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o adpcm_ima.o
OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_WS_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_MS_DECODER) += adpcm.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 1259bd4..d51a1f4 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -35,6 +35,7 @@
#include "adpcm.h"
#include "adpcm_data.h"
#include "internal.h"
+#include "adpcm_ima.h"
/**
* @file
@@ -118,10 +119,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) {
@@ -557,10 +556,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 +723,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] = ff_adpcm_ima_expand_nibble(cs, &g,
+ avctx->bits_per_coded_sample - 1);
+ }
+ }
+ }
+ 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 +751,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 0625fc9..1d3e579 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 0ebb7c3..2f62c28 100644
--- a/libavcodec/adpcm_data.h
+++ b/libavcodec/adpcm_data.h
@@ -28,6 +28,10 @@
#include <stdint.h>
+static const uint8_t ff_adpcm_ima_block_sizes[4] = { 8, 12, 4, 20 };
+static const uint8_t ff_adpcm_ima_block_samples[4] = { 32, 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/adpcm_ima.c b/libavcodec/adpcm_ima.c
new file mode 100644
index 0000000..4a74d64
--- /dev/null
+++ b/libavcodec/adpcm_ima.c
@@ -0,0 +1,26 @@
+#define BITSTREAM_READER_LE
+#include "adpcm_data.h"
+#include "adpcm_ima.h"
+#include "get_bits.h"
+
+inline int16_t ff_adpcm_ima_expand_nibble(ADPCMChannelStatus *c, GetBitContext *gb, int shift)
+{
+ int nibble, step_index, predictor, sign, delta, diff, step;
+
+ nibble = get_bits(gb, shift + 1),
+ step = ff_adpcm_step_table[c->step_index];
+ step_index = c->step_index + ff_adpcm_index_tables[shift - 1][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;
+}
diff --git a/libavcodec/adpcm_ima.h b/libavcodec/adpcm_ima.h
new file mode 100644
index 0000000..b12fbe1
--- /dev/null
+++ b/libavcodec/adpcm_ima.h
@@ -0,0 +1,4 @@
+#include "adpcm.h"
+#include "get_bits.h"
+
+int16_t ff_adpcm_ima_expand_nibble(ADPCMChannelStatus *c, GetBitContext *gb, int shift);
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index f26e260..c5dcd8b 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -2759,7 +2759,6 @@ int av_get_bits_per_sample(enum AVCodecID codec_id)
case AV_CODEC_ID_ADPCM_SBPRO_3:
return 3;
case AV_CODEC_ID_ADPCM_SBPRO_4:
- case AV_CODEC_ID_ADPCM_IMA_WAV:
case AV_CODEC_ID_ADPCM_IMA_QT:
case AV_CODEC_ID_ADPCM_SWF:
case AV_CODEC_ID_ADPCM_MS:
@@ -2899,7 +2898,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:
--
1.7.11.2
More information about the ffmpeg-devel
mailing list