[SCM] libav/experimental: flac-lpc patch by (Justin Ruggles jruggle earthlink net) tabs removed and regression.sh fixed (it was missing in the patch) by me

siretart at users.alioth.debian.org siretart at users.alioth.debian.org
Sun Jun 30 15:48:33 UTC 2013


The following commit has been merged in the experimental branch:
commit a403fc0324c0003339abbef90367fdba5adbf024
Author: Justin Ruggles <jruggle at earthlink.net>
Date:   Sun Jul 2 10:22:31 2006 +0000

    flac-lpc patch by (Justin Ruggles  jruggle earthlink net)
    tabs removed and regression.sh fixed (it was missing in the patch) by me
    
    Originally committed as revision 5572 to svn://svn.ffmpeg.org/ffmpeg/trunk

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 425b964..5b92017 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1983,6 +1983,58 @@ typedef struct AVCodecContext {
      * - decoding: unused
      */
     int b_sensitivity;
+
+    /**
+     * - encoding: set by user.
+     * - decoding: unused
+     */
+    int compression_level;
+#define FF_COMPRESSION_DEFAULT -1
+
+    /**
+     * sets whether to use LPC mode - used by FLAC encoder
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int use_lpc;
+
+    /**
+     * LPC coefficient precision - used by FLAC encoder
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int lpc_coeff_precision;
+
+    /**
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int min_prediction_order;
+
+    /**
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int max_prediction_order;
+
+    /**
+     * search method for selecting prediction order
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int prediction_order_method;
+
+    /**
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int min_partition_order;
+
+    /**
+     * - encoding: set by user.
+     * - decoding: unused.
+     */
+    int max_partition_order;
 } AVCodecContext;
 
 /**
diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c
index aba02ab..aec63ef 100644
--- a/libavcodec/flacenc.c
+++ b/libavcodec/flacenc.c
@@ -37,11 +37,38 @@
 #define FLAC_CHMODE_RIGHT_SIDE      9
 #define FLAC_CHMODE_MID_SIDE       10
 
+#define ORDER_METHOD_EST     0
+#define ORDER_METHOD_2LEVEL  1
+#define ORDER_METHOD_4LEVEL  2
+#define ORDER_METHOD_8LEVEL  3
+#define ORDER_METHOD_SEARCH  4
+
 #define FLAC_STREAMINFO_SIZE  34
 
+#define MIN_LPC_ORDER       1
+#define MAX_LPC_ORDER      32
+#define MAX_FIXED_ORDER     4
+#define MAX_PARTITION_ORDER 8
+#define MAX_PARTITIONS     (1 << MAX_PARTITION_ORDER)
+#define MAX_LPC_PRECISION  15
+#define MAX_LPC_SHIFT      15
+#define MAX_RICE_PARAM     14
+
+typedef struct CompressionOptions {
+    int compression_level;
+    int block_time_ms;
+    int use_lpc;
+    int lpc_coeff_precision;
+    int min_prediction_order;
+    int max_prediction_order;
+    int prediction_order_method;
+    int min_partition_order;
+    int max_partition_order;
+} CompressionOptions;
+
 typedef struct RiceContext {
     int porder;
-    int params[256];
+    int params[MAX_PARTITIONS];
 } RiceContext;
 
 typedef struct FlacSubframe {
@@ -49,6 +76,8 @@ typedef struct FlacSubframe {
     int type_code;
     int obits;
     int order;
+    int32_t coefs[MAX_LPC_ORDER];
+    int shift;
     RiceContext rc;
     int32_t samples[FLAC_MAX_BLOCKSIZE];
     int32_t residual[FLAC_MAX_BLOCKSIZE];
@@ -72,6 +101,7 @@ typedef struct FlacEncodeContext {
     int max_framesize;
     uint32_t frame_count;
     FlacFrame frame;
+    CompressionOptions options;
     AVCodecContext *avctx;
 } FlacEncodeContext;
 
@@ -112,13 +142,11 @@ static void write_streaminfo(FlacEncodeContext *s, uint8_t *header)
     /* MD5 signature = 0 */
 }
 
-#define BLOCK_TIME_MS 27
-
 /**
  * Sets blocksize based on samplerate
  * Chooses the closest predefined blocksize >= BLOCK_TIME_MS milliseconds
  */
