shithub: opus

Download patch

ref: ef2e6505927dfda67b9bd4b7b438bf93df5128ab
parent: 99a19474a0eb683893664d60a33adc4dc3ec1e4f
author: Timothy B. Terriberry <[email protected]>
date: Mon Nov 8 20:43:18 EST 2010

Add coarse energy entropy model tuning.

This tunes the entropy model for coarse energy introduced in commit
 c1c40a76.
It uses a constant set of parameters, tuned from about an hour and a
 half of randomly selected test data encoded for each frame size,
 prediction type (inter/intra), and band number.
These will be slightly sub-optimal for different frame sizes, but
 should be better than what we were using.

For inter, this saves an average of 2.8, 5.2, 7.1, and 6.7 bits/frame
 for frame sizes of 120, 240, 480, and 960, respectively.
For intra, this saves an average of 1.5, 3.0, 4.5, and 5.3 bits/frame
 (for the same frame sizes, respectively).

--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -861,8 +861,8 @@
 
    ALLOC(error, C*st->mode->nbEBands, celt_word16);
    quant_coarse_energy(st->mode, st->start, st->end, effEnd, bandLogE,
-         oldBandE, nbCompressedBytes*8, st->mode->prob,
-         error, enc, C, LM, nbAvailableBytes, st->force_intra,
+         oldBandE, nbCompressedBytes*8, error, enc,
+         C, LM, nbAvailableBytes, st->force_intra,
          &st->delayedIntra, st->complexity >= 4);
 
    if (LM > 0)
@@ -1663,7 +1663,7 @@
    intra_ener = ec_dec_bit_prob(dec, 8192);
    /* Get band energies */
    unquant_coarse_energy(st->mode, st->start, st->end, bandE, oldBandE,
-         intra_ener, st->mode->prob, dec, C, LM);
+         intra_ener, dec, C, LM);
 
    if (LM > 0)
       isTransient = ec_dec_bit_prob(dec, 8192);
--- a/libcelt/dump_modes.c
+++ b/libcelt/dump_modes.c
@@ -109,15 +109,6 @@
          fprintf(file, "\n");
       }
 
-      fprintf(file, "#ifndef DEF_PROB%d\n", mode->nbEBands);
-      fprintf(file, "#define DEF_PROB%d\n", mode->nbEBands);
-      fprintf (file, "static const celt_int16 prob%d[%d] = {\n", mode->nbEBands, 4*mode->nbEBands);
-      for (j=0;j<4*mode->nbEBands;j++)
-         fprintf (file, "%d, ", mode->prob[j]);
-      fprintf (file, "};\n");
-      fprintf(file, "#endif\n");
-      fprintf(file, "\n");
-
       fprintf(file, "#ifndef DEF_LOGN%d\n", framerate);
       fprintf(file, "#define DEF_LOGN%d\n", framerate);
       fprintf (file, "static const celt_int16 logN%d[%d] = {\n", framerate, mode->nbEBands);
@@ -234,7 +225,6 @@
       fprintf(file, "%d,\t/* maxLM */\n", mode->maxLM);
       fprintf(file, "%d,\t/* nbShortMdcts */\n", mode->nbShortMdcts);
       fprintf(file, "%d,\t/* shortMdctSize */\n", mode->shortMdctSize);
-      fprintf(file, "prob%d,\t/* prob */\n", mode->nbEBands);
       fprintf(file, "logN%d,\t/* logN */\n", framerate);
       fprintf(file, "{%d, cache_index%d, cache_bits%d},\t/* cache */\n",
             mode->cache.size, mode->Fs/mdctSize, mode->Fs/mdctSize);
--- a/libcelt/laplace.c
+++ b/libcelt/laplace.c
@@ -44,13 +44,6 @@
     direction). */
 #define LAPLACE_NMIN (16)
 
-int ec_laplace_get_start_freq(int decay)
-{
-   celt_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
-   int fs = (ft*(16384-decay))/(16384+decay);
-   return fs+LAPLACE_MINP;
-}
-
 static int ec_laplace_get_freq1(int fs0, int decay)
 {
    celt_int32 ft;
@@ -58,7 +51,7 @@
    return ft*(16384-decay)>>15;
 }
 
-void ec_laplace_encode_start(ec_enc *enc, int *value, int decay, int fs)
+void ec_laplace_encode(ec_enc *enc, int *value, int fs, int decay)
 {
    unsigned fl;
    int val = *value;
@@ -102,15 +95,8 @@
 }
 
 
