diff options
author | Timothy B. Terriberry <tterribe@xiph.org> | 2011-01-20 03:30:03 +0300 |
---|---|---|
committer | Jean-Marc Valin <jean-marc.valin@usherbrooke.ca> | 2011-01-20 03:43:08 +0300 |
commit | 21af73eb217f64fef2f549bc752b860fc95e0293 (patch) | |
tree | e7652cbe2e90e2465d55c14d153fae1428a02608 /libcelt/vq.c | |
parent | 87efe1df00c6f952e4121c103af787f755723b59 (diff) |
Make collapse-detection bitexact.
Jean-Marc's original anti-collapse patch used a threshold on the
content of a decoded band to determine whether or not it should
be filled with random noise.
Since this is highly sensitive to the accuracy of the
implementation, it could lead to significant decoder output
differences even if decoding error up to that point was relatively
small.
This patch detects collapsed bands from the output of the vector
quantizer, using exact integer arithmetic.
It makes two simplifying assumptions:
a) If either input to haar1() is non-zero during TF resolution
adjustments, then the output will be non-zero.
b) If the content of a block is non-zero in any of the bands that
are used for folding, then the folded output will be non-zero.
b) in particular is likely to be false when SPREAD_NONE is used.
It also ignores the case where mid and side are orthogonal in
stereo_merge, but this is relatively unlikely.
This misses just over 3% of the cases that Jean-Marc's anti-collapse
detection strategy would catch, but does not mis-classify any (all
detected collapses are true collapses).
This patch overloads the "fill" parameter to mark which blocks have
non-zero content for folding.
As a consequence, if a set of blocks on one side of a split has
collapsed, _no_ folding is done: the result would be zero anyway,
except for short blocks with SPREAD_AGGRESSIVE that are split down
to a single block, but a) that means a lot of bits were available
so a collapse is unlikely and b) anti-collapse can fill the block
anyway, if it's used.
This also means that if itheta==0 or itheta==16384, we no longer
fold at all on that side (even with long blocks), since we'd be
multiplying the result by zero anyway.
Diffstat (limited to 'libcelt/vq.c')
-rw-r--r-- | libcelt/vq.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/libcelt/vq.c b/libcelt/vq.c index ed2c46a..e5f2b98 100644 --- a/libcelt/vq.c +++ b/libcelt/vq.c @@ -106,6 +106,8 @@ static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int while ((stride2*stride2+stride2)*stride + (stride>>2) < len) stride2++; } + /*TODO: We should be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ len /= stride; for (i=0;i<stride;i++) { @@ -153,7 +155,27 @@ static void normalise_residual(int * restrict iy, celt_norm * restrict X, while (++i < N); } -void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband, +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*TODO: We should be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = N/B; + collapse_mask = 0; + i=0; do { + int j; + j=0; do { + collapse_mask |= (iy[i*N0+j]!=0)<<i; + } while (++j<N0); + } while (++i<B); + return collapse_mask; +} + +unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband, int resynth, ec_enc *enc, celt_int32 *seed, celt_word16 gain) { VARDECL(celt_norm, y); @@ -165,6 +187,7 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband celt_word32 sum; celt_word32 xy; celt_word16 yy; + unsigned collapse_mask; SAVE_STACK; celt_assert2(K!=0, "alg_quant() needs at least one pulse"); @@ -308,17 +331,20 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband normalise_residual(iy, X, N, K, yy, gain); exp_rotation(X, N, -1, B, K, spread); } + collapse_mask = extract_collapse_mask(iy, N, B); RESTORE_STACK; + return collapse_mask; } /** Decode pulse vector and combine the result with the pitch vector to produce the final normalised signal in the current band. */ -void alg_unquant(celt_norm *X, int N, int K, int spread, int B, +unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband, ec_dec *dec, celt_int32 *seed, celt_word16 gain) { int i; celt_word32 Ryy; + unsigned collapse_mask; VARDECL(int, iy); SAVE_STACK; @@ -332,7 +358,9 @@ void alg_unquant(celt_norm *X, int N, int K, int spread, int B, } while (++i < N); normalise_residual(iy, X, N, K, Ryy, gain); exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); RESTORE_STACK; + return collapse_mask; } void renormalise_vector(celt_norm *X, int N, celt_word16 gain) |