summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Marc Valin <jmvalin@jmvalin.ca>2014-01-19 01:31:00 -0500
committerJean-Marc Valin <jmvalin@jmvalin.ca>2014-01-19 01:32:53 -0500
commit05548fa1c127bd4f5ae2d1143149e8428560e48b (patch)
tree8ae5086dc84d823f02037ba69acddd517ff75269
parentb331167821d3cfc8190697c2a1e485c9701f5eac (diff)
downloadopus-05548fa1c127bd4f5ae2d1143149e8428560e48b.tar.gz
Adds a median filter to make dynalloc_analysis() more conservative
This should prevent extreme dynalloc behaviour in cases where some bands are heavily attenuated.
-rw-r--r--celt/celt_encoder.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/celt/celt_encoder.c b/celt/celt_encoder.c
index 4cd8c4a0..7ab96ec2 100644
--- a/celt/celt_encoder.c
+++ b/celt/celt_encoder.c
@@ -860,6 +860,66 @@ static int stereo_analysis(const CELTMode *m, const celt_norm *X,
> MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
}
+#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0)
+static opus_val16 median_of_5(const opus_val16 *x)
+{
+ opus_val16 t0, t1, t2, t3, t4;
+ t2 = x[2];
+ if (x[0] > x[1])
+ {
+ t0 = x[1];
+ t1 = x[0];
+ } else {
+ t0 = x[0];
+ t1 = x[1];
+ }
+ if (x[3] > x[4])
+ {
+ t3 = x[4];
+ t4 = x[3];
+ } else {
+ t3 = x[3];
+ t4 = x[4];
+ }
+ if (t0 > t3)
+ {
+ MSWAP(t0, t3);
+ MSWAP(t1, t4);
+ }
+ if (t2 > t1)
+ {
+ if (t1 < t3)
+ return MIN16(t2, t3);
+ else
+ return MIN16(t4, t1);
+ } else {
+ if (t2 < t3)
+ return MIN16(t1, t3);
+ else
+ return MIN16(t2, t4);
+ }
+}
+
+static opus_val16 median_of_3(const opus_val16 *x)
+{
+ opus_val16 t0, t1, t2;
+ if (x[0] > x[1])
+ {
+ t0 = x[1];
+ t1 = x[0];
+ } else {
+ t0 = x[0];
+ t1 = x[1];
+ }
+ t2 = x[2];
+ if (t1 < t2)
+ return t1;
+ else if (t0 < t2)
+ return t2;
+ else
+ return t0;
+}
+
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,
@@ -895,6 +955,8 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
int last=0;
c=0;do
{
+ opus_val16 offset;
+ opus_val16 tmp;
follower[c*nbEBands] = bandLogE2[c*nbEBands];
for (i=1;i<end;i++)
{
@@ -907,6 +969,20 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
}
for (i=last-1;i>=0;i--)
follower[c*nbEBands+i] = MIN16(follower[c*nbEBands+i], MIN16(follower[c*nbEBands+i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i]));
+
+ /* Combine with a median filter to avoid dynalloc triggering unnecessarily.
+ The "offset" value controls how conservative we are -- a higher offset
+ reduces the impact of the median filter and makes dynalloc use more bits. */
+ offset = QCONST16(1.f, DB_SHIFT);
+ for (i=2;i<end-2;i++)
+ follower[c*nbEBands+i] = MAX16(follower[c*nbEBands+i], median_of_5(&bandLogE2[c*nbEBands+i-2])-offset);
+ tmp = median_of_3(&bandLogE2[c*nbEBands])-offset;
+ follower[c*nbEBands] = MAX16(follower[c*nbEBands], tmp);
+ follower[c*nbEBands+1] = MAX16(follower[c*nbEBands+1], tmp);
+ tmp = median_of_3(&bandLogE2[c*nbEBands+nbEBands-3])-offset;
+ follower[c*nbEBands+nbEBands-2] = MAX16(follower[c*nbEBands+nbEBands-2], tmp);
+ follower[c*nbEBands+nbEBands-1] = MAX16(follower[c*nbEBands+nbEBands-1], tmp);
+
for (i=0;i<end;i++)
follower[c*nbEBands+i] = MAX16(follower[c*nbEBands+i], noise_floor[i]);
} while (++c<C);