-void ec_laplace_encode(ec_enc *enc, int *value, int decay)
+int ec_laplace_decode(ec_dec *dec, int fs, int decay)
 {
-   int fs = ec_laplace_get_start_freq(decay);
-   ec_laplace_encode_start(enc, value, decay, fs);
-}
-
-
-int ec_laplace_decode_start(ec_dec *dec, int decay, int fs)
-{
    int val=0;
    unsigned fl;
    int fm;
@@ -149,10 +135,4 @@
    celt_assert(fm<IMIN(fl+fs,32768));
    ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
    return val;
-}
-
-int ec_laplace_decode(ec_dec *dec, int decay)
-{
-   int fs = ec_laplace_get_start_freq(decay);
-   return ec_laplace_decode_start(dec, decay, fs);
 }
--- a/libcelt/laplace.h
+++ b/libcelt/laplace.h
@@ -33,24 +33,20 @@
 #include "entenc.h"
 #include "entdec.h"
 
-int ec_laplace_get_start_freq(int decay);
-
 /** Encode a value that is assumed to be the realisation of a
     Laplace-distributed random process
  @param enc Entropy encoder state
  @param value Value to encode
+ @param fs Probability of 0, multiplied by 32768
  @param decay Probability of the value +/- 1, multiplied by 16384
 */
-void ec_laplace_encode(ec_enc *enc, int *value, int decay);
+void ec_laplace_encode(ec_enc *enc, int *value, int fs, int decay);
 
-void ec_laplace_encode_start(ec_enc *enc, int *value, int decay, int fs);
-
 /** Decode a value that is assumed to be the realisation of a
     Laplace-distributed random process
  @param dec Entropy decoder state
+ @param fs Probability of 0, multiplied by 32768
  @param decay Probability of the value +/- 1, multiplied by 16384
  @return Value decoded
  */
-int ec_laplace_decode(ec_dec *dec, int decay);
-
-int ec_laplace_decode_start(ec_dec *dec, int decay, int fs);
+int ec_laplace_decode(ec_dec *dec, int fs, int decay);
--- a/libcelt/modes.c
+++ b/libcelt/modes.c
@@ -454,10 +454,6 @@
    )
       goto failure;
 
-   mode->prob = quant_prob_alloc(mode);
-   if (mode->prob==NULL)
-     goto failure;
-
    if (error)
       *error = CELT_OK;
 
@@ -486,7 +482,6 @@
    celt_free((celt_int16*)mode->cache.index);
    celt_free((unsigned char*)mode->cache.bits);
    clt_mdct_clear(&mode->mdct);
-   quant_prob_free(mode->prob);
 
    celt_free((CELTMode *)mode);
 #endif
--- a/libcelt/modes.h
+++ b/libcelt/modes.h
@@ -97,7 +97,6 @@
    int         nbShortMdcts;
    int         shortMdctSize;
 
-   const celt_int16 *prob;
    const celt_int16 *logN;
 
    PulseCache cache;
--- a/libcelt/quant_bands.c
+++ b/libcelt/quant_bands.c
@@ -70,6 +70,74 @@
 static const celt_word16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.};
 #endif
 
