Commit 6507dc36e5 for ffmpeg

commit 6507dc36e542df5fb1c0b8b394f56297ef50385e
Author: Kacper Michajłow <kasper93@gmail.com>
Date:   Wed Sep 30 02:54:17 2026 +0200

    swscale: pass the chroma positions to the cascaded contexts

    The alpha blending, gamma, Bayer, YUV matrix and large downscale cascades
    set up their contexts without the chroma positions, so both ends of the
    conversion fell back to the default siting. The first context of a cascade
    now gets the source positions and the last one the destination positions.

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

diff --git a/libswscale/utils.c b/libswscale/utils.c
index 1c2e03eab4..138c1a4edd 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -93,6 +93,19 @@ static SwsContext *alloc_set_opts(int srcW, int srcH, enum AVPixelFormat srcForm
     return sws;
 }

+static void set_cascade_chr_pos(SwsContext *cascade, const SwsContext *sws,
+                                int src, int dst)
+{
+    if (src) {
+        cascade->src_h_chr_pos = sws->src_h_chr_pos;
+        cascade->src_v_chr_pos = sws->src_v_chr_pos;
+    }
+    if (dst) {
+        cascade->dst_h_chr_pos = sws->dst_h_chr_pos;
+        cascade->dst_v_chr_pos = sws->dst_v_chr_pos;
+    }
+}
+
 int ff_shuffle_filter_coefficients(SwsInternal *c, int *filterPos,
                                    int filterSize, int16_t *filter,
                                    int dstW)
@@ -963,6 +976,7 @@ int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4],
                 return -1;

             c->cascaded_context[0]->alpha_blend = sws->alpha_blend;
+            set_cascade_chr_pos(c->cascaded_context[0], sws, 1, 0);
             ret = sws_init_context(c->cascaded_context[0], NULL , NULL);
             if (ret < 0)
                 return ret;
@@ -978,6 +992,7 @@ int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4],
                 return -1;
             c->cascaded_context[1]->src_range = srcRange;
             c->cascaded_context[1]->dst_range = dstRange;
+            set_cascade_chr_pos(c->cascaded_context[1], sws, 0, 1);
             ret = sws_init_context(c->cascaded_context[1], NULL , NULL);
             if (ret < 0)
                 return ret;
@@ -1485,13 +1500,15 @@ av_cold int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter,
         if (ret < 0)
             return ret;

-        c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat,
+        c->cascaded_context[0] = alloc_set_opts(srcW, srcH, srcFormat,
                                                 srcW, srcH, tmpFmt,
-                                                flags, NULL, NULL,
-                                                sws->scaler_params);
-        if (!c->cascaded_context[0]) {
+                                                flags, sws->scaler_params);
+        if (!c->cascaded_context[0])
             return AVERROR(ENOMEM);
-        }
+        set_cascade_chr_pos(c->cascaded_context[0], sws, 1, 0);
+        ret = sws_init_context(c->cascaded_context[0], NULL, NULL);
+        if (ret < 0)
+            return ret;

         c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFmt,
                                                 dstW, dstH, tmpFmt,
@@ -1525,12 +1542,15 @@ av_cold int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter,
             if (ret < 0)
                 return ret;

-            c->cascaded_context[2] = sws_getContext(dstW, dstH, tmpFmt,
+            c->cascaded_context[2] = alloc_set_opts(dstW, dstH, tmpFmt,
                                                     dstW, dstH, dstFormat,
-                                                    flags, NULL, NULL,
-                                                    sws->scaler_params);
+                                                    flags, sws->scaler_params);
             if (!c->cascaded_context[2])
                 return AVERROR(ENOMEM);
+            set_cascade_chr_pos(c->cascaded_context[2], sws, 0, 1);
+            ret = sws_init_context(c->cascaded_context[2], NULL, NULL);
+            if (ret < 0)
+                return ret;
         }
         return 0;
     }
@@ -1562,12 +1582,15 @@ av_cold int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter,
             if (!c->cascaded_context[0])
                 return AVERROR(ENOMEM);

-            c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFormat,
+            c->cascaded_context[1] = alloc_set_opts(srcW, srcH, tmpFormat,
                                                     dstW, dstH, dstFormat,
-                                                    flags, NULL, dstFilter,
-                                                    sws->scaler_params);
+                                                    flags, sws->scaler_params);
             if (!c->cascaded_context[1])
                 return AVERROR(ENOMEM);
+            set_cascade_chr_pos(c->cascaded_context[1], sws, 0, 1);
+            ret = sws_init_context(c->cascaded_context[1], NULL, dstFilter);
+            if (ret < 0)
+                return ret;
             return 0;
         }
     }
@@ -1618,6 +1641,7 @@ av_cold int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter,

                 c->cascaded_context[1]->src_range = sws->src_range;
                 c->cascaded_context[1]->dst_range = sws->dst_range;
+                set_cascade_chr_pos(c->cascaded_context[1], sws, 1, 1);
                 ret = sws_init_context(c->cascaded_context[1], srcFilter , dstFilter);
                 if (ret < 0)
                     return ret;
@@ -1839,19 +1863,25 @@ fail: // FIXME replace things by appropriate error codes
         if (ret < 0)
             return ret;

-        c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat,
+        c->cascaded_context[0] = alloc_set_opts(srcW, srcH, srcFormat,
                                                 tmpW, tmpH, tmpFormat,
-                                                flags, srcFilter, NULL,
-                                                sws->scaler_params);
+                                                flags, sws->scaler_params);
         if (!c->cascaded_context[0])
             return AVERROR(ENOMEM);
