summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin Ruggles <justin.ruggles@gmail.com>2011-11-20 14:21:32 -0500
committerJustin Ruggles <justin.ruggles@gmail.com>2011-11-26 16:25:06 -0500
commitb237248e297760648307356efa5fcbfe16844829 (patch)
tree76ac03216c87ddc68904f9abe3e1e5a89c25604b
parent954d94dd5e13ba7a5e9e049d0f980bddced9644c (diff)
downloadffmpeg-streaming-b237248e297760648307356efa5fcbfe16844829.zip
ffmpeg-streaming-b237248e297760648307356efa5fcbfe16844829.tar.gz
adx: calculate correct LPC coeffs
Instead of using fixed coefficients, the correct way is to calculate the coefficients using the highpass cutoff frequency from the ADX stream header and the sample rate.
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/adx.c34
-rw-r--r--libavcodec/adx.h14
-rw-r--r--libavcodec/adxdec.c7
-rw-r--r--libavcodec/adxenc.c27
5 files changed, 70 insertions, 14 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 37aa8ee..2cdcca2 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -489,7 +489,7 @@ OBJS-$(CONFIG_PCM_U32LE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o
OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.o
-OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o
+OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o
OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o
diff --git a/libavcodec/adx.c b/libavcodec/adx.c
new file mode 100644
index 0000000..bc3e882
--- /dev/null
+++ b/libavcodec/adx.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Justin Ruggles
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/mathematics.h"
+#include "adx.h"
+
+void ff_adx_calculate_coeffs(int cutoff, int sample_rate, int bits, int *coeff)
+{
+ double a, b, c;
+
+ a = M_SQRT2 - cos(2.0 * M_PI * cutoff / sample_rate);
+ b = M_SQRT2 - 1.0;
+ c = (a - sqrt((a + b) * (a - b))) / b;
+
+ coeff[0] = lrintf(c * 2.0 * (1 << bits));
+ coeff[1] = lrintf(-(c * c) * (1 << bits));
+}
diff --git a/libavcodec/adx.h b/libavcodec/adx.h
index ae5eb6a..cd8c45b 100644
--- a/libavcodec/adx.h
+++ b/libavcodec/adx.h
@@ -41,10 +41,20 @@ typedef struct {
int header_parsed;
unsigned char dec_temp[18*2];
int in_temp;
+ int cutoff;
+ int coeff[2];
} ADXContext;
#define COEFF_BITS 12
-#define COEFF1 0x1CA6
-#define COEFF2 0x0CD4
+
+/**
+ * Calculate LPC coefficients based on cutoff frequency and sample rate.
+ *
+ * @param cutoff cutoff frequency
+ * @param sample_rate sample rate
+ * @param bits number of bits used to quantize coefficients
+ * @param[out] coeff 2 quantized LPC coefficients
+ */
+void ff_adx_calculate_coeffs(int cutoff, int sample_rate, int bits, int *coeff);
#endif /* AVCODEC_ADX_H */
diff --git a/libavcodec/adxdec.c b/libavcodec/adxdec.c
index 93bbc6b..f9f17cd 100644
--- a/libavcodec/adxdec.c
+++ b/libavcodec/adxdec.c
@@ -59,7 +59,7 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch)
s2 = prev->s2;
for (i = 0; i < 32; i++) {
d = get_sbits(&gb, 4);
- s0 = ((d << COEFF_BITS) * scale + COEFF1 * s1 - COEFF2 * s2) >> COEFF_BITS;
+ s0 = ((d << COEFF_BITS) * scale + c->coeff[0] * s1 + c->coeff[1] * s2) >> COEFF_BITS;
s2 = s1;
s1 = av_clip_int16(s0);
*out = s1;
@@ -81,7 +81,7 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
int bufsize)
{
ADXContext *c = avctx->priv_data;
- int offset;
+ int offset, cutoff;
if (AV_RB16(buf) != 0x8000)
return AVERROR_INVALIDDATA;
@@ -98,6 +98,9 @@ static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
return AVERROR_INVALIDDATA;
avctx->bit_rate = avctx->sample_rate * avctx->channels * 18 * 8 / 32;
+ cutoff = AV_RB16(buf + 16);
+ ff_adx_calculate_coeffs(cutoff, avctx->sample_rate, COEFF_BITS, c->coeff);
+
return offset;
}
diff --git a/libavcodec/adxenc.c b/libavcodec/adxenc.c
index 7225c31..b85a70d 100644
--- a/libavcodec/adxenc.c
+++ b/libavcodec/adxenc.c
@@ -34,7 +34,7 @@
/* 18 bytes <-> 32 samples */
-static void adx_encode(unsigned char *adx,const short *wav,
+static void adx_encode(ADXContext *c, unsigned char *adx, const short *wav,
ADXChannelState *prev)
{
int scale;
@@ -48,7 +48,7 @@ static void adx_encode(unsigned char *adx,const short *wav,
s2 = prev->s2;
for(i=0;i<32;i++) {
s0 = wav[i];
- d = ((s0 << COEFF_BITS) - COEFF1 * s1 + COEFF2 * s2) >> COEFF_BITS;
+ d = ((s0 << COEFF_BITS) - c->coeff[0] * s1 - c->coeff[1] * s2) >> COEFF_BITS;
data[i]=d;
if (max<d) max=d;
if (min>d) min=d;
@@ -102,19 +102,24 @@ static int adx_encode_header(AVCodecContext *avctx,unsigned char *buf,size_t buf
} adxhdr; /* big endian */
/* offset-6 "(c)CRI" */
#endif
+ ADXContext *c = avctx->priv_data;
+
AV_WB32(buf+0x00,0x80000000|0x20);
AV_WB32(buf+0x04,0x03120400|avctx->channels);
AV_WB32(buf+0x08,avctx->sample_rate);
AV_WB32(buf+0x0c,0); /* FIXME: set after */
- AV_WB32(buf+0x10,0x01040300);
- AV_WB32(buf+0x14,0x00000000);
- AV_WB32(buf+0x18,0x00000000);
- memcpy(buf+0x1c,"\0\0(c)CRI",8);
+ AV_WB16(buf + 0x10, c->cutoff);
+ AV_WB32(buf + 0x12, 0x03000000);
+ AV_WB32(buf + 0x16, 0x00000000);
+ AV_WB32(buf + 0x1a, 0x00000000);
+ memcpy (buf + 0x1e, "(c)CRI", 6);
return 0x20+4;
}
static av_cold int adx_encode_init(AVCodecContext *avctx)
{
+ ADXContext *c = avctx->priv_data;
+
if (avctx->channels > 2)
return -1; /* only stereo or mono =) */
avctx->frame_size = 32;
@@ -124,6 +129,10 @@ static av_cold int adx_encode_init(AVCodecContext *avctx)
// avctx->bit_rate = avctx->sample_rate*avctx->channels*18*8/32;
+ /* the cutoff can be adjusted, but this seems to work pretty well */
+ c->cutoff = 500;
+ ff_adx_calculate_coeffs(c->cutoff, avctx->sample_rate, COEFF_BITS, c->coeff);
+
av_log(avctx, AV_LOG_DEBUG, "adx encode init\n");
return 0;
@@ -159,7 +168,7 @@ static int adx_encode_frame(AVCodecContext *avctx,
if (avctx->channels==1) {
while(rest>=32) {
- adx_encode(dst,samples,c->prev);
+ adx_encode(c, dst, samples, c->prev);
dst+=18;
samples+=32;
rest-=32;
@@ -174,8 +183,8 @@ static int adx_encode_frame(AVCodecContext *avctx,
tmpbuf[i+32] = samples[i*2+1];
}
- adx_encode(dst,tmpbuf,c->prev);
- adx_encode(dst+18,tmpbuf+32,c->prev+1);
+ adx_encode(c, dst, tmpbuf, c->prev);
+ adx_encode(c, dst + 18, tmpbuf + 32, c->prev + 1);
dst+=18*2;
samples+=32*2;
rest-=32*2;
OpenPOWER on IntegriCloud