PR #24133 opened by AYOUB NABIL BOUBAGRAT (ayoubnabil) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24133 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24133.patch
custom input layouts containing AV_CHAN_UNUSED were rejected by swr_build_matrix2(), so streams with unused input positions could not be rematrixed. allow AV_CHAN_UNUSED in custom input layouts, preserve its physical matrix position, and clear the corresponding matrix column. output layouts still reject unused channels. add a fate test for a FL+FR+UNSD+UNSD to stereo matrix. this fixes #24094 >From 15eafdf713823fe652c3facca2db4a0f3f702353 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Thu, 13 Aug 2026 20:23:07 +0200 Subject: [PATCH 1/2] libswresample/tests/rematrix: uninit channel layouts release parsed channel layouts before exiting. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libswresample/tests/rematrix.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libswresample/tests/rematrix.c b/libswresample/tests/rematrix.c index eaa78784c6..464da7638b 100644 --- a/libswresample/tests/rematrix.c +++ b/libswresample/tests/rematrix.c @@ -82,23 +82,30 @@ int main(int argc, char **argv) if (ret < 0) { if (ret == AVERROR(EINVAL)) fprintf(stderr, "Invalid input layout %s\n", in); - return 1; + ret = 1; + goto end; } ret = av_channel_layout_from_string(&out_layout, out); if (ret < 0) { if (ret == AVERROR(EINVAL)) fprintf(stderr, "Invalid output layout %s\n", out); - return 1; + ret = 1; + goto end; } if (in_layout.nb_channels > MATRIX_STRIDE || out_layout.nb_channels > MATRIX_STRIDE) { fprintf(stderr, "channel layout exceeds matrix capacity\n"); - return 1; + ret = 1; + goto end; } ret = print_matrix(&in_layout, &out_layout); +end: + av_channel_layout_uninit(&in_layout); + av_channel_layout_uninit(&out_layout); + return ret; } -- 2.52.0 >From a5261e4a1a7fb45a7e9f0b73126faf8fc651372a Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Thu, 13 Aug 2026 20:23:19 +0200 Subject: [PATCH 2/2] swresample/rematrix: accept unused input channels ignore AV_CHAN_UNUSED input channels while preserving their physical matrix positions. add a fate test covering #24094. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libswresample/rematrix.c | 23 +++++++++++++++++++---- libswresample/swresample.h | 3 +++ libswresample/tests/rematrix.c | 26 ++++++++++++++++++++++++++ tests/fate/libswresample.mak | 4 ++++ tests/ref/fate/swr-rematrix-unused | 2 ++ 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/ref/fate/swr-rematrix-unused diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index 67d9b48339..e3f91aede2 100644 --- a/libswresample/rematrix.c +++ b/libswresample/rematrix.c @@ -111,12 +111,16 @@ static int clean_layout(AVChannelLayout *out, const AVChannelLayout *in, void *s return ret; } -static int sane_layout(AVChannelLayout *ch_layout) { +static int sane_layout(const AVChannelLayout *ch_layout, int allow_unused) { if(ch_layout->nb_channels >= SWR_CH_MAX) return 0; if(ch_layout->order == AV_CHANNEL_ORDER_CUSTOM) for (int i = 0; i < ch_layout->nb_channels; i++) { - if (ch_layout->u.map[i].id >= 64) + enum AVChannel id = ch_layout->u.map[i].id; + + if (id == AV_CHAN_UNUSED && allow_unused) + continue; + if (id >= 64) return 0; } else if (ch_layout->order != AV_CHANNEL_ORDER_NATIVE) @@ -156,6 +160,17 @@ static void build_matrix(const AVChannelLayout *in_ch_layout, const AVChannelLay double maxcoef=0; int i, j; + if (in_ch_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + for (j = 0; j < in_ch_layout->nb_channels; j++) { + if (in_ch_layout->u.map[j].id == AV_CHAN_UNUSED) { + /* the named-channel loop below cannot visit AV_CHAN_UNUSED. + * explicitly clear its column so callers may reuse a matrix. */ + for (i = 0; i < out_ch_layout->nb_channels; i++) + matrix_param[stride * i + j] = 0.0; + } + } + } + for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){ if (in_mask & out_mask & (1ULL << i)) matrix[i][i]= 1.0; @@ -576,7 +591,7 @@ av_cold int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelL ret = AVERROR(EINVAL); goto fail; } - if(!sane_layout(&in_ch_layout)) { + if(!sane_layout(&in_ch_layout, 1)) { av_channel_layout_describe(&in_ch_layout, buf, sizeof(buf)); av_log(log_context, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf); ret = AVERROR(EINVAL); @@ -588,7 +603,7 @@ av_cold int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelL ret = AVERROR(EINVAL); goto fail; } - if(!sane_layout(&out_ch_layout)) { + if(!sane_layout(&out_ch_layout, 0)) { av_channel_layout_describe(&out_ch_layout, buf, sizeof(buf)); av_log(log_context, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf); ret = AVERROR(EINVAL); diff --git a/libswresample/swresample.h b/libswresample/swresample.h index 052089acca..9b70719b48 100644 --- a/libswresample/swresample.h +++ b/libswresample/swresample.h @@ -377,6 +377,9 @@ int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map); * default mixing matrix. It is made public just as a utility function for * building custom matrices. * + * AV_CHAN_UNUSED entries in custom input layouts are ignored and their matrix + * columns are set to zero. + * * @param in_layout input channel layout * @param out_layout output channel layout * @param center_mix_level mix level for the center channel diff --git a/libswresample/tests/rematrix.c b/libswresample/tests/rematrix.c index 464da7638b..c8d3f285d4 100644 --- a/libswresample/tests/rematrix.c +++ b/libswresample/tests/rematrix.c @@ -28,6 +28,11 @@ /* swr_build_matrix2() accesses an internal SWR_CH_MAX by SWR_CH_MAX matrix. */ #define MATRIX_STRIDE 64 +static int channel_is_unused(const AVChannelLayout *layout, int index) +{ + return av_channel_layout_channel_from_index(layout, index) == AV_CHAN_UNUSED; +} + static int print_matrix(const AVChannelLayout *in_layout, const AVChannelLayout *out_layout) { @@ -35,6 +40,12 @@ static int print_matrix(const AVChannelLayout *in_layout, char in_name[16], out_name[16]; int ret; + /* ensure swr_build_matrix2() overwrites unused input columns with zero. */ + for (int out = 0; out < out_layout->nb_channels; out++) + for (int in = 0; in < in_layout->nb_channels; in++) + if (channel_is_unused(in_layout, in)) + matrix[out * MATRIX_STRIDE + in] = 1.0; + /* Disable normalization so the raw downmix gains can be checked. */ ret = swr_build_matrix2(in_layout, out_layout, M_SQRT1_2, M_SQRT1_2, @@ -45,6 +56,16 @@ static int print_matrix(const AVChannelLayout *in_layout, return 1; } + for (int out = 0; out < out_layout->nb_channels; out++) { + for (int in = 0; in < in_layout->nb_channels; in++) { + if (channel_is_unused(in_layout, in) && + matrix[out * MATRIX_STRIDE + in] != 0.0) { + fprintf(stderr, "unused input %d has a non-zero coefficient\n", in); + return 1; + } + } + } + for (int i = 0; i < 64; i++) { int out_i = av_channel_layout_index_from_channel(out_layout, i); if (out_i < 0) @@ -58,6 +79,11 @@ static int print_matrix(const AVChannelLayout *in_layout, av_channel_name(in_name, sizeof(in_name), j); printf(".%s = %f, ", in_name, matrix[out_i * MATRIX_STRIDE + in_i]); } + for (int in_i = 0; in_i < in_layout->nb_channels; in_i++) { + if (channel_is_unused(in_layout, in_i)) + printf(".UNSD%d = %f, ", in_i, + matrix[out_i * MATRIX_STRIDE + in_i]); + } printf("},\n"); } diff --git a/tests/fate/libswresample.mak b/tests/fate/libswresample.mak index 7959aa87cd..315c05b5be 100644 --- a/tests/fate/libswresample.mak +++ b/tests/fate/libswresample.mak @@ -1138,6 +1138,10 @@ $(call SWR_REMATRIX_TEST,$(FATE_SWR_7_1_LAYOUTS),7.1) $(call SWR_REMATRIX_TEST,$(FATE_SWR_5_1_LAYOUTS),5.1) $(call SWR_REMATRIX_TEST,$(FATE_SWR_STEREO_LAYOUTS),stereo) +FATE_SWR_REMATRIX-$(CONFIG_SWRESAMPLE) += fate-swr-rematrix-unused +fate-swr-rematrix-unused: libswresample/tests/rematrix$(EXESUF) +fate-swr-rematrix-unused: CMD = run libswresample/tests/rematrix$(EXESUF) FL+FR+UNSD+UNSD stereo + FATE_SWR += $(FATE_SWR_REMATRIX-yes) fate-swr-rematrix: $(FATE_SWR_REMATRIX-yes) diff --git a/tests/ref/fate/swr-rematrix-unused b/tests/ref/fate/swr-rematrix-unused new file mode 100644 index 0000000000..605caf3b70 --- /dev/null +++ b/tests/ref/fate/swr-rematrix-unused @@ -0,0 +1,2 @@ +[FL] = { .FL = 1.000000, .FR = 0.000000, .UNSD2 = 0.000000, .UNSD3 = 0.000000, }, +[FR] = { .FL = 0.000000, .FR = 1.000000, .UNSD2 = 0.000000, .UNSD3 = 0.000000, }, -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
