Commit 70e948e2e5 for ffmpeg

commit 70e948e2e502c310e5854b961303b8babb2ae065
Author: Kacper Michajłow <kasper93@gmail.com>
Date:   Sun Sep 27 16:03:32 2026 +0200

    swresample/rematrix: recognize the stereo downmix pair in custom layouts

    The pair is mixed like stereo if the other side has no such channels.
    It was only recognized as the native layout, so a custom layout with
    the pair in another order or next to unused channels was rejected for
    the lack of a front channel.

    Signed-off-by: Kacper Michajłow <kasper93@gmail.com>

diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c
index fa976b7f7c..7a0ea88682 100644
--- a/libswresample/rematrix.c
+++ b/libswresample/rematrix.c
@@ -132,6 +132,28 @@ static int clean_layout(AVChannelLayout *out, const AVChannelLayout *in, void *s
     return 0;
 }

+/**
+ * Stereo downmix channels are mixed like stereo, unless the other layout has
+ * such channels as well. The channels keep their places.
+ */
+static void clean_downmix(AVChannelLayout *ch_layout, const AVChannelLayout *other)
+{
+    if (av_channel_layout_subset(ch_layout, ~(uint64_t)0) != AV_CH_LAYOUT_STEREO_DOWNMIX ||
+        av_channel_layout_subset(other, AV_CH_LAYOUT_STEREO_DOWNMIX))
+        return;
+
+    if (ch_layout->order == AV_CHANNEL_ORDER_NATIVE) {
+        ch_layout->u.mask = AV_CH_LAYOUT_STEREO;
+    } else 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 == AV_CHAN_STEREO_LEFT)
+                ch_layout->u.map[i].id = AV_CHAN_FRONT_LEFT;
+            else if (ch_layout->u.map[i].id == AV_CHAN_STEREO_RIGHT)
+                ch_layout->u.map[i].id = AV_CHAN_FRONT_RIGHT;
+        }
+    }
+}
+
 static int sane_layout(const AVChannelLayout *ch_layout) {
     if(ch_layout->nb_channels >= SWR_CH_MAX)
         return 0;
@@ -605,18 +627,8 @@ av_cold int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelL
     if (ret < 0)
         goto fail;

-    if(   !av_channel_layout_compare(&out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)
-       && !av_channel_layout_subset(&in_ch_layout, AV_CH_LAYOUT_STEREO_DOWNMIX)
-    ) {
-        av_channel_layout_uninit(&out_ch_layout);
-        out_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
-    }
-    if(   !av_channel_layout_compare(&in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)
-       && !av_channel_layout_subset(&out_ch_layout, AV_CH_LAYOUT_STEREO_DOWNMIX)
-    ) {
-        av_channel_layout_uninit(&in_ch_layout);
-        in_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
-    }
+    clean_downmix(&out_ch_layout, &in_ch_layout);
+    clean_downmix(&in_ch_layout, &out_ch_layout);

     if(!av_channel_layout_check(&in_ch_layout)) {
         av_log(log_context, AV_LOG_ERROR, "Input channel layout is invalid\n");
diff --git a/tests/fate/libswresample.mak b/tests/fate/libswresample.mak
index e918bd7b46..98cd890e38 100644
--- a/tests/fate/libswresample.mak
+++ b/tests/fate/libswresample.mak
@@ -1158,6 +1158,14 @@ FATE_SWR_REMATRIX-$(CONFIG_SWRESAMPLE) += fate-swr-rematrix-unused-mono-output
 fate-swr-rematrix-unused-mono-output: libswresample/tests/rematrix$(EXESUF)
 fate-swr-rematrix-unused-mono-output: CMD = run libswresample/tests/rematrix$(EXESUF) stereo UNSD+FR

+FATE_SWR_REMATRIX-$(CONFIG_SWRESAMPLE) += fate-swr-rematrix-downmix-input
+fate-swr-rematrix-downmix-input: libswresample/tests/rematrix$(EXESUF)
+fate-swr-rematrix-downmix-input: CMD = run libswresample/tests/rematrix$(EXESUF) DR+DL 5.1
+
+FATE_SWR_REMATRIX-$(CONFIG_SWRESAMPLE) += fate-swr-rematrix-downmix-output
+fate-swr-rematrix-downmix-output: libswresample/tests/rematrix$(EXESUF)
+fate-swr-rematrix-downmix-output: CMD = run libswresample/tests/rematrix$(EXESUF) 5.1 DR+UNSD+DL
+
 FATE_SWR += $(FATE_SWR_REMATRIX-yes)
 fate-swr-rematrix: $(FATE_SWR_REMATRIX-yes)

diff --git a/tests/ref/fate/swr-rematrix-downmix-input b/tests/ref/fate/swr-rematrix-downmix-input
new file mode 100644
index 0000000000..254405fb7a
--- /dev/null
+++ b/tests/ref/fate/swr-rematrix-downmix-input
@@ -0,0 +1,6 @@
+[FL] = { .DR = 0.000000, .DL = 1.000000, },
+[FR] = { .DR = 1.000000, .DL = 0.000000, },
+[FC] = { .DR = 0.000000, .DL = 0.000000, },
+[LFE] = { .DR = 0.000000, .DL = 0.000000, },
+[BL] = { .DR = 0.000000, .DL = 0.000000, },
+[BR] = { .DR = 0.000000, .DL = 0.000000, },
diff --git a/tests/ref/fate/swr-rematrix-downmix-output b/tests/ref/fate/swr-rematrix-downmix-output
new file mode 100644
index 0000000000..a96b879ca9
--- /dev/null
+++ b/tests/ref/fate/swr-rematrix-downmix-output
@@ -0,0 +1,3 @@
+[DR] = { .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, },
+[DL] = { .FL = 1.000000, .FR = 0.000000, .FC = 0.707107, .LFE = 0.000000, .BL = 0.707107, .BR = 0.000000, },