[FFmpeg-soc] [soc]: r3302 - alacenc/alacenc.c

jai_menon subversion at mplayerhq.hu
Fri Aug 15 08:44:30 CEST 2008


Author: jai_menon
Date: Fri Aug 15 08:44:29 2008
New Revision: 3302

Log:
add autocorrelation and quantization

Modified:
   alacenc/alacenc.c

Modified: alacenc/alacenc.c
==============================================================================
--- alacenc/alacenc.c	(original)
+++ alacenc/alacenc.c	Fri Aug 15 08:44:29 2008
@@ -21,6 +21,7 @@
 
 #include "avcodec.h"
 #include "bitstream.h"
+#include "dsputil.h"
 
 #define DEFAULT_FRAME_SIZE        4096
 #define DEFAULT_SAMPLE_SIZE       16
@@ -31,6 +32,9 @@
 
 #define ALAC_ESCAPE_CODE          0x1FF
 #define MAX_LPC_ORDER             30
+#define DEFAULT_MAX_PRED_ORDER    6
+#define MAX_LPC_PRECISION         9
+#define MAX_LPC_SHIFT             9
 
 typedef struct RiceContext {
     int history_mult;
@@ -56,6 +60,7 @@ typedef struct AlacEncodeContext {
     PutBitContext pbctx;
     RiceContext rc;
     LPCContext lpc[MAX_CHANNELS];
+    DSPContext dspctx;
     AVCodecContext *avctx;
 } AlacEncodeContext;
 
@@ -70,6 +75,102 @@ static void put_sbits(PutBitContext *pb,
     put_bits(pb, bits, val & ((1<<bits)-1));
 }
 
+/**
+ * Levinson-Durbin recursion.
+ * Produces LPC coefficients from autocorrelation data.
+ * TODO: reuse code from flacenc
+*/
+static void compute_lpc_coefs(const double *autoc, int max_order,
+                              double lpc[][MAX_LPC_ORDER], double *ref)
+{
+    int i, j, i2;
+    double r, err, tmp;
+    double lpc_tmp[MAX_LPC_ORDER];
+
+    for(i=0; i<max_order; i++) lpc_tmp[i] = 0;
+    err = autoc[0];
+
+    for(i=0; i<max_order; i++) {
+        r = -autoc[i+1];
+        for(j=0; j<i; j++) {
+            r -= lpc_tmp[j] * autoc[i-j];
+        }
+        r /= err;
+        ref[i] = fabs(r);
+
+        err *= 1.0 - (r * r);
+
+        i2 = (i >> 1);
+        lpc_tmp[i] = r;
+        for(j=0; j<i2; j++) {
+            tmp = lpc_tmp[j];
+            lpc_tmp[j] += r * lpc_tmp[i-1-j];
+            lpc_tmp[i-1-j] += r * tmp;
+        }
+        if(i & 1) {
+            lpc_tmp[j] += lpc_tmp[j] * r;
+        }
+
+        for(j=0; j<=i; j++) {
+            lpc[i][j] = -lpc_tmp[j];
+        }
+    }
+}
+
+/**
+ * Quantize LPC coefficients
+ * TODO: reuse code from flacenc
+ */
+static void quantize_lpc_coefs(double *lpc_in, int order, int precision,
+                               int32_t *lpc_out, int *shift)
+{
+    int i;
+    double cmax, error;
+    int32_t qmax;
+    int sh;
+
+    /* define maximum levels */
+    qmax = (1 << (precision - 1)) - 1;
+
+    /* find maximum coefficient value */
+    cmax = 0.0;
+    for(i=0; i<order; i++) {
+        cmax= FFMAX(cmax, fabs(lpc_in[i]));
+    }
+
+    /* if maximum value quantizes to zero, return all zeros */
+    if(cmax * (1 << MAX_LPC_SHIFT) < 1.0) {
+        *shift = 1;
+        memset(lpc_out, 0, sizeof(int32_t) * order);
+        return;
+    }
+
+    /* calculate level shift which scales max coeff to available bits */
+    sh = MAX_LPC_SHIFT;
+    while((cmax * (1 << sh) > qmax) && (sh > 0)) {
+        sh--;
+    }
+
+    /* since negative shift values are unsupported in decoder, scale down
+    coefficients instead */
+    if(sh == 0 && cmax > qmax) {
+        double scale = ((double)qmax) / cmax;
+        for(i=0; i<order; i++) {
+            lpc_in[i] *= scale;
+        }
+    }
+
+    /* output quantized coefficients and level shift */
+    error=0;
+    for(i=0; i<order; i++) {
+        error += lpc_in[i] * (1 << sh);
+        lpc_out[i] = av_clip(lrintf(error), -qmax, qmax);
+        error -= lpc_out[i];
+    }
+    *shift = sh;
+}
+
+
 static void allocate_sample_buffers(AlacEncodeContext *s)
 {
     int i = s->channels;
@@ -144,14 +245,16 @@ static void write_frame_header(AlacEncod
 
 static void calc_predictor_params(AlacEncodeContext *s, int ch)
 {
-    // Set default predictor parameters
-    s->lpc[ch].lpc_order      = 4;
-    s->lpc[ch].lpc_quant      = 12;
-    s->lpc[ch].lpc_coeff[0]   = 4;
-    s->lpc[ch].lpc_coeff[1]   = -6;
-    s->lpc[ch].lpc_coeff[2]   = 4;
-    s->lpc[ch].lpc_coeff[3]   = -1;
+    double autoc[MAX_LPC_ORDER+1];
+    double ref[MAX_LPC_ORDER];
+    double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER];
+    int order;
 
+    s->dspctx.flac_compute_autocorr(s->sample_buf[ch], s->avctx->frame_size, DEFAULT_MAX_PRED_ORDER, autoc);
+    compute_lpc_coefs(autoc, DEFAULT_MAX_PRED_ORDER, lpc, ref);
+    order = (ref[5] > ref[3]) ? 6 : 4;
+    s->lpc[ch].lpc_order = order;
+    quantize_lpc_coefs(lpc[order-1], order, MAX_LPC_PRECISION, s->lpc[ch].lpc_coeff, &s->lpc[ch].lpc_quant);
 }
 
 static void alac_linear_predictor(AlacEncodeContext *s, int ch)
@@ -351,6 +454,7 @@ static av_cold int alac_encode_init(AVCo
     avctx->coded_frame->key_frame = 1;
 
     s->avctx = avctx;
+    dsputil_init(&s->dspctx, avctx);
 
     allocate_sample_buffers(s);
 



More information about the FFmpeg-soc mailing list