+        set_cascade_chr_pos(c->cascaded_context[0], sws, 1, 0);
+        ret = sws_init_context(c->cascaded_context[0], srcFilter, NULL);
+        if (ret < 0)
+            return ret;

-        c->cascaded_context[1] = sws_getContext(tmpW, tmpH, tmpFormat,
+        c->cascaded_context[1] = alloc_set_opts(tmpW, tmpH, tmpFormat,
                                                 dstW, dstH, dstFormat,
-                                                flags, NULL, dstFilter,
-                                                sws->scaler_params);
+                                                flags, sws->scaler_params);
         if (!c->cascaded_context[1])
             return AVERROR(ENOMEM);
+        set_cascade_chr_pos(c->cascaded_context[1], sws, 0, 1);
+        ret = sws_init_context(c->cascaded_context[1], NULL, dstFilter);
+        if (ret < 0)
+            return ret;
         return 0;
     }
     return ret;
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index 6de375fcfb..2bc6d14081 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -578,6 +578,14 @@ FATE_FILTER_VSYNTH-$(call FILTERDEMDEC, SCALE, RAWVIDEO, RAWVIDEO) += fate-filte
 fate-filter-scalechroma: tests/data/vsynth1.yuv
 fate-filter-scalechroma: CMD = framecrc -flags bitexact -s 352x288 -pix_fmt yuv444p -i $(TARGET_PATH)/tests/data/vsynth1.yuv -pix_fmt yuv420p -sws_flags +bitexact -vf scale=out_chroma_loc=bottomleft

+FATE_FILTER-$(call FILTERFRAMECRC, TESTSRC2 FORMAT SCALE, SWSCALE_ALPHA) += fate-filter-scalechroma-alphablend fate-filter-scalechroma-alphablend-scaled
+fate-filter-scalechroma-alphablend: CMD = framecrc -flags bitexact -lavfi testsrc2=s=64x64:r=1:d=1:alpha=128,format=yuva420p,scale=in_chroma_loc=topleft:out_chroma_loc=center:alphablend=uniform_color:flags=accurate_rnd+bitexact,format=yuv420p -frames:v 1
+fate-filter-scalechroma-alphablend-scaled: CMD = framecrc -flags bitexact -lavfi testsrc2=s=64x64:r=1:d=1:alpha=128,format=yuva420p,scale=96:80:in_chroma_loc=topleft:out_chroma_loc=center:alphablend=uniform_color:flags=accurate_rnd+bitexact,format=yuv420p -frames:v 1
+
+FATE_FILTER-$(call FILTERFRAMECRC, TESTSRC2 FORMAT SCALE) += fate-filter-scalechroma-matrix fate-filter-scalechroma-downscale
+fate-filter-scalechroma-matrix: CMD = framecrc -flags bitexact -lavfi testsrc2=s=64x64:r=1:d=1,format=yuv420p,scale=96:80:in_color_matrix=bt709:out_color_matrix=bt470bg:in_range=tv:out_range=tv:in_chroma_loc=topleft:out_chroma_loc=center:flags=accurate_rnd+bitexact,format=yuv420p -frames:v 1
+fate-filter-scalechroma-downscale: CMD = framecrc -flags bitexact -lavfi testsrc2=s=2048x2048:r=1:d=1,format=yuv420p,scale=8:8:in_chroma_loc=topleft:out_chroma_loc=center:flags=accurate_rnd+bitexact,format=yuv420p -frames:v 1
+
 FATE_FILTER-$(call ALLYES, SCALE_FILTER TESTSRC2_FILTER LAVFI_INDEV \
                            WRAPPED_AVFRAME_DECODER WRAPPED_AVFRAME_ENCODER \
                            NULL_MUXER) += fate-filter-scale-print-info \
diff --git a/tests/ref/fate/filter-scalechroma-alphablend b/tests/ref/fate/filter-scalechroma-alphablend
new file mode 100644
index 0000000000..963090d153
--- /dev/null
+++ b/tests/ref/fate/filter-scalechroma-alphablend
@@ -0,0 +1,6 @@
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 64x64
+#sar 0: 1/1
+0,          0,          0,        1,     6144, 0x0fa9d30b
diff --git a/tests/ref/fate/filter-scalechroma-alphablend-scaled b/tests/ref/fate/filter-scalechroma-alphablend-scaled
new file mode 100644
index 0000000000..34eb32fa4c
--- /dev/null
+++ b/tests/ref/fate/filter-scalechroma-alphablend-scaled
@@ -0,0 +1,6 @@
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 96x80
+#sar 0: 5/6
+0,          0,          0,        1,    11520, 0xc9f1cbcd
diff --git a/tests/ref/fate/filter-scalechroma-downscale b/tests/ref/fate/filter-scalechroma-downscale
new file mode 100644
index 0000000000..c950c7ce87
--- /dev/null
+++ b/tests/ref/fate/filter-scalechroma-downscale
@@ -0,0 +1,6 @@
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 8x8
+#sar 0: 1/1
+0,          0,          0,        1,       96, 0xeea52f46
diff --git a/tests/ref/fate/filter-scalechroma-matrix b/tests/ref/fate/filter-scalechroma-matrix
new file mode 100644
index 0000000000..3231a9a38a
--- /dev/null
+++ b/tests/ref/fate/filter-scalechroma-matrix
@@ -0,0 +1,6 @@
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 96x80
+#sar 0: 5/6
+0,          0,          0,        1,    11520, 0x840d7d5a