diff options
-rw-r--r-- | libavcodec/aaccoder.c | 101 |
1 files changed, 76 insertions, 25 deletions
diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c index f265103173..8a241d2c06 100644 --- a/libavcodec/aaccoder.c +++ b/libavcodec/aaccoder.c @@ -49,16 +49,15 @@ #include "aacenc_pred.h" /** Frequency in Hz for lower limit of noise substitution **/ -#define NOISE_LOW_LIMIT 4500 +#define NOISE_LOW_LIMIT 4000 -/* Energy spread threshold value below which no PNS is used, this corresponds to - * typically around 17Khz, after which PNS usage decays ending at 19Khz */ -#define NOISE_SPREAD_THRESHOLD 0.5f +/* Parameter of f(x) = a*(lambda/100), defines the maximum fourier spread + * beyond which no PNS is used (since the SFBs contain tone rather than noise) */ +#define NOISE_SPREAD_THRESHOLD 0.9673f -/* This constant gets divided by lambda to return ~1.65 which when multiplied - * by the band->threshold and compared to band->energy is the boundary between - * excessive PNS and little PNS usage. */ -#define NOISE_LAMBDA_NUMERATOR 252.1f +/* Parameter of f(x) = a*(100/lambda), defines how much PNS is allowed to + * replace low energy non zero bands */ +#define NOISE_LAMBDA_REPLACE 1.948f /** * structure used in optimal codebook search @@ -863,30 +862,82 @@ static void search_for_quantizers_fast(AVCodecContext *avctx, AACEncContext *s, static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce) { - int start = 0, w, w2, g; + FFPsyBand *band; + int w, g, w2, i, start, count = 0; + float *PNS = &s->scoefs[0*128], *PNS34 = &s->scoefs[1*128]; + float *NOR34 = &s->scoefs[3*128]; const float lambda = s->lambda; const float freq_mult = avctx->sample_rate/(1024.0f/sce->ics.num_windows)/2.0f; - const float spread_threshold = NOISE_SPREAD_THRESHOLD*(lambda/120.f); - const float thr_mult = NOISE_LAMBDA_NUMERATOR/lambda; + const float thr_mult = NOISE_LAMBDA_REPLACE*(100.0f/lambda); + const float spread_threshold = NOISE_SPREAD_THRESHOLD*(lambda/100.f); for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { start = 0; for (g = 0; g < sce->ics.num_swb; g++) { - if (start*freq_mult > NOISE_LOW_LIMIT*(lambda/170.0f)) { - float energy = 0.0f, threshold = 0.0f, spread = 0.0f; - for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { - FFPsyBand *band = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g]; - energy += band->energy; - threshold += band->threshold; - spread += band->spread; - } - if (spread > spread_threshold*sce->ics.group_len[w] && - ((sce->zeroes[w*16+g] && energy >= threshold) || - energy < threshold*thr_mult*sce->ics.group_len[w])) { - sce->band_type[w*16+g] = NOISE_BT; - sce->pns_ener[w*16+g] = energy / sce->ics.group_len[w]; - sce->zeroes[w*16+g] = 0; + int noise_sfi, try_pns = 0; + float dist1 = 0.0f, dist2 = 0.0f, noise_amp; + float energy = 0.0f, threshold = 0.0f, spread = 0.0f; + if (start*freq_mult < NOISE_LOW_LIMIT) { + start += sce->ics.swb_sizes[g]; + continue; + } + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + energy += band->energy; + spread += band->spread; + threshold += band->threshold; + } + sce->pns_ener[w*16+g] = energy; + + if (sce->zeroes[w*16+g]) { + try_pns = 1; + } else if (energy < threshold) { + try_pns = 1; + } else if (spread > spread_threshold) { + try_pns = 0; + } else if (energy < threshold*thr_mult) { + try_pns = 1; + } + + if (!try_pns || !energy) { + start += sce->ics.swb_sizes[g]; + continue; + } + + noise_sfi = av_clip(roundf(log2f(energy)*2), -100, 155); /* Quantize */ + noise_amp = -ff_aac_pow2sf_tab[noise_sfi + POW_SF2_ZERO]; /* Dequantize */ + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + float band_energy, scale; + band = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g]; + for (i = 0; i < sce->ics.swb_sizes[g]; i++) + PNS[i] = s->random_state = lcg_random(s->random_state); + band_energy = s->fdsp->scalarproduct_float(PNS, PNS, sce->ics.swb_sizes[g]); + scale = noise_amp/sqrtf(band_energy); + s->fdsp->vector_fmul_scalar(PNS, PNS, scale, sce->ics.swb_sizes[g]); + abs_pow34_v(NOR34, &sce->coeffs[start+(w+w2)*128], sce->ics.swb_sizes[g]); + abs_pow34_v(PNS34, PNS, sce->ics.swb_sizes[g]); + dist1 += quantize_band_cost(s, &sce->coeffs[start + (w+w2)*128], + NOR34, + sce->ics.swb_sizes[g], + sce->sf_idx[(w+w2)*16+g], + sce->band_alt[(w+w2)*16+g], + lambda/band->threshold, INFINITY, NULL, 0); + dist2 += quantize_band_cost(s, PNS, + PNS34, + sce->ics.swb_sizes[g], + noise_sfi, + NOISE_BT, + lambda/band->threshold, INFINITY, NULL, 0); + } + if (dist2 < dist1) { + sce->band_type[w*16+g] = NOISE_BT; + sce->zeroes[w*16+g] = 0; + if (sce->band_type[w*16+g-1] != NOISE_BT && /* Prevent holes */ + sce->band_type[w*16+g-2] == NOISE_BT) { + sce->band_type[w*16+g-1] = NOISE_BT; + sce->zeroes[w*16+g-1] = 0; } + count++; } start += sce->ics.swb_sizes[g]; } |