+/*Parameters of the Laplace-like probability models used for the coarse energy.
+  There is one pair of parameters for each frame size, prediction type
+   (inter/intra), and band number.
+  The first number of each pair is the probability of 0, and the second is the
+   decay rate, both in Q8 precision.*/
+static const unsigned char e_prob_model[4][2][42] = {
+   /*120 sample frames.*/
+   {
+      /*Inter*/
+      {
+          72, 127,  65, 129,  66, 128,  65, 128,  64, 128,  62, 128,  64, 128,
+          64, 128,  92,  78,  92,  79,  92,  78,  90,  79, 116,  41, 115,  40,
+         114,  40, 132,  26, 132,  26, 145,  17, 161,  12, 176,  10, 177,  11
+      },
+      /*Intra*/
+      {
+          24, 179,  48, 138,  54, 135,  54, 132,  53, 134,  56, 133,  55, 132,
+          55, 132,  61, 114,  70,  96,  74,  88,  75,  88,  87,  74,  89,  66,
+          91,  67, 100,  59, 108,  50, 120,  40, 122,  37,  97,  43,  78,  50
+      }
+   },
+   /*240 sample frames.*/
+   {
+      /*Inter*/
+      {
+          83,  78,  84,  81,  88,  75,  86,  74,  87,  71,  90,  73,  93,  74,
+          93,  74, 109,  40, 114,  36, 117,  34, 117,  34, 143,  17, 145,  18,
+         146,  19, 162,  12, 165,  10, 178,   7, 189,   6, 190,   8, 177,   9
+      },
+      /*Intra*/
+      {
+          23, 178,  54, 115,  63, 102,  66,  98,  69,  99,  74,  89,  71,  91,
+          73,  91,  78,  89,  86,  80,  92,  66,  93,  64, 102,  59, 103,  60,
+         104,  60, 117,  52, 123,  44, 138,  35, 133,  31,  97,  38,  77,  45
+      }
+   },
+   /*480 sample frames.*/
+   {
+      /*Inter*/
+      {
+          61,  90,  93,  60, 105,  42, 107,  41, 110,  45, 116,  38, 113,  38,
+         112,  38, 124,  26, 132,  27, 136,  19, 140,  20, 155,  14, 159,  16,
+         158,  18, 170,  13, 177,  10, 187,   8, 192,   6, 175,   9, 159,  10
+      },
+      /*Intra*/
+      {
+          21, 178,  59, 110,  71,  86,  75,  85,  84,  83,  91,  66,  88,  73,
+          87,  72,  92,  75,  98,  72, 105,  58, 107,  54, 115,  52, 114,  55,
+         112,  56, 129,  51, 132,  40, 150,  33, 140,  29,  98,  35,  77,  42
+      }
+   },
+   /*960 sample frames.*/
+   {
+      /*Inter*/
+      {
+          42, 121,  96,  66, 108,  43, 111,  40, 117,  44, 123,  32, 120,  36,
+         119,  33, 127,  33, 134,  34, 139,  21, 147,  23, 152,  20, 158,  25,
+         154,  26, 166,  21, 173,  16, 184,  13, 184,  10, 150,  13, 139,  15
+      },
+      /*Intra*/
+      {
+          22, 178,  63, 114,  74,  82,  84,  83,  92,  82, 103,  62,  96,  72,
+          96,  67, 101,  73, 107,  72, 113,  55, 118,  52, 125,  52, 118,  52,
+         117,  55, 135,  49, 137,  39, 157,  32, 145,  29,  97,  33,  77,  40
+      }
+   }
+};
+
 static int intra_decision(const celt_word16 *eBands, celt_word16 *oldEBands, int start, int end, int len, int C)
 {
    int c, i;
@@ -84,38 +152,10 @@
    return SHR32(dist,2*DB_SHIFT-4) > 2*C*(end-start);
 }
 
-#ifndef STATIC_MODES
-
-celt_int16 *quant_prob_alloc(const CELTMode *m)
-{
-   int i;
-   celt_int16 *prob;
-   prob = celt_alloc(4*m->nbEBands*sizeof(celt_int16));
-   if (prob==NULL)
-     return NULL;
-   for (i=0;i<m->nbEBands;i++)
-   {
-      prob[2*i] = 7000-i*200;
-      prob[2*i+1] = ec_laplace_get_start_freq(prob[2*i]);
-   }
-   for (i=0;i<m->nbEBands;i++)
-   {
-      prob[2*m->nbEBands+2*i] = 9000-i*220;
-      prob[2*m->nbEBands+2*i+1] = ec_laplace_get_start_freq(prob[2*m->nbEBands+2*i]);
-   }
-   return prob;
-}
-
-void quant_prob_free(const celt_int16 *freq)
-{
-   celt_free((celt_int16*)freq);
-}
-#endif
-
 static void quant_coarse_energy_impl(const CELTMode *m, int start, int end,
       const celt_word16 *eBands, celt_word16 *oldEBands, int budget,
-      const celt_int16 *prob, celt_word16 *error, ec_enc *enc, int _C, int LM,
-      int intra, celt_word16 max_decay)
+      const unsigned char *prob_model, celt_word16 *error, ec_enc *enc,
+      int _C, int LM, int intra, celt_word16 max_decay)
 {
    const int C = CHANNELS(_C);
    int i, c;
@@ -127,7 +167,6 @@
    if (intra)
    {
       coef = 0;
-      prob += 2*m->nbEBands;
       beta = QCONST16(.15f,15);
    } else {
       beta = beta_coef[LM];
@@ -141,6 +180,7 @@
       do {
          int bits_left;
          int qi;
+         int pi;
          celt_word16 q;
          celt_word16 x;
          celt_word32 f;
@@ -174,7 +214,9 @@
             if (bits_left<8)
                qi = 0;
          }
-         ec_laplace_encode_start(enc, &qi, prob[2*i], prob[2*i+1]);
+         pi = 2*IMIN(i,20);
+         ec_laplace_encode(enc, &qi,
+               prob_model[pi]<<7, prob_model[pi+1]<<6);
          error[i+c*m->nbEBands] = PSHR32(f,15) - SHL16(qi,DB_SHIFT);
          q = SHL16(qi,DB_SHIFT);
          
@@ -186,8 +228,8 @@
 
 void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
       const celt_word16 *eBands, celt_word16 *oldEBands, int budget,
-      const celt_int16 *prob, celt_word16 *error, ec_enc *enc, int _C, int LM,
-      int nbAvailableBytes, int force_intra, int *delayedIntra, int two_pass)
+      celt_word16 *error, ec_enc *enc, int _C, int LM, int nbAvailableBytes,
+      int force_intra, int *delayedIntra, int two_pass)
 {
    const int C = CHANNELS(_C);
    int intra;
@@ -223,7 +265,7 @@
    if (two_pass || intra)
    {
       quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
-            prob, error_intra, enc, C, LM, 1, max_decay);
+            e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay);
    }
 
    if (!intra)
