This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 03ce7af84be7926d5c12112bec6a8c705e6c2ad9 Author: Lynne <[email protected]> AuthorDate: Wed Sep 23 20:29:41 2026 +0900 Commit: Lynne <[email protected]> CommitDate: Sun Oct 4 17:51:01 2026 +0900 avcodec/aacenc: M/S balance gate, perceptual intensity stereo M/S balance gate. M/S has no coding gain on a hard-panned band (|S| ~ |M|) and its quantization noise decorrelates across the unfold, smearing the panned source into the far channel; require channel balance within ~6dB for M/S candidacy. Perceptual intensity stereo, on by default. Zimtohrli penalizes I/S reconstruction even when the image error sits below the masks, so the metric cannot govern it; ears above ~8kHz do not hear interaural fine structure, and they can. Engage I/S on perceptual criteria alone: above 8kHz, inter-channel correlation over 0.85 (sticky), long windows only, with the image-error budget opened for qualifying bands regardless of rate pressure. The gates select content like a scalpel - Angels 9.3% of bands, Enola 6.7%, trumpet 3.0% - and exactly 0% on decorrelated-HF material (velvet, Berling) where I/S would damage the image. Corpus cost is metric noise (+0.6% Zim at 128k, +1.4% at 64k - Zimtohrli penalizes I/S reconstruction the ear does not hear); freed bits improve the sub-8kHz spectrum 10% on engagement-heavy content. -aac_is 0 disables I/S altogether. Measured and not included: lifting the both-channels-noise-like requirement for stereo PNS (engagement moves less than 0.2% even at 15-18% band usage, corpus flat, and noise in one ear against coded texture in the other is an imaging risk), and M/S threshold, BMLD side reduction, M/S equivalence and I/S floor/surgical-candidacy sweeps. The id3v2 re-encode refs follow the default NMR output; the fast-coder encode tests are unaffected. --- libavcodec/aacenc.c | 32 ++++++++++++++++++++-- tests/ref/fate/id3v2-reenc-delete-metadata | 4 +-- tests/ref/fate/id3v2-reenc-delete-metadata-keep | 4 +-- .../fate/id3v2-reenc-delete-metadata-keep-format | 4 +-- .../fate/id3v2-reenc-delete-metadata-keep-stream | 4 +-- .../fate/id3v2-reenc-delete-metadata-map-metadata | 4 +-- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index efd3b4aba9..9398467bc7 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -753,6 +753,15 @@ static void apply_intensity_stereo(ChannelElement *cpe) /* PNS-stereo gate: substitute only clearly-decorrelated (wide) bands. */ #define NMR_PNS_STEREO_DECORR 0.6f +/* M/S balance gate: no M/S on bands panned harder than this energy ratio */ +#define NMR_MS_BALANCE 0.25f + +/* Perceptual I/S: highly correlated long-window bands above this frequency + * take I/S at this image-error budget regardless of rate pressure */ +#define NMR_IS_PERC_FREQ 8000.0f +#define NMR_IS_PERC_CORR 0.85f +#define NMR_IS_PERC_GATE 50.0f + /* Recode one band's window group as mid+side in place. */ static void nmr_apply_ms_band(AACEncContext *s, ChannelElement *cpe, int w, int g, int start, int len, int gl) @@ -872,7 +881,8 @@ static void nmr_decide_stereo(AACEncContext *s, ChannelElement *cpe) * not admit it). Unengaged candidates fall back to M/S. */ float is_ramp = s->nmr ? s->nmr->press * av_clipf((s->nmr->lam_floor - 40.0f) / (120.0f - 40.0f), 0.0f, 1.0f) : 0.0f; - const int allow_is = s->options.intensity_stereo && is_ramp > 0.0f; + /* perceptual I/S (below) makes candidacy pressure-independent */ + const int allow_is = s->options.intensity_stereo; const int pidx = (s->cur_channel >> 1) & 15; const int decoupled = s->psy.pair_decoupled[pidx]; @@ -931,6 +941,18 @@ static void nmr_decide_stereo(AACEncContext *s, ChannelElement *cpe) float eqgate = NMR_MS_EQUIV * (prev == 1 ? 1.5f : 1.0f); /* stay-until es>0.75em */ /* I/S = lossy economy: image-error budget scales with pressure */ float imgate = NMR_IS_IMG_GATE * is_ramp * (prev == 2 ? NMR_STICKY : 1.0f); + /* Perceptual I/S (metric-blind by design - Zimtohrli penalizes + * even sub-mask image error, ears above ~8k do not hear + * interaural fine structure): engage on genuinely intensity- + * panned HF - high inter-channel correlation, long windows, + * sticky - regardless of rate pressure. Freed bits are judged + * by the sub-8k spectrum; the image itself is judged by ears. */ + if (cpe->ch[0].ics.num_windows != 8 && ener0 > FLT_MIN && ener1 > FLT_MIN) { + float corr = dot / sqrtf(ener0 * ener1); + if (start * freq_mult > NMR_IS_PERC_FREQ && + fabsf(corr) > NMR_IS_PERC_CORR * (prev == 2 ? 0.9f : 1.0f)) + imgate = FFMAX(imgate, NMR_IS_PERC_GATE * (prev == 2 ? NMR_STICKY : 1.0f)); + } float es_d = es_tot, em_d = em_tot; if (s->nmr) { float *ees = &s->nmr->sema_es[pi][sidx]; @@ -942,10 +964,14 @@ static void nmr_decide_stereo(AACEncContext *s, ChannelElement *cpe) } es_d = *ees; em_d = *eem; } + /* Balance gate: M/S has no coding gain on a hard-panned band + * (|S| ~ |M|), and M/S quantization noise decorrelates across + * the unfold, smearing the panned source into the far channel. */ + int bal_ok = FFMIN(ener0, ener1) > NMR_MS_BALANCE * FFMAX(ener0, ener1); int ms_would = s->options.mid_side && (s->options.mid_side == 1 || - es_d < eqgate * em_d || - es_tot < NMR_MS_MASK * thr_g); + ((es_d < eqgate * em_d || + es_tot < NMR_MS_MASK * thr_g) && bal_ok)); int ms_ok = ms_would && !decoupled; float scale, sr_, imgratio; int p; /* I/S competes with M/S above the frequency limit (candidacy must diff --git a/tests/ref/fate/id3v2-reenc-delete-metadata b/tests/ref/fate/id3v2-reenc-delete-metadata index 866aea13ad..5da30d724d 100644 --- a/tests/ref/fate/id3v2-reenc-delete-metadata +++ b/tests/ref/fate/id3v2-reenc-delete-metadata @@ -1,5 +1,5 @@ -d551ef153999cb3c8a304768dbce9b80 *tests/data/fate/id3v2-reenc-delete-metadata.nut -2699 tests/data/fate/id3v2-reenc-delete-metadata.nut +b8a8450e6cca1ac5097a41f081584618 *tests/data/fate/id3v2-reenc-delete-metadata.nut +2716 tests/data/fate/id3v2-reenc-delete-metadata.nut [FORMAT] TAG:title=7rk [/FORMAT] diff --git a/tests/ref/fate/id3v2-reenc-delete-metadata-keep b/tests/ref/fate/id3v2-reenc-delete-metadata-keep index 4c031cad82..a2edc8e1ff 100644 --- a/tests/ref/fate/id3v2-reenc-delete-metadata-keep +++ b/tests/ref/fate/id3v2-reenc-delete-metadata-keep @@ -1,5 +1,5 @@ -8000a5d46a648126fc1c2d1b6240b44d *tests/data/fate/id3v2-reenc-delete-metadata-keep.nut -2839 tests/data/fate/id3v2-reenc-delete-metadata-keep.nut +dc08127e67c9284a11dde0cefd31177e *tests/data/fate/id3v2-reenc-delete-metadata-keep.nut +2856 tests/data/fate/id3v2-reenc-delete-metadata-keep.nut [FORMAT] TAG:title=7rk TAG:comment-iTunSMPB-eng= 00000000 00000210 0000086A 0000000000066486 00000000 0002DA9D 00000000 00000000 00000000 00000000 00000000 00000000 diff --git a/tests/ref/fate/id3v2-reenc-delete-metadata-keep-format b/tests/ref/fate/id3v2-reenc-delete-metadata-keep-format index 40410ca2b6..1b0e6ec891 100644 --- a/tests/ref/fate/id3v2-reenc-delete-metadata-keep-format +++ b/tests/ref/fate/id3v2-reenc-delete-metadata-keep-format @@ -1,5 +1,5 @@ -8000a5d46a648126fc1c2d1b6240b44d *tests/data/fate/id3v2-reenc-delete-metadata-keep-format.nut -2839 tests/data/fate/id3v2-reenc-delete-metadata-keep-format.nut +dc08127e67c9284a11dde0cefd31177e *tests/data/fate/id3v2-reenc-delete-metadata-keep-format.nut +2856 tests/data/fate/id3v2-reenc-delete-metadata-keep-format.nut [FORMAT] TAG:title=7rk TAG:comment-iTunSMPB-eng= 00000000 00000210 0000086A 0000000000066486 00000000 0002DA9D 00000000 00000000 00000000 00000000 00000000 00000000 diff --git a/tests/ref/fate/id3v2-reenc-delete-metadata-keep-stream b/tests/ref/fate/id3v2-reenc-delete-metadata-keep-stream index 29b487cf79..d9988c16b7 100644 --- a/tests/ref/fate/id3v2-reenc-delete-metadata-keep-stream +++ b/tests/ref/fate/id3v2-reenc-delete-metadata-keep-stream @@ -1,5 +1,5 @@ -d551ef153999cb3c8a304768dbce9b80 *tests/data/fate/id3v2-reenc-delete-metadata-keep-stream.nut -2699 tests/data/fate/id3v2-reenc-delete-metadata-keep-stream.nut +b8a8450e6cca1ac5097a41f081584618 *tests/data/fate/id3v2-reenc-delete-metadata-keep-stream.nut +2716 tests/data/fate/id3v2-reenc-delete-metadata-keep-stream.nut [FORMAT] TAG:title=7rk [/FORMAT] diff --git a/tests/ref/fate/id3v2-reenc-delete-metadata-map-metadata b/tests/ref/fate/id3v2-reenc-delete-metadata-map-metadata index 5658e4d250..2baca102ed 100644 --- a/tests/ref/fate/id3v2-reenc-delete-metadata-map-metadata +++ b/tests/ref/fate/id3v2-reenc-delete-metadata-map-metadata @@ -1,5 +1,5 @@ -d551ef153999cb3c8a304768dbce9b80 *tests/data/fate/id3v2-reenc-delete-metadata-map-metadata.nut -2699 tests/data/fate/id3v2-reenc-delete-metadata-map-metadata.nut +b8a8450e6cca1ac5097a41f081584618 *tests/data/fate/id3v2-reenc-delete-metadata-map-metadata.nut +2716 tests/data/fate/id3v2-reenc-delete-metadata-map-metadata.nut [FORMAT] TAG:title=7rk [/FORMAT] -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
