/**************************************************************************** Quantizer core functions quality setting, error distribution, etc. Copyright (C) 2017 Krzysztof Nikiel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****************************************************************************/ #include #include #include #include #include #include "quantize.h" #include "huff2.h" #include "cpu_compute.h" #ifdef __GNUC__ #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #endif typedef void (*QuantizeFunc)(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix); #if defined(HAVE_SSE2) extern void quantize_sse2(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix); #endif static void quantize_scalar(const faac_real * __restrict xr, int * __restrict xi, int n, faac_real sfacfix) { const faac_real magic = MAGIC_NUMBER; int cnt; for (cnt = 0; cnt < n; cnt++) { faac_real val = xr[cnt]; faac_real tmp = FAAC_FABS(val); tmp *= sfacfix; tmp = FAAC_SQRT(tmp * FAAC_SQRT(tmp)); int q = (int)(tmp + magic); xi[cnt] = (val < 0) ? -q : q; } } static QuantizeFunc qfunc = quantize_scalar; static faac_real sfstep; static faac_real max_quant_limit; /* Sentinel: delta chain has no previous band yet (first active regular band). */ #define SF_CHAIN_UNSET INT_MIN void QuantizeInit(void) { #if defined(HAVE_SSE2) CPUCaps caps = get_cpu_caps(); if (caps & CPU_CAP_SSE2) qfunc = quantize_sse2; 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); } /* Compute gain from integer sfac, clamping against Huffman overflow. * Updates *sfac if clamping was applied. Returns the usable gain. */ static faac_real gain_with_overflow_clamp(int *sfac, faac_real band_peak) { faac_real gain = FAAC_POW(10, *sfac / sfstep); if (band_peak > 0.0 && gain * band_peak > max_quant_limit) { gain = max_quant_limit / band_peak; *sfac = (int)FAAC_FLOOR(FAAC_LOG10(gain) * sfstep); gain = FAAC_POW(10, *sfac / sfstep); } return gain; } #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, faac_real * __restrict bandmaxe, int gnum, faac_real quality) { int sfb, start, end, cnt; int *cb_offset = coderInfo->sfb_offset; int last; faac_real avgenrg; faac_real powm = 0.4; faac_real totenrg = 0.0; int gsize = coderInfo->groups.len[gnum]; const faac_real *xr; int win; int enrgcnt = 0; int total_len = coderInfo->sfb_offset[coderInfo->sfbn]; for (win = 0; win < gsize; win++) { xr = xr0 + win * BLOCK_LEN_SHORT; for (cnt = 0; cnt < total_len; cnt++) { totenrg += xr[cnt] * xr[cnt]; } } enrgcnt = gsize * total_len; if (totenrg < ((NOISEFLOOR * NOISEFLOOR) * (faac_real)enrgcnt)) { for (sfb = 0; sfb < coderInfo->sfbn; sfb++) { bandqual[sfb] = 0.0; bandenrg[sfb] = 0.0; } return; } for (sfb = 0; sfb < coderInfo->sfbn; sfb++) { faac_real avge, maxe; faac_real target; start = cb_offset[sfb]; end = cb_offset[sfb + 1]; avge = 0.0; maxe = 0.0; for (win = 0; win < gsize; win++) { xr = xr0 + win * BLOCK_LEN_SHORT + start; int n = end - start; for (cnt = 0; cnt < n; cnt++) { faac_real val = xr[cnt]; faac_real e = val * val; avge += e; if (maxe < e) maxe = e; } } bandenrg[sfb] = avge; /* Track peak magnitude to identify potential Huffman overflows. */ bandmaxe[sfb] = FAAC_SQRT(maxe); maxe *= gsize; #define NOISETONE 0.2 if (coderInfo->block_type == ONLY_SHORT_WINDOW) { last = BLOCK_LEN_SHORT; avgenrg = totenrg / last; avgenrg *= end - start; target = NOISETONE * FAAC_POW(avge/avgenrg, powm); target += (1.0 - NOISETONE) * 0.45 * FAAC_POW(maxe/avgenrg, powm); target *= 1.5; } else { last = BLOCK_LEN_LONG; avgenrg = totenrg / last; avgenrg *= end - start; target = NOISETONE * FAAC_POW(avge/avgenrg, powm); target += (1.0 - NOISETONE) * 0.45 * FAAC_POW(maxe/avgenrg, powm); } target *= 10.0 / (1.0 + ((faac_real)(start+end)/last)); bandqual[sfb] = target * quality; } } enum {MAXSHORTBAND = 36}; // use band quality levels to quantize a group of windows 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 *p_last_abs /* previous active band's absolute stored scalefactor */ ) { int sb; int gsize = coderInfo->groups.len[gnum]; faac_real pnsthr = 0.1 * pnslevel; for (sb = 0; sb < coderInfo->sfbn && coderInfo->bandcnt < MAX_SCFAC_BANDS; sb++) { faac_real sfacfix; int sfac; int sf_rel; /* relative scalefactor index: SF_OFFSET - sfac */ faac_real rmsx; faac_real etot; int xitab[8 * MAXSHORTBAND]; int *xi; int start, end; const faac_real *xr; int win; if (coderInfo->book[coderInfo->bandcnt] != HCB_NONE) { coderInfo->bandcnt++; continue; } start = coderInfo->sfb_offset[sb]; end = coderInfo->sfb_offset[sb+1]; etot = bandenrg[sb] / (faac_real)gsize; rmsx = FAAC_SQRT(etot / (end - start)); if ((rmsx < NOISEFLOOR) || (!bandqual[sb])) { coderInfo->book[coderInfo->bandcnt++] = HCB_ZERO; continue; } if (bandqual[sb] < pnsthr) { coderInfo->book[coderInfo->bandcnt] = HCB_PNS; coderInfo->sf[coderInfo->bandcnt] += FAAC_LRINT(FAAC_LOG10(etot) * (0.5 * sfstep)); coderInfo->bandcnt++; continue; } sfac = FAAC_LRINT(FAAC_LOG10(bandqual[sb] / rmsx) * sfstep); sf_rel = SF_OFFSET - sfac; /* sf_bias: IS intensity stereo energy offset pre-loaded into sf[] by * AACstereo() before qlevel() runs; zero for regular bands. * sf_abs = sf_bias + sf_rel is the value written to the bitstream. * Delta chain comparisons must use sf_abs, not sf_rel alone. */ int sf_bias = coderInfo->sf[coderInfo->bandcnt]; int sf_abs = sf_bias + sf_rel; if (sf_rel < SF_MIN) { sfacfix = 0.0; } else { /* Compute gain and clamp against Huffman overflow. */ sfacfix = gain_with_overflow_clamp(&sfac, bandmaxe[sb]); sf_rel = SF_OFFSET - sfac; sf_abs = sf_bias + sf_rel; /* Pre-clamp: enforce delta limits against the previous band's stored * value so encoder and decoder use the same gain (sf_abs). */ if (*p_last_abs != SF_CHAIN_UNSET) { int diff = sf_abs - *p_last_abs; int clamped_diff = clamp_sf_diff(diff); if (clamped_diff != diff) { sf_abs = *p_last_abs + clamped_diff; sf_rel = sf_abs - sf_bias; sfac = SF_OFFSET - sf_rel; if (clamped_diff > 0) { /* Upward clamp raised gain; re-check Huffman overflow. */ sfacfix = gain_with_overflow_clamp(&sfac, bandmaxe[sb]); sf_rel = SF_OFFSET - sfac; sf_abs = sf_bias + sf_rel; } else { /* Downward clamp lowered gain; overflow impossible. */ sfacfix = FAAC_POW(10, sfac / sfstep); } } } } end -= start; xi = xitab; if (sfacfix <= 0.0) { memset(xi, 0, gsize * end * sizeof(int)); } else { for (win = 0; win < gsize; win++) { xr = xr0 + win * BLOCK_LEN_SHORT + start; qfunc(xr, xi, end, sfacfix); xi += end; } } huffbook(coderInfo, xitab, gsize * end); /* Track sf_abs (full bitstream value) for the next band's delta check. * HCB_ZERO bands don't participate in the regular-band delta chain. */ if (coderInfo->book[coderInfo->bandcnt] != HCB_ZERO) *p_last_abs = sf_abs; coderInfo->sf[coderInfo->bandcnt++] += sf_rel; } } int BlocQuant(CoderInfo * __restrict coder, faac_real * __restrict xr, AACQuantCfg *aacquantCfg) { faac_real bandlvl[MAX_SCFAC_BANDS]; faac_real bandenrg[MAX_SCFAC_BANDS]; faac_real bandmaxe[MAX_SCFAC_BANDS]; int cnt; faac_real *gxr; coder->global_gain = 0; coder->bandcnt = 0; coder->datacnt = 0; int lastsf = SF_CHAIN_UNSET; /* no previous band yet; first active band skips delta clamp */ gxr = xr; for (cnt = 0; cnt < coder->groups.n; cnt++) { bmask(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, (faac_real)aacquantCfg->quality/DEFQUAL); qlevel(coder, gxr, bandlvl, bandenrg, bandmaxe, cnt, aacquantCfg->pnslevel, &lastsf); gxr += coder->groups.len[cnt] * BLOCK_LEN_SHORT; } coder->global_gain = 0; for (cnt = 0; cnt < coder->bandcnt; cnt++) { int book = coder->book[cnt]; if (!book) continue; if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2)) { coder->global_gain = coder->sf[cnt]; break; } } int lastis = 0; 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; diff = clamp_sf_diff(diff); lastis += diff; coder->sf[cnt] = lastis; } else if (book == HCB_PNS) { int diff = coder->sf[cnt] - lastpns; diff = clamp_sf_diff(diff); lastpns += diff; coder->sf[cnt] = lastpns; } } return 1; } void CalcBW(unsigned *bw, int rate, SR_INFO *sr, AACQuantCfg *aacquantCfg) { // find max short frame band int max = *bw * (BLOCK_LEN_SHORT << 1) / rate; int cnt; int l; l = 0; for (cnt = 0; cnt < sr->num_cb_short; cnt++) { if (l >= max) break; l += sr->cb_width_short[cnt]; } aacquantCfg->max_cbs = cnt; if (aacquantCfg->pnslevel) *bw = (faac_real)l * rate / (BLOCK_LEN_SHORT << 1); // find max long frame band max = *bw * (BLOCK_LEN_LONG << 1) / rate; l = 0; for (cnt = 0; cnt < sr->num_cb_long; cnt++) { if (l >= max) break; l += sr->cb_width_long[cnt]; } aacquantCfg->max_cbl = cnt; aacquantCfg->max_l = l; *bw = (faac_real)l * rate / (BLOCK_LEN_LONG << 1); } enum {MINSFB = 2}; static void calce(faac_real * __restrict xr, const int * __restrict bands, faac_real e[NSFB_SHORT], int maxsfb, int maxl) { int sfb; int l; // mute lines above cutoff freq for (l = maxl; l < bands[maxsfb]; l++) xr[l] = 0.0; for (sfb = MINSFB; sfb < maxsfb; sfb++) { e[sfb] = 0; for (l = bands[sfb]; l < bands[sfb + 1]; l++) e[sfb] += xr[l] * xr[l]; } } static void resete(faac_real min[NSFB_SHORT], faac_real max[NSFB_SHORT], faac_real e[NSFB_SHORT], int maxsfb) { int sfb; for (sfb = MINSFB; sfb < maxsfb; sfb++) min[sfb] = max[sfb] = e[sfb]; } #define PRINTSTAT 0 #if PRINTSTAT static int groups = 0; static int frames = 0; #endif void BlocGroup(faac_real *xr, CoderInfo *coderInfo, AACQuantCfg *cfg) { int win, sfb; faac_real e[NSFB_SHORT]; faac_real min[NSFB_SHORT]; faac_real max[NSFB_SHORT]; const faac_real thr = 3.0; int win0; int fastmin; int maxsfb, maxl; if (coderInfo->block_type != ONLY_SHORT_WINDOW) { coderInfo->groups.n = 1; coderInfo->groups.len[0] = 1; return; } maxl = cfg->max_l / 8; maxsfb = cfg->max_cbs; fastmin = ((maxsfb - MINSFB) * 3) >> 2; #if PRINTSTAT frames++; #endif calce(xr, coderInfo->sfb_offset, e, maxsfb, maxl); resete(min, max, e, maxsfb); win0 = 0; coderInfo->groups.n = 0; for (win = 1; win < MAX_SHORT_WINDOWS; win++) { int fast = 0; calce(xr + win * BLOCK_LEN_SHORT, coderInfo->sfb_offset, e, maxsfb, maxl); for (sfb = MINSFB; sfb < maxsfb; sfb++) { if (min[sfb] > e[sfb]) min[sfb] = e[sfb]; if (max[sfb] < e[sfb]) max[sfb] = e[sfb]; if (max[sfb] > thr * min[sfb]) fast++; } if (fast > fastmin) { coderInfo->groups.len[coderInfo->groups.n++] = win - win0; win0 = win; resete(min, max, e, maxsfb); } } coderInfo->groups.len[coderInfo->groups.n++] = win - win0; #if PRINTSTAT groups += coderInfo->groups.n; #endif } void BlocStat(void) { #if PRINTSTAT printf("frames:%d; groups:%d; g/f:%f\n", frames, groups, (faac_real)groups/frames); #endif }