@@ -246,7 +288,7 @@
       *(enc->buf) = buf_start_state;
 
       quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
-            prob, error, enc, C, LM, 0, max_decay);
+            e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay);
 
       if (two_pass && ec_enc_tell(enc, 3) > tell_intra)
       {
@@ -332,8 +374,9 @@
    }
 }
 
-void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, const celt_int16 *prob, ec_dec *dec, int _C, int LM)
+void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, ec_dec *dec, int _C, int LM)
 {
+   const unsigned char *prob_model = e_prob_model[LM][intra];
    int i, c;
    celt_word32 prev[2] = {0, 0};
    celt_word16 coef;
@@ -345,7 +388,6 @@
    {
       coef = 0;
       beta = QCONST16(.15f,15);
-      prob += 2*m->nbEBands;
    } else {
       beta = beta_coef[LM];
       coef = pred_coef[LM];
@@ -357,8 +399,11 @@
       c=0;
       do {
          int qi;
+         int pi;
          celt_word16 q;
-         qi = ec_laplace_decode_start(dec, prob[2*i], prob[2*i+1]);
+         pi = 2*IMIN(i,20);
+         qi = ec_laplace_decode(dec,
+               prob_model[pi]<<7, prob_model[pi+1]<<6);
          q = SHL16(qi,DB_SHIFT);
 
          oldEBands[i+c*m->nbEBands] = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]) + prev[c] + SHL32(EXTEND32(q),15), 15);
--- a/libcelt/quant_bands.h
+++ b/libcelt/quant_bands.h
@@ -45,12 +45,12 @@
 void log2Amp(const CELTMode *m, int start, int end,
       celt_ener *eBands, celt_word16 *oldEBands, int _C);
 
-celt_int16 *quant_prob_alloc(const CELTMode *m);
+unsigned char *quant_prob_alloc(const CELTMode *m);
 void quant_prob_free(const celt_int16 *freq);
 
 void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
       const celt_word16 *eBands, celt_word16 *oldEBands, int budget,
-      const celt_int16 *prob, celt_word16 *error, ec_enc *enc, int _C, int LM,
+      celt_word16 *error, ec_enc *enc, int _C, int LM,
       int nbAvailableBytes, int force_intra, int *delayedIntra, int two_pass);
 
 void quant_fine_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, ec_enc *enc, int _C);
@@ -57,7 +57,7 @@
 
 void quant_energy_finalise(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int _C);
 
-void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, const celt_int16 *prob, ec_dec *dec, int _C, int LM);
+void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, ec_dec *dec, int _C, int LM);
 
 void unquant_fine_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int *fine_quant, ec_dec *dec, int _C);
 
--- a/tests/laplace-test.c
+++ b/tests/laplace-test.c
@@ -17,6 +17,13 @@
 
 #define DATA_SIZE 40000
 
+int ec_laplace_get_start_freq(int decay)
+{
+   celt_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
+   int fs = (ft*(16384-decay))/(16384+decay);
+   return fs+LAPLACE_MINP;
+}
+
 int main(void)
 {
    int i;
@@ -41,8 +48,9 @@
       decay[i] = rand()%11000+5000;
    }
    for (i=0;i<10000;i++)
-      ec_laplace_encode(&enc, &val[i], decay[i]);      
-      
+      ec_laplace_encode(&enc, &val[i],
+            ec_laplace_get_start_freq(decay[i]), decay[i]);
+
    ec_enc_done(&enc);
 
    ec_byte_readinit(&buf,ec_byte_get_buffer(&buf),ec_byte_bytes(&buf));
@@ -50,7 +58,8 @@
 
    for (i=0;i<10000;i++)
    {
-      int d = ec_laplace_decode(&dec, decay[i]);
+      int d = ec_laplace_decode(&dec,
+            ec_laplace_get_start_freq(decay[i]), decay[i]);
       if (d != val[i])
       {
          fprintf (stderr, "Got %d instead of %d\n", d, val[i]);