This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit d02bad0c903baf67891dbe6b87c6577d9a27c79f Author: Ayoub Nabil Boubagrat <[email protected]> AuthorDate: Thu Aug 13 20:23:19 2026 +0200 Commit: James Almer <[email protected]> CommitDate: Fri Aug 14 19:08:29 2026 +0000 swresample/rematrix: accept unused channels custom layouts containing AV_CHAN_UNUSED were rejected by swr_build_matrix2(). accept unused channels in input and output layouts. preserve their physical positions, clear input columns, and leave output rows silent. add fate coverage for both cases. this fixes #24094. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libswresample/rematrix.c | 30 ++++++++++++++- libswresample/swresample.h | 3 ++ libswresample/tests/rematrix.c | 62 ++++++++++++++++++++++++++----- tests/fate/libswresample.mak | 8 ++++ tests/ref/fate/swr-rematrix-unused-input | 2 + tests/ref/fate/swr-rematrix-unused-output | 4 ++ 6 files changed, 98 insertions(+), 11 deletions(-) diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index 67d9b48339..582b2b38e3 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) { 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) + continue; + if (id >= 64) return 0; } else if (ch_layout->order != AV_CHANNEL_ORDER_NATIVE) @@ -156,6 +160,28 @@ 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; + } + } + } + + if (out_ch_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + for (i = 0; i < out_ch_layout->nb_channels; i++) { + if (out_ch_layout->u.map[i].id == AV_CHAN_UNUSED) { + /* the named-channel loop below cannot visit AV_CHAN_UNUSED. + * explicitly clear its row so callers may reuse a matrix. */ + for (j = 0; j < in_ch_layout->nb_channels; j++) + 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; diff --git a/libswresample/swresample.h b/libswresample/swresample.h index 052089acca..b3cdc202e9 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 layouts are ignored: their input columns or + * output rows 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..9b5106cdfb 100644 --- a/libswresample/tests/rematrix.c +++ b/libswresample/tests/rematrix.c @@ -28,13 +28,47 @@ /* 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 void print_matrix_row(const double *matrix, + const AVChannelLayout *in_layout, + int out, const char *out_name) +{ + char in_name[16]; + + printf("[%s] = { ", out_name); + for (int i = 0; i < 64; i++) { + int in = av_channel_layout_index_from_channel(in_layout, i); + if (in < 0) + continue; + av_channel_name(in_name, sizeof(in_name), i); + printf(".%s = %f, ", in_name, matrix[out * MATRIX_STRIDE + in]); + } + for (int in = 0; in < in_layout->nb_channels; in++) { + if (channel_is_unused(in_layout, in)) + printf(".UNSD%d = %f, ", in, + matrix[out * MATRIX_STRIDE + in]); + } + printf("},\n"); +} + static int print_matrix(const AVChannelLayout *in_layout, const AVChannelLayout *out_layout) { double matrix[MATRIX_STRIDE * MATRIX_STRIDE] = { 0 }; - char in_name[16], out_name[16]; + char out_name[16]; int ret; + /* ensure swr_build_matrix2() overwrites unused columns and rows 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) || + channel_is_unused(out_layout, out)) + 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,20 +79,30 @@ 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) || + channel_is_unused(out_layout, out)) && + matrix[out * MATRIX_STRIDE + in] != 0.0) { + fprintf(stderr, "unused matrix position %d:%d is non-zero\n", + out, 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) continue; av_channel_name(out_name, sizeof(out_name), i); - printf("[%s] = { ", out_name); - for (int j = 0; j < 64; j++) { - int in_i = av_channel_layout_index_from_channel(in_layout, j); - if (in_i < 0) - continue; - av_channel_name(in_name, sizeof(in_name), j); - printf(".%s = %f, ", in_name, matrix[out_i * MATRIX_STRIDE + in_i]); + print_matrix_row(matrix, in_layout, out_i, out_name); + } + for (int out = 0; out < out_layout->nb_channels; out++) { + if (channel_is_unused(out_layout, out)) { + snprintf(out_name, sizeof(out_name), "UNSD%d", out); + print_matrix_row(matrix, in_layout, out, out_name); } - printf("},\n"); } return 0; diff --git a/tests/fate/libswresample.mak b/tests/fate/libswresample.mak index 7959aa87cd..d23525edbc 100644 --- a/tests/fate/libswresample.mak +++ b/tests/fate/libswresample.mak @@ -1138,6 +1138,14 @@ $(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-input +fate-swr-rematrix-unused-input: libswresample/tests/rematrix$(EXESUF) +fate-swr-rematrix-unused-input: CMD = run libswresample/tests/rematrix$(EXESUF) FL+FR+UNSD+UNSD stereo + +FATE_SWR_REMATRIX-$(CONFIG_SWRESAMPLE) += fate-swr-rematrix-unused-output +fate-swr-rematrix-unused-output: libswresample/tests/rematrix$(EXESUF) +fate-swr-rematrix-unused-output: CMD = run libswresample/tests/rematrix$(EXESUF) 5.1 FL+UNSD+FR+UNSD + FATE_SWR += $(FATE_SWR_REMATRIX-yes) fate-swr-rematrix: $(FATE_SWR_REMATRIX-yes) diff --git a/tests/ref/fate/swr-rematrix-unused-input b/tests/ref/fate/swr-rematrix-unused-input new file mode 100644 index 0000000000..605caf3b70 --- /dev/null +++ b/tests/ref/fate/swr-rematrix-unused-input @@ -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, }, diff --git a/tests/ref/fate/swr-rematrix-unused-output b/tests/ref/fate/swr-rematrix-unused-output new file mode 100644 index 0000000000..ab327fdd5f --- /dev/null +++ b/tests/ref/fate/swr-rematrix-unused-output @@ -0,0 +1,4 @@ +[FL] = { .FL = 1.000000, .FR = 0.000000, .FC = 0.707107, .LFE = 0.000000, .BL = 0.707107, .BR = 0.000000, }, +[FR] = { .FL = 0.000000, .FR = 1.000000, .FC = 0.707107, .LFE = 0.000000, .BL = 0.000000, .BR = 0.707107, }, +[UNSD1] = { .FL = 0.000000, .FR = 0.000000, .FC = 0.000000, .LFE = 0.000000, .BL = 0.000000, .BR = 0.000000, }, +[UNSD3] = { .FL = 0.000000, .FR = 0.000000, .FC = 0.000000, .LFE = 0.000000, .BL = 0.000000, .BR = 0.000000, }, _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
