diff --git a/libfaac/frame.c b/libfaac/frame.c index 1dc77805..db94d0a4 100644 --- a/libfaac/frame.c +++ b/libfaac/frame.c @@ -28,6 +28,7 @@ #include "channels.h" #include "bitstream.h" #include "filtbank.h" +#include "quantize.h" #include "util.h" #include "tns.h" #include "stereo.h" @@ -196,8 +197,8 @@ int FAACAPI faacEncSetConfiguration(faacEncHandle hpEncoder, if (!config->quantqual) { config->quantqual = (faac_real)config->bitRate * hEncoder->numChannels / 1280; - if (config->quantqual > 100) - config->quantqual = (config->quantqual - 100) * 3.0 + 100; + if (config->quantqual > DEFQUAL) + config->quantqual = (config->quantqual - DEFQUAL) * 3.0 + DEFQUAL; } } diff --git a/libfaac/huff2.c b/libfaac/huff2.c index e551182e..40108178 100644 --- a/libfaac/huff2.c +++ b/libfaac/huff2.c @@ -29,9 +29,9 @@ static int escape(int x, int *code) int preflen = 0; int base = 32; - if (x >= 8192) + if (x > MAX_HUFF_ESC_VAL) { - fprintf(stderr, "%s(%d): x_quant >= 8192\n", __FILE__, __LINE__); + fprintf(stderr, "%s(%d): x_quant > %d\n", __FILE__, __LINE__, MAX_HUFF_ESC_VAL); return 0; } @@ -430,7 +430,7 @@ int writesf(CoderInfo *coder, BitStream *stream, int write) lastsf = coder->global_gain; lastis = 0; - lastpns = coder->global_gain - 90; + lastpns = coder->global_gain - SF_PNS_OFFSET; // fixme: move range check to quantizer for (cnt = 0; cnt < coder->bandcnt; cnt++) @@ -440,18 +440,15 @@ int writesf(CoderInfo *coder, BitStream *stream, int write) if ((book == HCB_INTENSITY) || (book== HCB_INTENSITY2)) { diff = coder->sf[cnt] - lastis; - if (diff > 60) - diff = 60; - if (diff < -60) - diff = -60; - length = book12[60 + diff].len; + diff = clamp_sf_diff(diff); + length = book12[SF_DELTA + diff].len; bits += length; lastis += diff; if (write) - PutBit(stream, book12[60 + diff].data, length); + PutBit(stream, book12[SF_DELTA + diff].data, length); } else if (book == HCB_PNS) { @@ -470,32 +467,26 @@ int writesf(CoderInfo *coder, BitStream *stream, int write) continue; } - if (diff > 60) - diff = 60; - if (diff < -60) - diff = -60; + diff = clamp_sf_diff(diff); - length = book12[60 + diff].len; + length = book12[SF_DELTA + diff].len; bits += length; lastpns += diff; if (write) - PutBit(stream, book12[60 + diff].data, length); + PutBit(stream, book12[SF_DELTA + diff].data, length); } - else if (book) + else if ((book != HCB_ZERO) && (book != HCB_NONE)) { diff = coder->sf[cnt] - lastsf; - if (diff > 60) - diff = 60; - if (diff < -60) - diff = -60; - length = book12[60 + diff].len; + diff = clamp_sf_diff(diff); + length = book12[SF_DELTA + diff].len; bits += length; lastsf += diff; if (write) - PutBit(stream, book12[60 + diff].data, length); + PutBit(stream, book12[SF_DELTA + diff].data, length); } } diff --git a/libfaac/huff2.h b/libfaac/huff2.h index c8be2a02..aea92c57 100644 --- a/libfaac/huff2.h +++ b/libfaac/huff2.h @@ -17,8 +17,12 @@ along with this program. If not, see . ****************************************************************************/ +#ifndef HUFF2_H +#define HUFF2_H + #include "bitstream.h" +/* Huffman Codebooks */ enum { HCB_ZERO = 0, HCB_ESC = 11, @@ -28,8 +32,39 @@ enum { HCB_NONE }; +/* Maximum value representable by Huffman Book 11 escape sequences. + * Values >= 8192 would cause bitstream overflow/sync loss. */ +#define MAX_HUFF_ESC_VAL 8191 + +/* Scalefactor Management */ +enum { + /* Baseline scalefactor value used in bitstream */ + SF_OFFSET = 100, + /* Minimum allowable scalefactor to prevent underflow */ + SF_MIN = 10, + /* PNS predictor initialization offset (starts at floor) */ + SF_PNS_OFFSET = SF_OFFSET - SF_MIN, + /* Max allowed difference between successive scalefactors (AAC spec) */ + SF_DELTA = 60, +}; + +/** + * Restrict scalefactor delta to the spec-defined +/- SF_DELTA range. + * This ensures the delta remains valid for Book 12 Huffman encoding. + */ +static inline int clamp_sf_diff(int diff) +{ + if (diff > SF_DELTA) + return SF_DELTA; + if (diff < -SF_DELTA) + return -SF_DELTA; + return diff; +} + int huffbook(CoderInfo *coderInfo, int *qs /* quantized spectrum */, int len); int writebooks(CoderInfo *coder, BitStream *stream, int writeFlag); int writesf(CoderInfo *coder, BitStream *bitStream, int writeFlag); + +#endif /* HUFF2_H */ diff --git a/libfaac/huffdata.c b/libfaac/huffdata.c index 8fd63a39..907520cf 100644 --- a/libfaac/huffdata.c +++ b/libfaac/huffdata.c @@ -213,7 +213,7 @@ hcode16_t book11[289] = { {5,4}, }; -hcode32_t book12[121] = { +hcode32_t book12[2 * SF_DELTA + 1] = { {18,262120},{18,262118},{18,262119},{18,262117},{19,524277},{19,524273},{19,524269},{19,524278}, {19,524270},{19,524271},{19,524272},{19,524284},{19,524285},{19,524287},{19,524286},{19,524279}, {19,524280},{19,524283},{19,524281},{18,262116},{19,524282},{18,262115},{17,131055},{17,131056}, diff --git a/libfaac/huffdata.h b/libfaac/huffdata.h index 8a43f66e..821b66ae 100644 --- a/libfaac/huffdata.h +++ b/libfaac/huffdata.h @@ -15,6 +15,11 @@ along with this program. If not, see . ****************************************************************************/ +#ifndef HUFFDATA_H +#define HUFFDATA_H + +#include "huff2.h" + #include typedef struct { @@ -38,4 +43,6 @@ extern hcode16_t book08[64]; extern hcode16_t book09[169]; extern hcode16_t book10[169]; extern hcode16_t book11[289]; -extern hcode32_t book12[121]; +extern hcode32_t book12[2 * SF_DELTA + 1]; + +#endif /* HUFFDATA_H */ diff --git a/libfaac/quantize.c b/libfaac/quantize.c index cd26f6c5..1a1e4d1f 100644 --- a/libfaac/quantize.c +++ b/libfaac/quantize.c @@ -56,6 +56,8 @@ static void quantize_scalar(const faac_real * __restrict xr, int * __restrict xi } static QuantizeFunc qfunc = quantize_scalar; +static faac_real sfstep; +static faac_real max_quant_limit; void QuantizeInit(void) { @@ -66,12 +68,19 @@ void QuantizeInit(void) else #endif qfunc = quantize_scalar; + + /* 2^0.25 (1.50515 dB) step from AAC specs */ + sfstep = 1.0 / FAAC_LOG10(FAAC_SQRT(FAAC_SQRT(2.0))); + + /* Inverse-quantizer headroom: ensures (x * gain)^0.75 + 0.4054 <= 8191. + * Pre-calculated to avoid redundant runtime power functions. */ + max_quant_limit = FAAC_POW((faac_real)MAX_HUFF_ESC_VAL + 1.0 - MAGIC_NUMBER, 4.0/3.0); } #define NOISEFLOOR 0.4 // band sound masking static void bmask(CoderInfo * __restrict coderInfo, faac_real * __restrict xr0, faac_real * __restrict bandqual, - faac_real * __restrict bandenrg, int gnum, faac_real quality) + faac_real * __restrict bandenrg, faac_real * __restrict bandmaxe, int gnum, faac_real quality) { int sfb, start, end, cnt; int *cb_offset = coderInfo->sfb_offset; @@ -130,6 +139,8 @@ static void bmask(CoderInfo * __restrict coderInfo, faac_real * __restrict xr0, } } bandenrg[sfb] = avge; + /* Track peak magnitude to identify potential Huffman overflows. */ + bandmaxe[sfb] = FAAC_SQRT(maxe); maxe *= gsize; #define NOISETONE 0.2 @@ -166,21 +177,16 @@ static void qlevel(CoderInfo * __restrict coderInfo, const faac_real * __restrict xr0, const faac_real * __restrict bandqual, const faac_real * __restrict bandenrg, + const faac_real * __restrict bandmaxe, int gnum, int pnslevel ) { int sb; -#if !defined(__clang__) && defined(__GNUC__) && (GCC_VERSION >= 40600) - /* 2^0.25 (1.50515 dB) step from AAC specs */ - static const faac_real sfstep = 1.0 / FAAC_LOG10(FAAC_SQRT(FAAC_SQRT(2.0))); -#else - static const faac_real sfstep = 20 / 1.50515; -#endif int gsize = coderInfo->groups.len[gnum]; faac_real pnsthr = 0.1 * pnslevel; - for (sb = 0; sb < coderInfo->sfbn; sb++) + for (sb = 0; sb < coderInfo->sfbn && coderInfo->bandcnt < MAX_SCFAC_BANDS; sb++) { faac_real sfacfix; int sfac; @@ -220,11 +226,25 @@ static void qlevel(CoderInfo * __restrict coderInfo, } sfac = FAAC_LRINT(FAAC_LOG10(bandqual[sb] / rmsx) * sfstep); - if ((SF_OFFSET - sfac) < 10) + + if ((SF_OFFSET - sfac) < SF_MIN) sfacfix = 0.0; else + { sfacfix = FAAC_POW(10, sfac / sfstep); + /* Bitstream saturation check: if gain * peak exceeds the Huffman limit, + * clamp gain and re-sync the integer scalefactor to prevent overflow. */ + if (sfacfix * bandmaxe[sb] > max_quant_limit) + { + sfacfix = max_quant_limit / bandmaxe[sb]; + sfac = (int)FAAC_FLOOR(FAAC_LOG10(sfacfix) * sfstep); + /* Re-derive gain from the floored scalefactor to ensure bit-exact + * sync with the decoder's inverse quantizer. */ + sfacfix = FAAC_POW(10, sfac / sfstep); + } + } + end -= start; xi = xitab; if (sfacfix <= 0.0) @@ -249,6 +269,7 @@ int BlocQuant(CoderInfo * __restrict coder, faac_real * __restrict xr, AACQuantC { faac_real bandlvl[MAX_SCFAC_BANDS]; faac_real bandenrg[MAX_SCFAC_BANDS]; + faac_real bandmaxe[MAX_SCFAC_BANDS]; int cnt; faac_real *gxr; @@ -264,9 +285,9 @@ int BlocQuant(CoderInfo * __restrict coder, faac_real * __restrict xr, AACQuantC gxr = xr; for (cnt = 0; cnt < coder->groups.n; cnt++) { - bmask(coder, gxr, bandlvl, bandenrg, cnt, + bmask(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, (faac_real)aacquantCfg->quality/DEFQUAL); - qlevel(coder, gxr, bandlvl, bandenrg, cnt, aacquantCfg->pnslevel); + qlevel(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, aacquantCfg->pnslevel); gxr += coder->groups.len[cnt] * BLOCK_LEN_SHORT; } @@ -285,31 +306,28 @@ int BlocQuant(CoderInfo * __restrict coder, faac_real * __restrict xr, AACQuantC lastsf = coder->global_gain; lastis = 0; - // fixme: move SF range check to quantizer + int lastpns = coder->global_gain - SF_PNS_OFFSET; for (cnt = 0; cnt < coder->bandcnt; cnt++) { int book = coder->book[cnt]; if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2)) { int diff = coder->sf[cnt] - lastis; - - if (diff < -60) - diff = -60; - if (diff > 60) - diff = 60; - + diff = clamp_sf_diff(diff); lastis += diff; coder->sf[cnt] = lastis; } - else if (book == HCB_ESC) + else if (book == HCB_PNS) + { + int diff = coder->sf[cnt] - lastpns; + diff = clamp_sf_diff(diff); + lastpns += diff; + coder->sf[cnt] = lastpns; + } + else if ((book != HCB_ZERO) && (book != HCB_NONE)) { int diff = coder->sf[cnt] - lastsf; - - if (diff < -60) - diff = -60; - if (diff > 60) - diff = 60; - + diff = clamp_sf_diff(diff); lastsf += diff; coder->sf[cnt] = lastsf; } diff --git a/libfaac/quantize.h b/libfaac/quantize.h index 26c4c193..cbeef1c2 100644 --- a/libfaac/quantize.h +++ b/libfaac/quantize.h @@ -44,7 +44,6 @@ enum { MAXQUAL = 5000, MAXQUALADTS = MAXQUAL, MINQUAL = 10, - SF_OFFSET = 100, }; int BlocQuant(CoderInfo *coderInfo, faac_real *xr, AACQuantCfg *aacquantCfg);