mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-28 10:04:37 +08:00
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.
This commit is contained in:
1 parent
77506207d2
commit
03ce7af84b
6 files changed
+39
-13
No files matched your search
+29
-3
@@ -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
|
||||
|
||||
@@ -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]
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
Reference in new issue
Block a user