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);