Commit 2083d60533 for ffmpeg
commit 2083d60533a96e40c4ae0f20b592e323bb9222e2
Author: Lynne <dev@lynne.ee>
Date: Sun Nov 8 02:19:58 2026 +0800
avcodec/aacpsy: keep bands below the threshold in quiet uncoded
Two steps of the 3GPP model could leave a band's threshold below its
energy although the band sat below its threshold in quiet, so a band
holding nothing but float noise became codeable:
- the signal-relative mask ceiling capped every threshold a fixed depth
under the band's own energy, with no floor;
- the 5.6.1.3.7 further PE reduction set the threshold 1 dB under the
energy outright, which lowers it on a band that was masked.
Such a band (energy around 1e-15) can only be coded at a scalefactor
near 0. Next to an onset band whose finest legal scalefactor is 85-96 it
left the NMR trellis without any scalefactor chain within
SCALE_MAX_DIFF; the frame came out over the decoder buffer at every
lambda and the encoder re-encoded it forever. Twoloop hung the same way.
Floor the ceiling at the threshold in quiet, and only ever raise a
threshold in the PE reduction. The floor moves most streams by a few
hundredths of a percent in size. On the stereo bench corpus NMR
Zimtohrli improves 0.9% at 128k and 1.7% at 64k with ViSQOL unchanged,
and ABR quality and rate accuracy stay flat. The PE reduction change
only ever fires at the head of a stream.
Fixes: #25580
Reported-by: haasn
Reported-by: EthanSK
Co-authored-by: Robert Nagy <ronagy@icloud.com>
diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c
index e730e621b9..5e87e67595 100644
--- a/libavcodec/aacpsy.c
+++ b/libavcodec/aacpsy.c
@@ -937,7 +937,9 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
AacPsyBand *band = &pch->band[w+g];
if (band->avoid_holes != PSY_3GPP_AH_NONE && coeffs[g].min_snr < PSY_SNR_1DB) {
coeffs[g].min_snr = PSY_SNR_1DB;
- band->thr = band->energy * PSY_SNR_1DB;
+ /* a reduction step: never lower a threshold, or a
+ * band below its threshold in quiet becomes codeable */
+ band->thr = FFMAX(band->thr, band->energy * PSY_SNR_1DB);
pe += band->active_lines * 1.5f - band->pe;
}
}
@@ -965,8 +967,11 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
int start = 0;
for (g = 0; g < num_bands; g++) {
AacPsyBand *band = &pch->band[w+g];
+ /* never below the threshold in quiet: an inaudible band
+ * must stay uncoded */
if (start * l2f >= knee)
- band->thr = FFMIN(band->thr, band->energy * lo);
+ band->thr = FFMIN(band->thr, FFMAX(coeffs[g].ath,
+ band->energy * lo));
start += band_sizes[g];
}
}