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];
             }
         }