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]

Reply via email to