ref: 3e3a2ff127a27bf8cc54c14b444053712cd5e590
parent: 8299edfc0c34aaf91ef07bf2410ad15423bcaf96
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Tue Jan 16 07:38:07 EST 2018
Improve TF analysis RDO to take into account how important each band is Also adds the error terms for band 0 that were previously omitted
--- a/celt/celt_encoder.c
+++ b/celt/celt_encoder.c
@@ -577,7 +577,7 @@
static int tf_analysis(const CELTMode *m, int len, int isTransient,
int *tf_res, int lambda, celt_norm *X, int N0, int LM,
- opus_val16 tf_estimate, int tf_chan)
+ opus_val16 tf_estimate, int tf_chan, int *importance)
{
int i;
VARDECL(int, metric);
@@ -660,7 +660,7 @@
biasing the decision */
if (narrow && (metric[i]==0 || metric[i]==-2*LM))
metric[i]-=1;
- /*printf("%d ", metric[i]);*/
+ /*printf("%d ", metric[i]/2 + (!isTransient)*LM);*/
}
/*printf("\n");*/
/* Search for the optimal tf resolution, including tf_select */
@@ -667,15 +667,15 @@
tf_select = 0;
for (sel=0;sel<2;sel++)
{
- cost0 = 0;
- cost1 = isTransient ? 0 : lambda;
+ cost0 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
+ cost1 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*sel+1]) + (isTransient ? 0 : lambda);
for (i=1;i<len;i++)
{
int curr0, curr1;
curr0 = IMIN(cost0, cost1 + lambda);
curr1 = IMIN(cost0 + lambda, cost1);
- cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
- cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
+ cost0 = curr0 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
+ cost1 = curr1 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
}
cost0 = IMIN(cost0, cost1);
selcost[sel]=cost0;
@@ -684,8 +684,8 @@
* If tests confirm it's useful for non-transients, we could allow it. */
if (selcost[1]<selcost[0] && isTransient)
tf_select=1;
- cost0 = 0;
- cost1 = isTransient ? 0 : lambda;
+ cost0 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
+ cost1 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]) + (isTransient ? 0 : lambda);
/* Viterbi forward pass */
for (i=1;i<len;i++)
{
@@ -713,8 +713,8 @@
curr1 = from1;
path1[i]= 1;
}
- cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
- cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
+ cost0 = curr0 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
+ cost1 = curr1 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
}
tf_res[len-1] = cost0 < cost1 ? 0 : 1;
/* Viterbi backward pass to check the decisions */
@@ -964,7 +964,8 @@
static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2,
int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN,
int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM,
- int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc, AnalysisInfo *analysis)
+ int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc,
+ AnalysisInfo *analysis, int *importance)
{
int i, c;
opus_int32 tot_boost=0;
@@ -1046,6 +1047,14 @@
}
for (i=start;i<end;i++)
follower[i] = MAX16(follower[i], surround_dynalloc[i]);
+ for (i=start;i<end;i++)
+ {
+#ifdef FIXED_POINT
+ importance[i] = PSHR32(13*celt_exp2(MIN16(follower[i], QCONST16(4.f, DB_SHIFT)), 16);
+#else
+ importance[i] = (int)floor(.5f+13*celt_exp2(MIN16(follower[i], QCONST16(4.f, DB_SHIFT))));
+#endif
+ }
/* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
if ((!vbr || constrained_vbr)&&!isTransient)
{
@@ -1365,6 +1374,7 @@
VARDECL(int, pulses);
VARDECL(int, cap);
VARDECL(int, offsets);
+ VARDECL(int, importance);
VARDECL(int, fine_priority);
VARDECL(int, tf_res);
VARDECL(unsigned char, collapse_masks);
@@ -1417,6 +1427,7 @@
opus_int32 equiv_rate;
int hybrid;
int weak_transient = 0;
+ int enable_tf_analysis;
VARDECL(opus_val16, surround_dynalloc);
ALLOC_STACK;
@@ -1808,13 +1819,22 @@
/* Band normalisation */
normalise_bands(mode, freq, X, bandE, effEnd, C, M);
+ enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe;
+
+ ALLOC(offsets, nbEBands, int);
+ ALLOC(importance, nbEBands, int);
+
+ maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
+ st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
+ eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis, importance);
+
ALLOC(tf_res, nbEBands, int);
/* Disable variable tf resolution for hybrid and at very low bitrate */
- if (effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe)
+ if (enable_tf_analysis)
{
int lambda;
- lambda = IMAX(5, 1280/effectiveBytes + 2);
- tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan);
+ lambda = IMAX(80, 20480/effectiveBytes + 2);
+ tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance);
for (i=effEnd;i<end;i++)
tf_res[i] = tf_res[effEnd-1];
} else if (hybrid && weak_transient)
@@ -1904,11 +1924,6 @@
ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
}
- ALLOC(offsets, nbEBands, int);
-
- maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
- st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
- eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis);
/* For LFE, everything interesting is in the first band */
if (st->lfe)
offsets[0] = IMIN(8, effectiveBytes/3);