Skip to content

Commit b0e56e9

Browse files
authored
quantize: Pre-clamp scalefactor deltas to fix encoder/decoder mismatch (#100)
Problem: The post-loop delta clamping in BlocQuant() modified sf[] after qlevel() had already quantized the spectral data. When a negative delta exceeded -SF_DELTA, the decoder reconstructed using the clamped (larger) sf value while the encoder used the smaller (natural) gain. This gain mismatch caused post-echo artifacts in quiet bands following loud bands. Solution: Relocate the delta clamp inside qlevel(), prior to the quantization step, ensuring the encoder and decoder always operate on identical gain values. To support this, gain calculations and Huffman overflow limits are extracted into a single gain_with_overflow_clamp() helper. Variable names are updated (sf_rel, sf_abs) to explicitly distinguish between relative bitstream values and absolute energy levels, ensuring the pre-loaded IS stereo biases from AACstereo() are safely preserved.
1 parent ffded5f commit b0e56e9

1 file changed

Lines changed: 102 additions & 60 deletions

File tree

libfaac/quantize.c

Lines changed: 102 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
along with this program. If not, see <http://www.gnu.org/licenses/>.
1919
****************************************************************************/
2020

21+
#include <limits.h>
2122
#include <math.h>
2223
#include <stdio.h>
2324
#include <stdlib.h>
@@ -59,6 +60,9 @@ static QuantizeFunc qfunc = quantize_scalar;
5960
static faac_real sfstep;
6061
static faac_real max_quant_limit;
6162

63+
/* Sentinel: delta chain has no previous band yet (first active regular band). */
64+
#define SF_CHAIN_UNSET INT_MIN
65+
6266
void QuantizeInit(void)
6367
{
6468
#if defined(HAVE_SSE2)
@@ -76,6 +80,21 @@ void QuantizeInit(void)
7680
* Pre-calculated to avoid redundant runtime power functions. */
7781
max_quant_limit = FAAC_POW((faac_real)MAX_HUFF_ESC_VAL + 1.0 - MAGIC_NUMBER, 4.0/3.0);
7882
}
83+
84+
/* Compute gain from integer sfac, clamping against Huffman overflow.
85+
* Updates *sfac if clamping was applied. Returns the usable gain. */
86+
static faac_real gain_with_overflow_clamp(int *sfac, faac_real band_peak)
87+
{
88+
faac_real gain = FAAC_POW(10, *sfac / sfstep);
89+
if (band_peak > 0.0 && gain * band_peak > max_quant_limit)
90+
{
91+
gain = max_quant_limit / band_peak;
92+
*sfac = (int)FAAC_FLOOR(FAAC_LOG10(gain) * sfstep);
93+
gain = FAAC_POW(10, *sfac / sfstep);
94+
}
95+
return gain;
96+
}
97+
7998
#define NOISEFLOOR 0.4
8099

81100
// band sound masking
@@ -179,7 +198,8 @@ static void qlevel(CoderInfo * __restrict coderInfo,
179198
const faac_real * __restrict bandenrg,
180199
const faac_real * __restrict bandmaxe,
181200
int gnum,
182-
int pnslevel
201+
int pnslevel,
202+
int *p_last_abs /* previous active band's absolute stored scalefactor */
183203
)
184204
{
185205
int sb;
@@ -190,6 +210,7 @@ static void qlevel(CoderInfo * __restrict coderInfo,
190210
{
191211
faac_real sfacfix;
192212
int sfac;
213+
int sf_rel; /* relative scalefactor index: SF_OFFSET - sfac */
193214
faac_real rmsx;
194215
faac_real etot;
195216
int xitab[8 * MAXSHORTBAND];
@@ -226,22 +247,50 @@ static void qlevel(CoderInfo * __restrict coderInfo,
226247
}
227248

228249
sfac = FAAC_LRINT(FAAC_LOG10(bandqual[sb] / rmsx) * sfstep);
250+
sf_rel = SF_OFFSET - sfac;
251+
252+
/* sf_bias: IS intensity stereo energy offset pre-loaded into sf[] by
253+
* AACstereo() before qlevel() runs; zero for regular bands.
254+
* sf_abs = sf_bias + sf_rel is the value written to the bitstream.
255+
* Delta chain comparisons must use sf_abs, not sf_rel alone. */
256+
int sf_bias = coderInfo->sf[coderInfo->bandcnt];
257+
int sf_abs = sf_bias + sf_rel;
229258

230-
if ((SF_OFFSET - sfac) < SF_MIN)
259+
if (sf_rel < SF_MIN)
260+
{
231261
sfacfix = 0.0;
262+
}
232263
else
233264
{
234-
sfacfix = FAAC_POW(10, sfac / sfstep);
235-
236-
/* Bitstream saturation check: if gain * peak exceeds the Huffman limit,
237-
* clamp gain and re-sync the integer scalefactor to prevent overflow. */
238-
if (sfacfix * bandmaxe[sb] > max_quant_limit)
265+
/* Compute gain and clamp against Huffman overflow. */
266+
sfacfix = gain_with_overflow_clamp(&sfac, bandmaxe[sb]);
267+
sf_rel = SF_OFFSET - sfac;
268+
sf_abs = sf_bias + sf_rel;
269+
270+
/* Pre-clamp: enforce delta limits against the previous band's stored
271+
* value so encoder and decoder use the same gain (sf_abs). */
272+
if (*p_last_abs != SF_CHAIN_UNSET)
239273
{
240-
sfacfix = max_quant_limit / bandmaxe[sb];
241-
sfac = (int)FAAC_FLOOR(FAAC_LOG10(sfacfix) * sfstep);
242-
/* Re-derive gain from the floored scalefactor to ensure bit-exact
243-
* sync with the decoder's inverse quantizer. */
244-
sfacfix = FAAC_POW(10, sfac / sfstep);
274+
int diff = sf_abs - *p_last_abs;
275+
int clamped_diff = clamp_sf_diff(diff);
276+
if (clamped_diff != diff)
277+
{
278+
sf_abs = *p_last_abs + clamped_diff;
279+
sf_rel = sf_abs - sf_bias;
280+
sfac = SF_OFFSET - sf_rel;
281+
if (clamped_diff > 0)
282+
{
283+
/* Upward clamp raised gain; re-check Huffman overflow. */
284+
sfacfix = gain_with_overflow_clamp(&sfac, bandmaxe[sb]);
285+
sf_rel = SF_OFFSET - sfac;
286+
sf_abs = sf_bias + sf_rel;
287+
}
288+
else
289+
{
290+
/* Downward clamp lowered gain; overflow impossible. */
291+
sfacfix = FAAC_POW(10, sfac / sfstep);
292+
}
293+
}
245294
}
246295
}
247296

@@ -261,7 +310,11 @@ static void qlevel(CoderInfo * __restrict coderInfo,
261310
}
262311
}
263312
huffbook(coderInfo, xitab, gsize * end);
264-
coderInfo->sf[coderInfo->bandcnt++] += SF_OFFSET - sfac;
313+
/* Track sf_abs (full bitstream value) for the next band's delta check.
314+
* HCB_ZERO bands don't participate in the regular-band delta chain. */
315+
if (coderInfo->book[coderInfo->bandcnt] != HCB_ZERO)
316+
*p_last_abs = sf_abs;
317+
coderInfo->sf[coderInfo->bandcnt++] += sf_rel;
265318
}
266319
}
267320

@@ -278,63 +331,52 @@ int BlocQuant(CoderInfo * __restrict coder, faac_real * __restrict xr, AACQuantC
278331
coder->bandcnt = 0;
279332
coder->datacnt = 0;
280333

334+
int lastsf = SF_CHAIN_UNSET; /* no previous band yet; first active band skips delta clamp */
335+
336+
gxr = xr;
337+
for (cnt = 0; cnt < coder->groups.n; cnt++)
281338
{
282-
int lastis;
283-
int lastsf;
339+
bmask(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt,
340+
(faac_real)aacquantCfg->quality/DEFQUAL);
341+
qlevel(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt,
342+
aacquantCfg->pnslevel, &lastsf);
343+
gxr += coder->groups.len[cnt] * BLOCK_LEN_SHORT;
344+
}
284345

285-
gxr = xr;
286-
for (cnt = 0; cnt < coder->groups.n; cnt++)
346+
coder->global_gain = 0;
347+
for (cnt = 0; cnt < coder->bandcnt; cnt++)
348+
{
349+
int book = coder->book[cnt];
350+
if (!book)
351+
continue;
352+
if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2))
287353
{
288-
bmask(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt,
289-
(faac_real)aacquantCfg->quality/DEFQUAL);
290-
qlevel(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, aacquantCfg->pnslevel);
291-
gxr += coder->groups.len[cnt] * BLOCK_LEN_SHORT;
354+
coder->global_gain = coder->sf[cnt];
355+
break;
292356
}
357+
}
293358