-static int select_blocksize(int samplerate)
+static int select_blocksize(int samplerate, int block_time_ms)
 {
     int i;
     int target;
@@ -126,7 +154,7 @@ static int select_blocksize(int samplerate)
 
     assert(samplerate > 0);
     blocksize = flac_blocksizes[1];
-    target = (samplerate * BLOCK_TIME_MS) / 1000;
+    target = (samplerate * block_time_ms) / 1000;
     for(i=0; i<16; i++) {
         if(target >= flac_blocksizes[i] && flac_blocksizes[i] > blocksize) {
             blocksize = flac_blocksizes[i];
@@ -183,8 +211,198 @@ static int flac_encode_init(AVCodecContext *avctx)
         s->samplerate = freq;
     }
 
-    s->blocksize = select_blocksize(s->samplerate);
-    avctx->frame_size = s->blocksize;
+    /* set compression option defaults based on avctx->compression_level */
+    if(avctx->compression_level < 0) {
+        s->options.compression_level = 5;
+    } else {
+        s->options.compression_level = avctx->compression_level;
+    }
+    av_log(avctx, AV_LOG_DEBUG, " compression: %d\n", s->options.compression_level);
+
+    if(s->options.compression_level == 0) {
+        s->options.block_time_ms = 27;
+        s->options.use_lpc = 0;
+        s->options.min_prediction_order = 2;
+        s->options.max_prediction_order = 3;
+        s->options.prediction_order_method = ORDER_METHOD_EST;
+        s->options.min_partition_order = 2;
+        s->options.max_partition_order = 2;
+    } else if(s->options.compression_level == 1) {
+        s->options.block_time_ms = 27;
+        s->options.use_lpc = 0;
+        s->options.min_prediction_order = 0;
+        s->options.max_prediction_order = 4;
+        s->options.prediction_order_method = ORDER_METHOD_EST;
+        s->options.min_partition_order = 2;
+        s->options.max_partition_order = 2;
+    } else if(s->options.compression_level == 2) {
+        s->options.block_time_ms = 27;
+        s->options.use_lpc = 0;
+        s->options.min_prediction_order = 0;
+        s->options.max_prediction_order = 4;
+        s->options.prediction_order_method = ORDER_METHOD_EST;
+        s->options.min_partition_order = 0;
+        s->options.max_partition_order = 3;
+    } else if(s->options.compression_level == 3) {
+        s->options.block_time_ms = 105;
+        s->options.use_lpc = 1;
+        s->options.min_prediction_order = 1;
+        s->options.max_prediction_order = 6;
+        s->options.prediction_order_method = ORDER_METHOD_EST;
+        s->options.min_partition_order = 0;
+        s->options.max_partition_order = 3;
+    } else if(s->options.compression_level == 4) {
+        s->options.block_time_ms = 105;
+        s->options.use_lpc = 1;
+        s->options.min_prediction_order = 1;
+        s->options.max_prediction_order = 8;
+        s->options.prediction_order_method = ORDER_METHOD_EST;
+        s->options.min_partition_order = 0;
+        s->options.max_partition_order = 3;
+    } else if(s->options.compression_level == 5) {
+        s->options.block_time_ms = 105;
+        s->options.use_lpc = 1;
+        s->options.min_prediction_order = 1;
+        s->options.max_prediction_order = 8;
+        s->options.prediction_order_method = ORDER_METHOD_EST;
+        s->options.min_partition_order = 0;
+        s->options.max_partition_order = 8;
+    } else {
+        av_log(avctx, AV_LOG_ERROR, "invalid compression level: %d\n",
+               s->options.compression_level);
+        return -1;
+    }
+
+    /* set compression option overrides from AVCodecContext */
+    if(avctx->use_lpc >= 0) {
+        s->options.use_lpc = !!avctx->use_lpc;
+    }
+    av_log(avctx, AV_LOG_DEBUG, " use lpc: %s\n",
+           s->options.use_lpc? "yes" : "no");
+
+    if(avctx->min_prediction_order >= 0) {
+        if(s->options.use_lpc) {
+            if(avctx->min_prediction_order < MIN_LPC_ORDER ||
+                    avctx->min_prediction_order > MAX_LPC_ORDER) {
+                av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
+                       avctx->min_prediction_order);
+                return -1;
+            }
+        } else {
+            if(avctx->min_prediction_order > MAX_FIXED_ORDER) {
+                av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
+                       avctx->min_prediction_order);
+                return -1;
+            }
+        }
+        s->options.min_prediction_order = avctx->min_prediction_order;
+    }
+    if(avctx->max_prediction_order >= 0) {
+        if(s->options.use_lpc) {
+            if(avctx->max_prediction_order < MIN_LPC_ORDER ||
+                    avctx->max_prediction_order > MAX_LPC_ORDER) {
+                av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n",
+                       avctx->max_prediction_order);
+                return -1;
+            }
+        } else {
+            if(avctx->max_prediction_order > MAX_FIXED_ORDER) {
+                av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n",
+                       avctx->max_prediction_order);
+                return -1;
+            }
+        }
+        s->options.max_prediction_order = avctx->max_prediction_order;
+    }
+    if(s->options.max_prediction_order < s->options.min_prediction_order) {
+        av_log(avctx, AV_LOG_ERROR, "invalid prediction orders: min=%d max=%d\n",
+               s->options.min_prediction_order, s->options.max_prediction_order);
+        return -1;
+    }
+    av_log(avctx, AV_LOG_DEBUG, " prediction order: %d, %d\n",
+           s->options.min_prediction_order, s->options.max_prediction_order);
+
+    if(avctx->prediction_order_method >= 0) {
+        if(avctx->prediction_order_method > ORDER_METHOD_SEARCH) {
+            av_log(avctx, AV_LOG_ERROR, "invalid prediction order method: %d\n",
+                   avctx->prediction_order_method);
+            return -1;
+        }
+        s->options.prediction_order_method = avctx->prediction_order_method;
+    }
+    switch(avctx->prediction_order_method) {
+        case ORDER_METHOD_EST:    av_log(avctx, AV_LOG_DEBUG, " order method: %s\n",
+                                         "estimate"); break;
+        case ORDER_METHOD_2LEVEL: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n",
+                                         "2-level"); break;
+        case ORDER_METHOD_4LEVEL: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n",
+                                         "4-level"); break;
+        case ORDER_METHOD_8LEVEL: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n",
+                                         "8-level"); break;
+        case ORDER_METHOD_SEARCH: av_log(avctx, AV_LOG_DEBUG, " order method: %s\n",
+                                         "full search"); break;
+    }
+
+    if(avctx->min_partition_order >= 0) {
+        if(avctx->min_partition_order > MAX_PARTITION_ORDER) {
+            av_log(avctx, AV_LOG_ERROR, "invalid min partition order: %d\n",
+                   avctx->min_partition_order);
+            return -1;
+        }
+        s->options.min_partition_order = avctx->min_partition_order;
+    }
+    if(avctx->max_partition_order >= 0) {
+        if(avctx->max_partition_order > MAX_PARTITION_ORDER) {
+            av_log(avctx, AV_LOG_ERROR, "invalid max partition order: %d\n",
+                   avctx->max_partition_order);
+            return -1;
+        }
+        s->options.max_partition_order = avctx->max_partition_order;
+    }
+    if(s->options.max_partition_order < s->options.min_partition_order) {
+        av_log(avctx, AV_LOG_ERROR, "invalid partition orders: min=%d max=%d\n",
+               s->options.min_partition_order, s->options.max_partition_order);
+        return -1;
+    }
+    av_log(avctx, AV_LOG_DEBUG, " partition order: %d, %d\n",
+           s->options.min_partition_order, s->options.max_partition_order);
+
+    if(avctx->frame_size > 0) {
+        if(avctx->frame_size < FLAC_MIN_BLOCKSIZE ||
+                avctx->frame_size > FLAC_MIN_BLOCKSIZE) {
+            av_log(avctx, AV_LOG_ERROR, "invalid block size: %d\n",
+                   avctx->frame_size);
+            return -1;
+        }
+        s->blocksize = avctx->frame_size;
+    } else {
+        s->blocksize = select_blocksize(s->samplerate, s->options.block_time_ms);
+        avctx->frame_size = s->blocksize;
+    }
+    av_log(avctx, AV_LOG_DEBUG, " block size: %d\n", s->blocksize);
+
+    /* set LPC precision */
+    if(avctx->lpc_coeff_precision > 0) {
+        if(avctx->lpc_coeff_precision > MAX_LPC_PRECISION) {
+            av_log(avctx, AV_LOG_ERROR, "invalid lpc coeff precision: %d\n",
+                   avctx->lpc_coeff_precision);
+            return -1;
+        }
+        s->options.lpc_coeff_precision = avctx->lpc_coeff_precision;
+    } else {
+        /* select LPC precision based on block size */
+        if(     s->blocksize <=   192) s->options.lpc_coeff_precision =  7;
+        else if(s->blocksize <=   384) s->options.lpc_coeff_precision =  8;
+        else if(s->blocksize <=   576) s->options.lpc_coeff_precision =  9;
+        else if(s->blocksize <=  1152) s->options.lpc_coeff_precision = 10;
+        else if(s->blocksize <=  2304) s->options.lpc_coeff_precision = 11;
+        else if(s->blocksize <=  4608) s->options.lpc_coeff_precision = 12;
+        else if(s->blocksize <=  8192) s->options.lpc_coeff_precision = 13;
+        else if(s->blocksize <= 16384) s->options.lpc_coeff_precision = 14;
+        else                           s->options.lpc_coeff_precision = 15;
+    }
+    av_log(avctx, AV_LOG_DEBUG, " lpc precision: %d\n",
+           s->options.lpc_coeff_precision);
 
     /* set maximum encoded frame size in verbatim mode */
     if(s->channels == 2) {
@@ -259,14 +477,13 @@ static void copy_samples(FlacEncodeContext *s, int16_t *samples)
 static int find_optimal_param(uint32_t sum, int n)
 {
     int k, k_opt;
-    uint32_t nbits, nbits_opt;
+    uint32_t nbits[MAX_RICE_PARAM+1];
 
     k_opt = 0;
-    nbits_opt = rice_encode_count(sum, n, 0);
-    for(k=1; k<=14; k++) {
-        nbits = rice_encode_count(sum, n, k);
-        if(nbits < nbits_opt) {
-            nbits_opt = nbits;
+    nbits[0] = UINT32_MAX;
+    for(k=0; k<=MAX_RICE_PARAM; k++) {
+        nbits[k] = rice_encode_count(sum, n, k);
+        if(nbits[k] < nbits[k_opt]) {
             k_opt = k;
         }
     }
@@ -297,8 +514,8 @@ static uint32_t calc_optimal_rice_params(RiceContext *rc, int porder,
     return all_bits;
 }
 
-static void calc_sums(int pmax, uint32_t *data, int n, int pred_order,
-                      uint32_t sums[][256])
+static void calc_sums(int pmin, int pmax, uint32_t *data, int n, int pred_order,
+                      uint32_t sums[][MAX_PARTITIONS])
 {
     int i, j;
     int parts;
@@ -316,7 +533,7 @@ static void calc_sums(int pmax, uint32_t *data, int n, int pred_order,
         res_end+= n >> pmax;
     }
     /* sums for lower levels */
-    for(i=pmax-1; i>=0; i--) {
+    for(i=pmax-1; i>=pmin; i--) {
         parts = (1 << i);
         for(j=0; j<parts; j++) {
             sums[i][j] = sums[i+1][2*j] + sums[i+1][2*j+1];
@@ -324,59 +541,262 @@ static void calc_sums(int pmax, uint32_t *data, int n, int pred_order,
     }
 }
 
-static uint32_t calc_rice_params(RiceContext *rc, int pmax, int32_t *data,
-                                 int n, int pred_order)
+static uint32_t calc_rice_params(RiceContext *rc, int pmin, int pmax,
+                                 int32_t *data, int n, int pred_order)
 {
     int i;
-    uint32_t bits, opt_bits;
+    uint32_t bits[MAX_PARTITION_ORDER+1];
     int opt_porder;
-    RiceContext opt_rc;
+    RiceContext tmp_rc;
     uint32_t *udata;
-    uint32_t sums[9][256];
+    uint32_t sums[MAX_PARTITION_ORDER+1][MAX_PARTITIONS];
 
-    assert(pmax >= 0 && pmax <= 8);
+    assert(pmin >= 0 && pmin <= MAX_PARTITION_ORDER);
+    assert(pmax >= 0 && pmax <= MAX_PARTITION_ORDER);
+    assert(pmin <= pmax);
 
     udata = av_malloc(n * sizeof(uint32_t));
     for(i=0; i<n; i++) {
         udata[i] = (2*data[i]) ^ (data[i]>>31);
     }
 
-    calc_sums(pmax, udata, n, pred_order, sums);
+    calc_sums(pmin, pmax, udata, n, pred_order, sums);
 
-    opt_porder = 0;
-    opt_bits = UINT32_MAX;
-    for(i=0; i<=pmax; i++) {
-        bits = calc_optimal_rice_params(rc, i, sums[i], n, pred_order);
-        if(bits < opt_bits) {
-            opt_bits = bits;
+    opt_porder = pmin;
+    bits[pmin] = UINT32_MAX;
+    for(i=pmin; i<=pmax; i++) {
+        bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums[i], n, pred_order);
+        if(bits[i] <= bits[opt_porder]) {
             opt_porder = i;
-            memcpy(&opt_rc, rc, sizeof(RiceContext));
+            memcpy(rc, &tmp_rc, sizeof(RiceContext));
         }
     }
-    if(opt_porder != pmax) {
-        memcpy(rc, &opt_rc, sizeof(RiceContext));
-    }
 
     av_freep(&udata);
-    return opt_bits;
+    return bits[opt_porder];
 }
 
-static uint32_t calc_rice_params_fixed(RiceContext *rc, int pmax, int32_t *data,
-                                       int n, int pred_order, int bps)
+static uint32_t calc_rice_params_fixed(RiceContext *rc, int pmin, int pmax,
+                                       int32_t *data, int n, int pred_order,
+                                       int bps)
 {
     uint32_t bits;
     bits = pred_order*bps + 6;
-    bits += calc_rice_params(rc, pmax, data, n, pred_order);
+    bits += calc_rice_params(rc, pmin, pmax, data, n, pred_order);
+    return bits;
+}
+
+static uint32_t calc_rice_params_lpc(RiceContext *rc, int pmin, int pmax,
+                                     int32_t *data, int n, int pred_order,
+                                     int bps, int precision)
+{
+    uint32_t bits;
+    bits = pred_order*bps + 4 + 5 + pred_order*precision + 6;
+    bits += calc_rice_params(rc, pmin, pmax, data, n, pred_order);
     return bits;
 }
 
+/**
+ * Apply Welch window function to audio block
+ */
+static void apply_welch_window(const int32_t *data, int len, double *w_data)
+{
+    int i, n2;
+    double w;
+    double c;
+
+    n2 = (len >> 1);
+    c = 2.0 / (len - 1.0);
+    for(i=0; i<n2; i++) {
+        w = c - i - 1.0;
+        w = 1.0 - (w * w);
+        w_data[i] = data[i] * w;
+        w_data[len-1-i] = data[len-1-i] * w;
+    }
+}
+
+/**
+ * Calculates autocorrelation data from audio samples
+ * A Welch window function is applied before calculation.
+ */
+static void compute_autocorr(const int32_t *data, int len, int lag,
+                             double *autoc)
+{
+    int i;
+    double *data1;
+    int lag_ptr, ptr;
+
+    data1 = av_malloc(len * sizeof(double));
+    apply_welch_window(data, len, data1);
+
+    for(i=0; i<lag; i++) autoc[i] = 1.0;
+
+    ptr = 0;
+    while(ptr <= lag) {
+        lag_ptr = 0;
+        while(lag_ptr <= ptr) {
+            autoc[ptr-lag_ptr] += data1[ptr] * data1[lag_ptr];
+            lag_ptr++;
+        }
+        ptr++;
+    }
+    while(ptr < len) {
+        lag_ptr = ptr - lag;
+        while(lag_ptr <= ptr) {
+            autoc[ptr-lag_ptr] += data1[ptr] * data1[lag_ptr];
+            lag_ptr++;
+        }
+        ptr++;
+    }
+
+    av_freep(&data1);
+}
+
+/**
+ * Levinson-Durbin recursion.
+ * Produces LPC coefficients from autocorrelation data.
+ */
+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
+ */
+static void quantize_lpc_coefs(double *lpc_in, int order, int precision,
+                               int32_t *lpc_out, int *shift)
+{
+    int i;
+    double d, cmax;
+    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++) {
+        d = lpc_in[i];
+        if(d < 0) d = -d;
+        if(d > cmax)
+            cmax = d;
+    }
+
+    /* if maximum value quantizes to zero, return all zeros */
+    if(cmax * (1 << MAX_LPC_SHIFT) < 1.0) {
+        *shift = 0;
+        for(i=0; i<order; i++) {
+            lpc_out[i] = 0;
+        }
+        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 */
+    for(i=0; i<order; i++) {
+        lpc_out[i] = (int32_t)(lpc_in[i] * (1 << sh));
+    }
+    *shift = sh;
+}
+
+static int estimate_best_order(double *ref, int max_order)
+{
+    int i, est;
+
+    est = 1;
+    for(i=max_order-1; i>=0; i--) {
+        if(ref[i] > 0.10) {
+            est = i+1;
+            break;
+        }
+    }
+    return est;
+}
+
+/**
+ * Calculate LPC coefficients for multiple orders
+ */
+static int lpc_calc_coefs(const int32_t *samples, int blocksize, int max_order,
+                          int precision, int32_t coefs[][MAX_LPC_ORDER],
+                          int *shift)
+{
+    double autoc[MAX_LPC_ORDER+1];
+    double ref[MAX_LPC_ORDER];
+    double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER];
+    int i;
+    int opt_order;
+
+    assert(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER);
+
+    compute_autocorr(samples, blocksize, max_order+1, autoc);
+
+    compute_lpc_coefs(autoc, max_order, lpc, ref);
+
+    opt_order = estimate_best_order(ref, max_order);
+
+    i = opt_order-1;
+    quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i]);
+
+    return opt_order;
+}
+
+
 static void encode_residual_verbatim(int32_t *res, int32_t *smp, int n)
 {
     assert(n > 0);
     memcpy(res, smp, n * sizeof(int32_t));
 }
 
-static void encode_residual_fixed(int32_t *res, int32_t *smp, int n, int order)
+static void encode_residual_fixed(int32_t *res, const int32_t *smp, int n,
+                                  int order)
 {
     int i;
 
@@ -402,6 +822,24 @@ static void encode_residual_fixed(int32_t *res, int32_t *smp, int n, int order)
     }
 }
 
+static void encode_residual_lpc(int32_t *res, const int32_t *smp, int n,
+                                int order, const int32_t *coefs, int shift)
+{
+    int i, j;
+    int32_t pred;
+
+    for(i=0; i<order; i++) {
+        res[i] = smp[i];
+    }
+    for(i=order; i<n; i++) {
+        pred = 0;
+        for(j=0; j<order; j++) {
+            pred += coefs[j] * smp[i-j-1];
+        }
+        res[i] = smp[i] - (pred >> shift);
+    }
+}
+
 static int get_max_p_order(int max_porder, int n, int order)
 {
     int porder, max_parts;
@@ -419,10 +857,13 @@ static int get_max_p_order(int max_porder, int n, int order)
 
 static int encode_residual(FlacEncodeContext *ctx, int ch)
 {
-    int i, opt_order, porder, max_porder, n;
+    int i, n;
+    int min_order, max_order, opt_order, precision;
+    int porder, min_porder, max_porder;
     FlacFrame *frame;
     FlacSubframe *sub;
-    uint32_t bits[5];
+    int32_t coefs[MAX_LPC_ORDER][MAX_LPC_ORDER];
+    int shift[MAX_LPC_ORDER];
     int32_t *res, *smp;
 
     frame = &ctx->frame;
@@ -448,28 +889,51 @@ static int encode_residual(FlacEncodeContext *ctx, int ch)
         return sub->obits * n;
     }
 
-    max_porder = 3;
+    min_order = ctx->options.min_prediction_order;
+    max_order = ctx->options.max_prediction_order;
+    min_porder = ctx->options.min_partition_order;
+    max_porder = ctx->options.max_partition_order;
+    precision = ctx->options.lpc_coeff_precision;
 
     /* FIXED */
-    opt_order = 0;
-    bits[0] = UINT32_MAX;
-    for(i=0; i<=4; i++) {
-        encode_residual_fixed(res, smp, n, i);
-        porder = get_max_p_order(max_porder, n, i);
-        bits[i] = calc_rice_params_fixed(&sub->rc, porder, res, n, i, sub->obits);
-        if(bits[i] < bits[opt_order]) {
-            opt_order = i;
+    if(!ctx->options.use_lpc || max_order == 0 || (n <= max_order)) {
+        uint32_t bits[MAX_FIXED_ORDER+1];
+        if(max_order > MAX_FIXED_ORDER) max_order = MAX_FIXED_ORDER;
+        opt_order = 0;
+        bits[0] = UINT32_MAX;
+        for(i=min_order; i<=max_order; i++) {
+            encode_residual_fixed(res, smp, n, i);
+            porder = get_max_p_order(max_porder, n, i);
+            bits[i] = calc_rice_params_fixed(&sub->rc, min_porder, porder, res,
+                                             n, i, sub->obits);
+            if(bits[i] < bits[opt_order]) {
+                opt_order = i;
+            }
         }
+        sub->order = opt_order;
+        sub->type = FLAC_SUBFRAME_FIXED;
+        sub->type_code = sub->type | sub->order;
+        if(sub->order != max_order) {
+            encode_residual_fixed(res, smp, n, sub->order);
+            porder = get_max_p_order(max_porder, n, sub->order);
+            return calc_rice_params_fixed(&sub->rc, min_porder, porder, res, n,
+                                          sub->order, sub->obits);
+        }
+        return bits[sub->order];
     }
-    sub->order = opt_order;
-    sub->type = FLAC_SUBFRAME_FIXED;
-    sub->type_code = sub->type | sub->order;
-    if(sub->order != 4) {
-        encode_residual_fixed(res, smp, n, sub->order);
-        porder = get_max_p_order(max_porder, n, sub->order);
-        calc_rice_params_fixed(&sub->rc, porder, res, n, sub->order, sub->obits);
+
+    /* LPC */
+    sub->order = lpc_calc_coefs(smp, n, max_order, precision, coefs, shift);
+    sub->type = FLAC_SUBFRAME_LPC;
+    sub->type_code = sub->type | (sub->order-1);
+    sub->shift = shift[sub->order-1];
+    for(i=0; i<sub->order; i++) {
+        sub->coefs[i] = coefs[sub->order-1][i];
     }
-    return bits[sub->order];
+    porder = get_max_p_order(max_porder, n, sub->order);
+    encode_residual_lpc(res, smp, n, sub->order, sub->coefs, sub->shift);
+    return calc_rice_params_lpc(&sub->rc, 0, porder, res, n, sub->order,
+                                sub->obits, precision);
 }
 
 static int encode_residual_v(FlacEncodeContext *ctx, int ch)
@@ -509,7 +973,7 @@ static int estimate_stereo_mode(int32_t *left_ch, int32_t *right_ch, int n)
     uint64_t score[4];
     int k;
 
-    /* calculate sum of squares for each channel */
+    /* calculate sum of 2nd order residual for each channel */
     sum[0] = sum[1] = sum[2] = sum[3] = 0;
     for(i=2; i<n; i++) {
         lt = left_ch[i] - 2*left_ch[i-1] + left_ch[i-2];
@@ -519,6 +983,7 @@ static int estimate_stereo_mode(int32_t *left_ch, int32_t *right_ch, int n)
         sum[0] += ABS(lt);
         sum[1] += ABS(rt);
     }
+    /* estimate bit counts */
     for(i=0; i<4; i++) {
         k = find_optimal_param(2*sum[i], n);
         sum[i] = rice_encode_count(2*sum[i], n, k);
@@ -731,6 +1196,32 @@ static void output_subframe_fixed(FlacEncodeContext *ctx, int ch)
     output_residual(ctx, ch);
 }
 
+static void output_subframe_lpc(FlacEncodeContext *ctx, int ch)
+{
+    int i, cbits;
+    FlacFrame *frame;
+    FlacSubframe *sub;
+
+    frame = &ctx->frame;
+    sub = &frame->subframes[ch];
+
+    /* warm-up samples */
+    for(i=0; i<sub->order; i++) {
+        put_sbits(&ctx->pb, sub->obits, sub->residual[i]);
+    }
+
+    /* LPC coefficients */
+    cbits = ctx->options.lpc_coeff_precision;
+    put_bits(&ctx->pb, 4, cbits-1);
+    put_sbits(&ctx->pb, 5, sub->shift);
+    for(i=0; i<sub->order; i++) {
+        put_sbits(&ctx->pb, cbits, sub->coefs[i]);
+    }
+
+    /* residual */
+    output_residual(ctx, ch);
+}
+
 static void output_subframes(FlacEncodeContext *s)
 {
     FlacFrame *frame;
@@ -754,6 +1245,8 @@ static void output_subframes(FlacEncodeContext *s)
             output_subframe_verbatim(s, ch);
         } else if(sub->type == FLAC_SUBFRAME_FIXED) {
             output_subframe_fixed(s, ch);
+        } else if(sub->type == FLAC_SUBFRAME_LPC) {
+            output_subframe_lpc(s, ch);
         }
     }
 }
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 3828757..d106ae6 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -744,6 +744,14 @@ static AVOption options[]={
 {"mv0_threshold", NULL, OFFSET(mv0_threshold), FF_OPT_TYPE_INT, 256, 0, INT_MAX, V|E},
 {"ivlc", "intra vlc table", 0, FF_OPT_TYPE_CONST, CODEC_FLAG2_INTRA_VLC, INT_MIN, INT_MAX, V|E, "flags2"},
 {"b_sensitivity", NULL, OFFSET(b_sensitivity), FF_OPT_TYPE_INT, 40, 1, INT_MAX, V|E},
+{"compression_level", NULL, OFFSET(compression_level), FF_OPT_TYPE_INT, FF_COMPRESSION_DEFAULT, INT_MIN, INT_MAX, V|A|E},
+{"use_lpc", NULL, OFFSET(use_lpc), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
+{"lpc_coeff_precision", NULL, OFFSET(lpc_coeff_precision), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, A|E},
+{"min_prediction_order", NULL, OFFSET(min_prediction_order), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
+{"max_prediction_order", NULL, OFFSET(max_prediction_order), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
+{"prediction_order_method", NULL, OFFSET(prediction_order_method), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
+{"min_partition_order", NULL, OFFSET(min_partition_order), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
+{"max_partition_order", NULL, OFFSET(max_partition_order), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
 {NULL},
 };
 
@@ -800,6 +808,13 @@ void avcodec_get_context_defaults(AVCodecContext *s){
     s->sample_fmt= SAMPLE_FMT_S16; // FIXME: set to NONE
     s->mv0_threshold= 256;
     s->b_sensitivity= 40;
+    s->compression_level = FF_COMPRESSION_DEFAULT;
+    s->use_lpc = -1;
+    s->min_prediction_order = -1;
+    s->max_prediction_order = -1;
+    s->prediction_order_method = -1;
+    s->min_partition_order = -1;
+    s->max_partition_order = -1;
 
     s->intra_quant_bias= FF_DEFAULT_QUANT_BIAS;
     s->inter_quant_bias= FF_DEFAULT_QUANT_BIAS;
diff --git a/tests/ffmpeg.regression.ref b/tests/ffmpeg.regression.ref
index b5dda09..58a141f 100644
--- a/tests/ffmpeg.regression.ref
+++ b/tests/ffmpeg.regression.ref
@@ -176,7 +176,7 @@ stddev:1050.18 PSNR:35.89 bytes:1054720
 264236 ./data/a-adpcm_yam.wav
 e92cec8c07913ffb91ad2b11f79cdc00 *./data/out.wav
 stddev:18312.68 PSNR:11.06 bytes:1056768
-9ab5f311b70bc1fa8591b891db50b386 *./data/a-flac.flac
-353384 ./data/a-flac.flac
+c3382f03ce2efb5d475240d288a33898 *./data/a-flac.flac
+353368 ./data/a-flac.flac
 c4228df189aad9567a037727d0e763e4 *./data/out.wav
 stddev: 33.31 PSNR:65.87 bytes:1040384
diff --git a/tests/regression.sh b/tests/regression.sh
index 7bd285a..9aa1563 100755
--- a/tests/regression.sh
+++ b/tests/regression.sh
@@ -599,7 +599,7 @@ fi
 if [ -n "$do_flac" ] ; then
 # encoding
 file=${outfile}flac.flac
-do_ffmpeg $file -y -ab 128 -ac 2 -ar 44100 -f s16le -i $pcm_src -acodec flac $file
+do_ffmpeg $file -y -ab 128 -ac 2 -ar 44100 -f s16le -i $pcm_src -acodec flac -compression_level 2 $file
 
 # decoding
 do_ffmpeg $pcm_dst -y -i $file -f wav $pcm_dst
diff --git a/tests/rotozoom.regression.ref b/tests/rotozoom.regression.ref
index 4a77bb9..606b3ea 100644
--- a/tests/rotozoom.regression.ref
+++ b/tests/rotozoom.regression.ref
@@ -176,7 +176,7 @@ stddev:1050.18 PSNR:35.89 bytes:1054720
 264236 ./data/a-adpcm_yam.wav
 e92cec8c07913ffb91ad2b11f79cdc00 *./data/out.wav
 stddev:18312.68 PSNR:11.06 bytes:1056768
-9ab5f311b70bc1fa8591b891db50b386 *./data/a-flac.flac
-353384 ./data/a-flac.flac
+c3382f03ce2efb5d475240d288a33898 *./data/a-flac.flac
+353368 ./data/a-flac.flac
 c4228df189aad9567a037727d0e763e4 *./data/out.wav
 stddev: 33.31 PSNR:65.87 bytes:1040384

-- 
Libav/FFmpeg packaging



More information about the pkg-multimedia-commits mailing list