History

AAC encoder: improve SF range utilization

This patch does 4 things, all of which interact and thus it woudln't be possible to commit them separately without causing either quality regressions or assertion failures. Fate comparison targets don't all reflect improvements in quality, yet listening tests show substantially improved quality and stability. 1. Increase SF range utilization. The spec requires SF delta values to be constrained within the range -60..60. The previous code was applying that range to the whole SF array and not only the deltas of consecutive values, because doing so requires smarter code: zeroing or otherwise skipping a band may invalidate lots of SF choices. This patch implements that logic to allow the coders to utilize the full dynamic range of scalefactors, increasing quality quite considerably, and fixing delta-SF-related assertion failures, since now the limitation is enforced rather than asserted. 2. PNS tweaks The previous modification makes big improvements in twoloop's efficiency, and every time that happens PNS logic needs to be tweaked accordingly to avoid it from stepping all over twoloop's decisions. This patch includes modifications of the sort. 3. Account for lowpass cutoff during PSY analysis The closer PSY's allocation is to final allocation the better the quality is, and given these modifications, twoloop is now very efficient at avoiding holes. Thus, to compute accurate thresholds, PSY needs to account for the lowpass applied implicitly during twoloop (by zeroing high bands). This patch makes twoloop set the cutoff in psymodel's context the first time it runs, and makes PSY account for it during threshold computation, making PE and threshold computations closer to the final allocation and thus achieving better subjective quality. 4. Tweaks to RC lambda tracking loop in relation to PNS Without this tweak some corner cases cause quality regressions. Basically, lambda needs to react faster to overall bitrate efficiency changes since now PNS can be quite successful in enforcing maximum bitrates, when PSY allocates too many bits to the lower bands, suppressing the signals RC logic uses to lower lambda in those cases and causing aggressive PNS. This tweak makes PNS much less aggressive, though it can still use some further tweaks. Also update MIPS specializations and adjust fuzz Also in lavc/mips/aacpsy_mips.h: remove trailing whitespace

Claudio Freire committed 10 years ago

Commit ca203e91 parent ec83efd11 files · +393 −177Browse files

Showing the changes to libavcodec/aaccoder.c (1 of 11 files). Show all

Unified · Split