294-
coder->global_gain = 0;
295-
for (cnt = 0; cnt < coder->bandcnt; cnt++)
359+
int lastis = 0;
360+
int lastpns = coder->global_gain - SF_PNS_OFFSET;
361+
for (cnt = 0; cnt < coder->bandcnt; cnt++)
362+
{
363+
int book = coder->book[cnt];
364+
if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2))
296365
{
297-
int book = coder->book[cnt];
298-
if (!book)
299-
continue;
300-
if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2))
301-
{
302-
coder->global_gain = coder->sf[cnt];
303-
break;
304-
}
366+
int diff = coder->sf[cnt] - lastis;
367+
diff = clamp_sf_diff(diff);
368+
lastis += diff;
369+
coder->sf[cnt] = lastis;
305370
}
306-
307-
lastsf = coder->global_gain;
308-
lastis = 0;
309-
int lastpns = coder->global_gain - SF_PNS_OFFSET;
310-
for (cnt = 0; cnt < coder->bandcnt; cnt++)
371+
else if (book == HCB_PNS)
311372
{
312-
int book = coder->book[cnt];
313-
if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2))
314-
{
315-
int diff = coder->sf[cnt] - lastis;
316-
diff = clamp_sf_diff(diff);
317-
lastis += diff;
318-
coder->sf[cnt] = lastis;
319-
}
320-
else if (book == HCB_PNS)
321-
{
322-
int diff = coder->sf[cnt] - lastpns;
323-
diff = clamp_sf_diff(diff);
324-
lastpns += diff;
325-
coder->sf[cnt] = lastpns;
326-
}
327-
else if ((book != HCB_ZERO) && (book != HCB_NONE))
328-
{
329-
int diff = coder->sf[cnt] - lastsf;
330-
diff = clamp_sf_diff(diff);
331-
lastsf += diff;
332-
coder->sf[cnt] = lastsf;
333-
}
373+
int diff = coder->sf[cnt] - lastpns;
374+
diff = clamp_sf_diff(diff);
375+
lastpns += diff;
376+
coder->sf[cnt] = lastpns;
334377
}
335-
return 1;
336378
}
337-
return 0;
379+
return 1;
338380
}
339381

340382
void CalcBW(unsigned *bw, int rate, SR_INFO *sr, AACQuantCfg *aacquantCfg)

0 commit comments

Comments
 (0)