PR #24907 opened by Forgejo_Fairy URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24907 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24907.patch
LLM-GPT-6-ASTRA investigation: a 997 Hz tone placed only in BL or BR of 7.1, or BC of 6.1, measures −19.520 LUFS instead of the mono reference's −21.010 LUFS because the filter unconditionally gives these channels weight 1.41. Implement the layout distinction described by jlivingston in #24284: when both side channels are present, assign the rear pair weight 1.00; otherwise preserve the 1.41 surround weighting used by 5.x(back). Give BC weight 1.00 unconditionally. This follows Tables 4 and 5 of Recommendation ITU-R BS.1770-5. Use `av_channel_layout_subset()` to inspect channel presence independently of channel order. Add seven synthetic FATE tests covering BL/BR in 7.1, BC in 6.1, SL/SR in 7.1, and BL/BR in 5.1. Expected output is stored in `tests/ref/fate`; no new external samples are required. Validation: - On parent 404c2e47cf9a, the three affected-channel tests fail and the four controls pass. - All seven new tests and both existing ebur128 metadata tests pass with the fix on aarch64 and x86-64. - A 121-case single-channel sweep across 13 layouts confirms the intended rear/back-center changes and unchanged controls, including height and LFE channels. Fixes #24284. From 294ddbc4757605aa84f78c46c381070b1fb302e0 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Mon, 5 Oct 2026 23:27:33 +0000 Subject: [PATCH] avfilter/ebur128: correct back-channel loudness weights ITU-R BS.1770-5 Tables 4 and 5 assign weight 1.0 to the M+/-135 rear pair and M180 back center. The fixed channel-name mask gave all back channels weight 1.41. Use the presence of both side channels to distinguish the rear pair from the +/-110-degree surround pair used by 5.x(back). Keep the latter at 1.41, and remove back center from the boosted channels. Use av_channel_layout_subset() so the lookup also handles custom channel orders. Implement the layout distinction described by jlivingston in #24284. Add seven synthetic FATE tests covering both rear channels, back center, both side channels, and both 5.1 surround channels. The three affected-channel tests fail before the change. All seven new tests and the two existing ebur128 metadata tests pass on aarch64 and x86-64 after it. No external samples are needed for the new tests. Fixes #24284. Assisted-by: Fairy --- libavfilter/f_ebur128.c | 15 ++++++----- tests/fate/filter-video.mak | 25 +++++++++++++++++-- .../fate/filter-metadata-ebur128-back-center | 4 +++ .../fate/filter-metadata-ebur128-rear-left | 4 +++ .../fate/filter-metadata-ebur128-rear-right | 4 +++ .../fate/filter-metadata-ebur128-side-left | 4 +++ .../fate/filter-metadata-ebur128-side-right | 4 +++ .../filter-metadata-ebur128-surround-left | 4 +++ .../filter-metadata-ebur128-surround-right | 4 +++ 9 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 tests/ref/fate/filter-metadata-ebur128-back-center create mode 100644 tests/ref/fate/filter-metadata-ebur128-rear-left create mode 100644 tests/ref/fate/filter-metadata-ebur128-rear-right create mode 100644 tests/ref/fate/filter-metadata-ebur128-side-left create mode 100644 tests/ref/fate/filter-metadata-ebur128-side-right create mode 100644 tests/ref/fate/filter-metadata-ebur128-surround-left create mode 100644 tests/ref/fate/filter-metadata-ebur128-surround-right diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c index f2744fb8e6..574e865c76 100644 --- a/libavfilter/f_ebur128.c +++ b/libavfilter/f_ebur128.c @@ -432,12 +432,15 @@ static int config_audio_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; EBUR128Context *ebur128 = ctx->priv; const int nb_channels = outlink->ch_layout.nb_channels; + const uint64_t side_mask = AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT; + uint64_t weight_1_41_mask = side_mask | AV_CH_SURROUND_DIRECT_LEFT | + AV_CH_SURROUND_DIRECT_RIGHT; - /* Height channels always use a weight of 1.0 in ITU-R BS.1770. */ -#define WEIGHT_1_41_MASK (AV_CH_BACK_LEFT |AV_CH_BACK_CENTER | \ - AV_CH_BACK_RIGHT |AV_CH_SIDE_LEFT | \ - AV_CH_SIDE_RIGHT |AV_CH_SURROUND_DIRECT_LEFT | \ - AV_CH_SURROUND_DIRECT_RIGHT) + /* With a side pair, the back pair is at +/-135 degrees (weight 1.0). + * Otherwise retain the +/-110-degree surround weighting of 5.x(back). + * Back center and height channels use 1.0 in ITU-R BS.1770. */ + if (av_channel_layout_subset(&outlink->ch_layout, side_mask) != side_mask) + weight_1_41_mask |= AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT; ebur128->nb_channels = nb_channels; ebur128->dsp.y = av_calloc(nb_channels, 3 * sizeof(*ebur128->dsp.y)); @@ -471,7 +474,7 @@ static int config_audio_output(AVFilterLink *outlink) const enum AVChannel chl = av_channel_layout_channel_from_index(&outlink->ch_layout, i); if (chl == AV_CHAN_LOW_FREQUENCY || chl == AV_CHAN_LOW_FREQUENCY_2) { ebur128->ch_weighting[i] = 0; - } else if (chl < 64 && (1ULL << chl) & WEIGHT_1_41_MASK) { + } else if (chl < 64 && (1ULL << chl) & weight_1_41_mask) { ebur128->ch_weighting[i] = 1.41; } else { ebur128->ch_weighting[i] = 1.0; diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak index ebbc0a7d1c..961a11875c 100644 --- a/tests/fate/filter-video.mak +++ b/tests/fate/filter-video.mak @@ -923,10 +923,31 @@ FATE_METADATA_FILTER-$(call ALLYES, $(EBUR128_METADATA_DEPS)) += fate-filter-met fate-filter-metadata-ebur128: SRC = $(TARGET_SAMPLES)/filter/seq-3341-7_seq-3342-5-24bit.flac fate-filter-metadata-ebur128: CMD = run $(FILTER_METADATA_COMMAND) "amovie='$(SRC)',ebur128=peak=sample:metadata=1" -EBUR128_HEIGHT_DEPS = FFPROBE LAVFI_INDEV AEVALSRC_FILTER ARESAMPLE_FILTER EBUR128_FILTER -FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_HEIGHT_DEPS)) += fate-filter-metadata-ebur128-height +EBUR128_CHANNEL_DEPS = FFPROBE LAVFI_INDEV AEVALSRC_FILTER ARESAMPLE_FILTER EBUR128_FILTER +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-height fate-filter-metadata-ebur128-height: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0.12589*sin(2*PI*997*t):channel_layout=TBL:sample_rate=48000:duration=0.4,ebur128=metadata=1" +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-rear-left +fate-filter-metadata-ebur128-rear-left: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0.12589*sin(2*PI*997*t)|0|0|0:channel_layout=7.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-rear-right +fate-filter-metadata-ebur128-rear-right: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0|0.12589*sin(2*PI*997*t)|0|0:channel_layout=7.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-back-center +fate-filter-metadata-ebur128-back-center: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0.12589*sin(2*PI*997*t)|0|0:channel_layout=6.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-side-left +fate-filter-metadata-ebur128-side-left: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0|0|0.12589*sin(2*PI*997*t)|0:channel_layout=7.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-side-right +fate-filter-metadata-ebur128-side-right: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0|0|0|0.12589*sin(2*PI*997*t):channel_layout=7.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-surround-left +fate-filter-metadata-ebur128-surround-left: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0.12589*sin(2*PI*997*t)|0:channel_layout=5.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + +FATE_FILTER_FFPROBE-$(call ALLYES, $(EBUR128_CHANNEL_DEPS)) += fate-filter-metadata-ebur128-surround-right +fate-filter-metadata-ebur128-surround-right: CMD = run $(FILTER_METADATA_COMMAND) "aevalsrc=0|0|0|0|0|0.12589*sin(2*PI*997*t):channel_layout=5.1:sample_rate=48000:duration=0.4,ebur128=metadata=1" + READVITC_METADATA_DEPS = LAVFI_INDEV MOVIE_FILTER \ AVI_DEMUXER FFVHUFF_DECODER READVITC_FILTER FATE_METADATA_FILTER-$(call ALLYES, $(READVITC_METADATA_DEPS)) += fate-filter-metadata-readvitc-def diff --git a/tests/ref/fate/filter-metadata-ebur128-back-center b/tests/ref/fate/filter-metadata-ebur128-back-center new file mode 100644 index 0000000000..f182793368 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-back-center @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-21.010|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.010|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 diff --git a/tests/ref/fate/filter-metadata-ebur128-rear-left b/tests/ref/fate/filter-metadata-ebur128-rear-left new file mode 100644 index 0000000000..f182793368 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-rear-left @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-21.010|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.010|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 diff --git a/tests/ref/fate/filter-metadata-ebur128-rear-right b/tests/ref/fate/filter-metadata-ebur128-rear-right new file mode 100644 index 0000000000..f182793368 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-rear-right @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-21.010|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.010|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 diff --git a/tests/ref/fate/filter-metadata-ebur128-side-left b/tests/ref/fate/filter-metadata-ebur128-side-left new file mode 100644 index 0000000000..35914bc544 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-side-left @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-19.517|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-19.520|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 diff --git a/tests/ref/fate/filter-metadata-ebur128-side-right b/tests/ref/fate/filter-metadata-ebur128-side-right new file mode 100644 index 0000000000..35914bc544 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-side-right @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-19.517|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-19.520|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 diff --git a/tests/ref/fate/filter-metadata-ebur128-surround-left b/tests/ref/fate/filter-metadata-ebur128-surround-left new file mode 100644 index 0000000000..35914bc544 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-surround-left @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-19.517|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-19.520|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 diff --git a/tests/ref/fate/filter-metadata-ebur128-surround-right b/tests/ref/fate/filter-metadata-ebur128-surround-right new file mode 100644 index 0000000000..35914bc544 --- /dev/null +++ b/tests/ref/fate/filter-metadata-ebur128-surround-right @@ -0,0 +1,4 @@ +pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 +pts=14400|tag:lavfi.r128.M=-19.517|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-19.520|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