libavcodec/aaccoder.c+41−19
@@ -54,7 +54,7 @@ · 53 unmodified lines
5454
5555 /* Parameter of f(x) = a*(lambda/100), defines the maximum fourier spread
5656 * beyond which no PNS is used (since the SFBs contain tone rather than noise) */
57−#define NOISE_SPREAD_THRESHOLD 0.5073f
57+#define NOISE_SPREAD_THRESHOLD 0.9f
5858
5959 /* Parameter of f(x) = a*(100/lambda), defines how much PNS is allowed to
6060 * replace low energy non zero bands */
@@ -591,6 +591,7 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne · 530 unmodified lines
591591 int bandwidth, cutoff;
592592 float *PNS = &s->scoefs[0*128], *PNS34 = &s->scoefs[1*128];
593593 float *NOR34 = &s->scoefs[3*128];
594+ uint8_t nextband[128];
594595 const float lambda = s->lambda;
595596 const float freq_mult = avctx->sample_rate*0.5f/wlen;
596597 const float thr_mult = NOISE_LAMBDA_REPLACE*(100.0f/lambda);
@@ -604,6 +605,7 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne · 7 unmodified lines
604605
605606 /** Keep this in sync with twoloop's cutoff selection */
606607 float rate_bandwidth_multiplier = 1.5f;
608+ int prev = -1000, prev_sf = -1;
607609 int frame_bit_rate = (avctx->flags & CODEC_FLAG_QSCALE)
608610 ? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
609611 : (avctx->bit_rate / avctx->channels);
@@ -619,6 +621,7 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne · 9 unmodified lines
619621 cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
620622
621623 memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type));
624+ ff_init_nextband_map(sce, nextband);
622625 for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
623626 int wstart = w*128;
624627 for (g = 0; g < sce->ics.num_swb; g++) {
@@ -655,16 +658,27 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne · 30 unmodified lines
655658 *
656659 * At this stage, point 2 is relaxed for zeroed bands near the noise threshold (hole avoidance is more important)
657660 */
658− if (((sce->zeroes[w*16+g] || !sce->band_alt[w*16+g]) && sfb_energy < threshold*sqrtf(1.5f/freq_boost)) || spread < spread_threshold ||
661+ if ((!sce->zeroes[w*16+g] && !ff_sfdelta_can_remove_band(sce, nextband, prev_sf, w*16+g)) ||
662+ ((sce->zeroes[w*16+g] || !sce->band_alt[w*16+g]) && sfb_energy < threshold*sqrtf(1.0f/freq_boost)) || spread < spread_threshold ||
659663 (!sce->zeroes[w*16+g] && sce->band_alt[w*16+g] && sfb_energy > threshold*thr_mult*freq_boost) ||
660664 min_energy < pns_transient_energy_r * max_energy ) {
661665 sce->pns_ener[w*16+g] = sfb_energy;
666+ if (!sce->zeroes[w*16+g])
667+ prev_sf = sce->sf_idx[w*16+g];
662668 continue;
663669 }
664670
665671 pns_tgt_energy = sfb_energy*FFMIN(1.0f, spread*spread);
666672 noise_sfi = av_clip(roundf(log2f(pns_tgt_energy)*2), -100, 155); /* Quantize */
667673 noise_amp = -ff_aac_pow2sf_tab[noise_sfi + POW_SF2_ZERO]; /* Dequantize */
674+ if (prev != -1000) {
675+ int noise_sfdiff = noise_sfi - prev + SCALE_DIFF_ZERO;
676+ if (noise_sfdiff < 0 || noise_sfdiff > 2*SCALE_MAX_DIFF) {
677+ if (!sce->zeroes[w*16+g])
678+ prev_sf = sce->sf_idx[w*16+g];
679+ continue;
680+ }
681+ }
668682 for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
669683 float band_energy, scale, pns_senergy;
670684 const int start_c = (w+w2)*128+sce->ics.swb_offset[g];
@@ -697,7 +711,10 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne · 26 unmodified lines
697711 if (sce->zeroes[w*16+g] || !sce->band_alt[w*16+g] || (energy_ratio > 0.85f && energy_ratio < 1.25f && dist2 < dist1)) {
698712 sce->band_type[w*16+g] = NOISE_BT;
699713 sce->zeroes[w*16+g] = 0;
714+ prev = noise_sfi;
700715 }
716+ if (!sce->zeroes[w*16+g])
717+ prev_sf = sce->sf_idx[w*16+g];
701718 }
702719 }
703720 }
@@ -775,7 +792,8 @@ static void mark_pns(AACEncContext *s, AVCodecContext *avctx, SingleChannelEleme · 71 unmodified lines
775792
776793 static void search_for_ms(AACEncContext *s, ChannelElement *cpe)
777794 {
778− int start = 0, i, w, w2, g, sid_sf_boost;
795+ int start = 0, i, w, w2, g, sid_sf_boost, prev_mid, prev_side;
796+ uint8_t nextband0[128], nextband1[128];
779797 float M[128], S[128];
780798 float *L34 = s->scoefs, *R34 = s->scoefs + 128, *M34 = s->scoefs + 128*2, *S34 = s->scoefs + 128*3;
781799 const float lambda = s->lambda;
@@ -784,21 +802,19 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe) · 2 unmodified lines
784802 SingleChannelElement *sce1 = &cpe->ch[1];
785803 if (!cpe->common_window)
786804 return;
787− for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) {
788− int min_sf_idx_mid = SCALE_MAX_POS;
789− int min_sf_idx_side = SCALE_MAX_POS;
790− for (g = 0; g < sce0->ics.num_swb; g++) {
791− if (!sce0->zeroes[w*16+g] && sce0->band_type[w*16+g] < RESERVED_BT)
792− min_sf_idx_mid = FFMIN(min_sf_idx_mid, sce0->sf_idx[w*16+g]);
793− if (!sce1->zeroes[w*16+g] && sce1->band_type[w*16+g] < RESERVED_BT)
794− min_sf_idx_side = FFMIN(min_sf_idx_side, sce1->sf_idx[w*16+g]);
795− }
796805
806+ /** Scout out next nonzero bands */
807+ ff_init_nextband_map(sce0, nextband0);
808+ ff_init_nextband_map(sce1, nextband1);
809+
810+ prev_mid = sce0->sf_idx[0];
811+ prev_side = sce1->sf_idx[0];
812+ for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) {
797813 start = 0;
798814 for (g = 0; g < sce0->ics.num_swb; g++) {
799815 float bmax = bval2bmax(g * 17.0f / sce0->ics.num_swb) / 0.0045f;
800816 cpe->ms_mask[w*16+g] = 0;
801− if (!cpe->ch[0].zeroes[w*16+g] && !cpe->ch[1].zeroes[w*16+g]) {
817+ if (!sce0->zeroes[w*16+g] && !sce1->zeroes[w*16+g]) {
802818 float Mmax = 0.0f, Smax = 0.0f;
803819
804820 /* Must compute mid/side SF and book for the whole window group */
@@ -825,16 +841,18 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe) · 20 unmodified lines
825841 int midcb, sidcb;
826842
827843 minidx = FFMIN(sce0->sf_idx[w*16+g], sce1->sf_idx[w*16+g]);
828− mididx = av_clip(minidx, min_sf_idx_mid, min_sf_idx_mid + SCALE_MAX_DIFF);
829− sididx = av_clip(minidx - sid_sf_boost * 3, min_sf_idx_side, min_sf_idx_side + SCALE_MAX_DIFF);
830− midcb = find_min_book(Mmax, mididx);
831− sidcb = find_min_book(Smax, sididx);
832−
833− if ((mididx > minidx) || (sididx > minidx)) {
844+ mididx = av_clip(minidx, 0, SCALE_MAX_POS - SCALE_DIV_512);
845+ sididx = av_clip(minidx - sid_sf_boost * 3, 0, SCALE_MAX_POS - SCALE_DIV_512);
846+ if (!cpe->is_mask[w*16+g] && sce0->band_type[w*16+g] != NOISE_BT && sce1->band_type[w*16+g] != NOISE_BT
847+ && ( !ff_sfdelta_can_replace(sce0, nextband0, prev_mid, mididx, w*16+g)
848+ || !ff_sfdelta_can_replace(sce1, nextband1, prev_side, sididx, w*16+g))) {
834849 /* scalefactor range violation, bad stuff, will decrease quality unacceptably */
835850 continue;
836851 }
837852
853+ midcb = find_min_book(Mmax, mididx);
854+ sidcb = find_min_book(Smax, sididx);
855+
838856 /* No CB can be zero */
839857 midcb = FFMAX(1,midcb);
840858 sidcb = FFMAX(1,sidcb);
@@ -900,6 +918,10 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe) · 59 unmodified lines
900918 }
901919 }
902920 }
921+ if (!sce0->zeroes[w*16+g] && sce0->band_type[w*16+g] < RESERVED_BT)
922+ prev_mid = sce0->sf_idx[w*16+g];
923+ if (!sce1->zeroes[w*16+g] && !cpe->is_mask[w*16+g] && sce1->band_type[w*16+g] < RESERVED_BT)
924+ prev_side = sce1->sf_idx[w*16+g];
903925 start += sce0->ics.swb_sizes[g];
904926 }
905927 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t