This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 6b38a4035ab9250d9e04cf211675f87fe279c6c0
Author:     Niklas Haas <[email protected]>
AuthorDate: Tue Aug 4 12:17:58 2026 +0200
Commit:     Niklas Haas <[email protected]>
CommitDate: Sun Aug 9 21:03:33 2026 +0200

    swscale/graph: add plane copy metadata
    
    This can be set opportunistically by passes which are effectively
    memcopies. Information about end-to-end plane copies will also propagate
    upwards to the SwsGraph, and can be used there by the caller.
    
    The reason we need to solve it this way is deeply tied to the way
    SwsGraph is designed; specifically the fact that it can be used with
    arbitrary frames and also lives per-field (rather than per-frame),
    meaning that we can't just directly mutate the output frame somehow from
    the run() call to ref the output planes.
    
    Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c | 49 ++++++++++++++++++++++++++++++++++++++++++-------
 libswscale/graph.h | 19 +++++++++++++++++++
 2 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 978be35203..012bb53388 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -207,6 +207,7 @@ int ff_sws_graph_add_pass(SwsGraph *graph, enum 
AVPixelFormat fmt,
     pass->output->height = height;
     pass->output->width  = width;
     pass->output->width_align = 1;
+    memset(pass->output->plane_copy, -1, sizeof(pass->output->plane_copy));
 
     if (!align) {
         pass->slice_h = pass->lines;
@@ -242,6 +243,13 @@ void ff_sws_pass_link_output(SwsPass *dst, const SwsPass 
*src)
     keep->width_align = FFMAX(keep->width_align, drop->width_align);
     keep->width_pad   = FFMAX(keep->width_pad,   drop->width_pad);
 
+    for (int i = 0; i < FF_ARRAY_ELEMS(keep->plane_copy); i++) {
+        if (keep->plane_copy[i] < 0)
+            keep->plane_copy[i] = drop->plane_copy[i];
+        else if (drop->plane_copy[i] >= 0)
+            av_assert1(keep->plane_copy[i] == drop->plane_copy[i]);
+    }
+
     av_refstruct_replace(&dst->output, src->output);
 }
 
@@ -790,15 +798,41 @@ static int init_passes(SwsGraph *graph)
             return ret;
     }
 
-    if (pass)
-        return 0;
+    if (!pass) {
+        /* No passes were added, so no operations were necessary */
+        graph->noop = 1;
+
+        const int nb_planes = av_pix_fmt_count_planes(dst.format);
+        for (int i = 0; i < nb_planes; i++)
+            graph->plane_copy[i] = i;
 
-    /* No passes were added, so no operations were necessary */
-    graph->noop = 1;
+        /* Add threaded memcpy pass */
+        return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
+                                    pass, 0, 1, run_copy, NULL, NULL, NULL, 
&pass);
+    }
 
-    /* Add threaded memcpy pass */
-    return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
-                                 pass, 0, 1, run_copy, NULL, NULL, NULL, 
&pass);
+    /* Compute end-to-end plane copy map */
+    for (int n = 0; n < graph->num_passes; n++) {
+        const SwsPass *pass = graph->passes[n];
+        /* This pass writes to an output buffer other than the image
+         * output, or copies from the output of a different pass */
+        if (pass->output->avframe || pass->input)
+            continue;
+        for (int i = 0; i < FF_ARRAY_ELEMS(graph->plane_copy); i++) {
+            const int idx = pass->output->plane_copy[i];
+            if (idx < 0)
+                continue;
+            if (graph->plane_copy[i] < 0) {
+                graph->plane_copy[i] = idx;
+                av_log(graph->ctx, AV_LOG_DEBUG, "Plane %d passthrough from "
+                       "plane %d\n", i, idx);
+            } else {
+                av_assert0(graph->plane_copy[i] == idx);
+            }
+        }
+    }
+
+    return 0;
 }
 
 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
@@ -845,6 +879,7 @@ int ff_sws_graph_init(SwsGraph *graph, SwsContext *ctx, 
const SwsFormat *dst,
     graph->opts_copy = *ctx;
     av_assert0(src->interlaced == dst->interlaced);
     av_assert0(src->field      == dst->field);
+    memset(graph->plane_copy, -1, sizeof(graph->plane_copy));
 
     if (ctx->threads == 1) {
         graph->num_threads = 1;
diff --git a/libswscale/graph.h b/libswscale/graph.h
index 4399346d46..7380a991ce 100644
--- a/libswscale/graph.h
+++ b/libswscale/graph.h
@@ -66,6 +66,15 @@ typedef struct SwsPassBuffer {
     /* Optional allocation hints for optimal performance */
     int width_align;   /* Align width to multiple of this */
     int width_pad;     /* Extra padding pixels */
+
+    /**
+     * Map of planes which are directly copied from the pass input. These
+     * may be promoted from a memcpy to a refcopy.
+     *
+     * Each entry maps the output index to the corresponding input plane
+     * index, or -1 for no copythrough.
+     */
+    int plane_copy[4];
 } SwsPassBuffer;
 
 /**
@@ -130,6 +139,16 @@ typedef struct SwsGraph {
 
     AVBufferRef *hw_frames_ref;
 
+    /**
+     * Map of planes which directly copied from the input. These may be
+     * promoted from a memcpy to a refcopy. This requires special handling
+     * by the caller.
+     *
+     * Each entry maps the output index to the corresponding input plane
+     * index, or -1 for no copythrough.
+     */
+    int plane_copy[4];
+
     /** Sorted sequence of filter passes to apply */
     SwsPass **passes;
     int num_passes;

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to