[FFmpeg-cvslog] adx: calculate correct LPC coeffs

Justin Ruggles git at videolan.org
Sun Nov 27 00:39:15 CET 2011


ffmpeg | branch: master | Justin Ruggles <justin.ruggles at gmail.com> | Sun Nov 20 14:21:32 2011 -0500| [b237248e297760648307356efa5fcbfe16844829] | committer: Justin Ruggles

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.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=b237248e297760648307356efa5fcbfe16844829
---

 libavcodec/Makefile |    2 +-
 libavcodec/adx.c    |   34 ++++++++++++++++++++++++++++++++++
 libavcodec/adx.h    |   14 ++++++++++++--
 libavcodec/adxdec.c |    7 +++++--
 libavcodec/adxenc.c |   27 ++++++++++++++++++---------
 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;



More information about the ffmpeg-cvslog mailing list