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

Git pushed a commit to branch master
in repository ffmpeg.

commit 67f36272671be9405248386bfbc467a6a772d5ce
Author:     Niklas Haas <[email protected]>
AuthorDate: Fri Feb 27 11:02:38 2026 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Fri Feb 27 16:18:34 2026 +0000

    swscale/graph: nuke SwsImg
    
    This has now become fully redundant with AVFrame, especially since the
    existence of SwsPassBuffer. Delete it, simplifying a lot of things and
    avoiding reinventing the wheel everywhere.
    
    Also generally reduces overhead, since there is less redundant copying
    going on.
    
    Sponsored-by: Sovereign Tech Fund
    Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/graph.c | 98 +++++++++++++++++++++++++++---------------------------
 libswscale/graph.h | 27 ++++++---------
 libswscale/ops.c   | 12 +++----
 3 files changed, 66 insertions(+), 71 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 5469012f37..6a17a12496 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -94,10 +94,6 @@ static int pass_alloc_output(SwsPass *pass)
     }
 
     buffer->frame = frame;
-    buffer->img.fmt = pass->format;
-    buffer->img.frame_ptr = frame;
-    memcpy(buffer->img.data, frame->data, sizeof(frame->data));
-    memcpy(buffer->img.linesize, frame->linesize, sizeof(frame->linesize));
     return 0;
 }
 
@@ -141,9 +137,8 @@ SwsPass *ff_sws_graph_add_pass(SwsGraph *graph, enum 
AVPixelFormat fmt,
     }
 
     /* Align output buffer to include extra slice padding */
-    pass->output->img.fmt = fmt;
-    pass->output->width   = pass->width;
-    pass->output->height  = pass->slice_h * pass->num_slices;
+    pass->output->width  = pass->width;
+    pass->output->height = pass->slice_h * pass->num_slices;
 
     ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
     if (ret < 0)
@@ -168,25 +163,25 @@ static int pass_append(SwsGraph *graph, enum 
AVPixelFormat fmt, int w, int h,
     return 0;
 }
 
-static void img_shift(const SwsImg *img, const int y, uint8_t *data[4])
+static void frame_shift(const AVFrame *f, const int y, uint8_t *data[4])
 {
     for (int i = 0; i < 4; i++) {
-        if (img->data[i])
-            data[i] = img->data[i] + (y >> ff_fmt_vshift(img->fmt, i)) * 
img->linesize[i];
+        if (f->data[i])
+            data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * 
f->linesize[i];
         else
             data[i] = NULL;
     }
 }
 
-static void run_copy(const SwsImg *out, const SwsImg *in, int y, int h,
+static void run_copy(const AVFrame *out, const AVFrame *in, int y, int h,
                      const SwsPass *pass)
 {
     uint8_t *in_data[4], *out_data[4];
-    img_shift(in,  y, in_data);
-    img_shift(out, y, out_data);
+    frame_shift(in,  y, in_data);
+    frame_shift(out, y, out_data);
 
     for (int i = 0; i < 4 && out_data[i]; i++) {
-        const int lines = h >> ff_fmt_vshift(in->fmt, i);
+        const int lines = h >> ff_fmt_vshift(in->format, i);
         av_assert1(in_data[i]);
 
         if (in_data[i] == out_data[i]) {
@@ -204,7 +199,7 @@ static void run_copy(const SwsImg *out, const SwsImg *in, 
int y, int h,
     }
 }
 
-static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h,
+static void run_rgb0(const AVFrame *out, const AVFrame *in, int y, int h,
                      const SwsPass *pass)
 {
     SwsInternal *c = pass->priv;
@@ -225,7 +220,7 @@ static void run_rgb0(const SwsImg *out, const SwsImg *in, 
int y, int h,
     }
 }
 
-static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h,
+static void run_xyz2rgb(const AVFrame *out, const AVFrame *in, int y, int h,
                         const SwsPass *pass)
 {
     const SwsInternal *c = pass->priv;
@@ -234,7 +229,7 @@ static void run_xyz2rgb(const SwsImg *out, const SwsImg 
*in, int y, int h,
                     pass->width, h);
 }
 
-static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h,
+static void run_rgb2xyz(const AVFrame *out, const AVFrame *in, int y, int h,
                         const SwsPass *pass)
 {
     const SwsInternal *c = pass->priv;
@@ -255,7 +250,7 @@ static void free_legacy_swscale(void *priv)
     sws_free_context(&sws);
 }
 
-static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in,
+static void setup_legacy_swscale(const AVFrame *out, const AVFrame *in,
                                  const SwsPass *pass)
 {
     SwsContext *sws = pass->priv;
@@ -288,25 +283,25 @@ static inline SwsContext *slice_ctx(const SwsPass *pass, 
int y)
     return sws;
 }
 
-static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in,
+static void run_legacy_unscaled(const AVFrame *out, const AVFrame *in,
                                 int y, int h, const SwsPass *pass)
 {
     SwsContext *sws = slice_ctx(pass, y);
     SwsInternal *c = sws_internal(sws);
     uint8_t *in_data[4];
-    img_shift(in, y, in_data);
+    frame_shift(in, y, in_data);
 
     c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, 
h,
                         out->data, out->linesize);
 }
 
-static void run_legacy_swscale(const SwsImg *out, const SwsImg *in,
+static void run_legacy_swscale(const AVFrame *out, const AVFrame *in,
                                int y, int h, const SwsPass *pass)
 {
     SwsContext *sws = slice_ctx(pass, y);
     SwsInternal *c = sws_internal(sws);
     uint8_t *out_data[4];
-    img_shift(out, y, out_data);
+    frame_shift(out, y, out_data);
 
     ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
                sws->src_h, out_data, out->linesize, y, h);
@@ -637,7 +632,7 @@ static void free_lut3d(void *priv)
     ff_sws_lut3d_free(&lut);
 }
 
-static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass 
*pass)
+static void setup_lut3d(const AVFrame *out, const AVFrame *in, const SwsPass 
*pass)
 {
     SwsLut3D *lut = pass->priv;
 
@@ -645,13 +640,13 @@ static void setup_lut3d(const SwsImg *out, const SwsImg 
*in, const SwsPass *pass
     ff_sws_lut3d_update(lut, &pass->graph->src.color);
 }
 
-static void run_lut3d(const SwsImg *out, const SwsImg *in, int y, int h,
+static void run_lut3d(const AVFrame *out, const AVFrame *in, int y, int h,
                       const SwsPass *pass)
 {
     SwsLut3D *lut = pass->priv;
     uint8_t *in_data[4], *out_data[4];
-    img_shift(in,  y, in_data);
-    img_shift(out, y, out_data);
+    frame_shift(in,  y, in_data);
+    frame_shift(out, y, out_data);
 
     ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0],
                        out->linesize[0], pass->width, h);
@@ -769,7 +764,7 @@ static void sws_graph_worker(void *priv, int jobnr, int 
threadnr, int nb_jobs,
     const int slice_y = jobnr * pass->slice_h;
     const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
 
-    pass->run(&graph->exec.output, &graph->exec.input, slice_y, slice_h, pass);
+    pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
 }
 
 int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat 
*src,
@@ -786,6 +781,14 @@ int ff_sws_graph_create(SwsContext *ctx, const SwsFormat 
*dst, const SwsFormat *
     graph->field = field;
     graph->opts_copy = *ctx;
 
+    for (int i = 0; i < FF_ARRAY_ELEMS(graph->field_tmp); i++) {
+        graph->field_tmp[i] = av_frame_alloc();
+        if (!graph->field_tmp[i]) {
+            ret = AVERROR(ENOMEM);
+            goto error;
+        }
+    }
+
     ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
                                     sws_graph_worker, NULL, ctx->threads);
     if (ret == AVERROR(ENOSYS))
@@ -824,6 +827,9 @@ void ff_sws_graph_free(SwsGraph **pgraph)
     }
     av_free(graph->passes);
 
+    for (int i = 0; i < FF_ARRAY_ELEMS(graph->field_tmp); i++)
+        av_frame_free(&graph->field_tmp[i]);
+
     av_free(graph);
     *pgraph = NULL;
 }
@@ -869,28 +875,22 @@ void ff_sws_graph_update_metadata(SwsGraph *graph, const 
SwsColor *color)
     ff_color_update_dynamic(&graph->src.color, color);
 }
 
-static SwsImg get_field(const AVFrame *frame, int field)
+static const AVFrame *get_field(SwsGraph *graph, const AVFrame *frame,
+                                AVFrame *restrict tmp)
 {
-    SwsImg img = {0};
-
-    img.frame_ptr = frame;
-    img.fmt = frame->format;
-    for (int i = 0; i < 4; i++) {
-        img.data[i]     = frame->data[i];
-        img.linesize[i] = frame->linesize[i];
-    }
-
     if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) {
-        av_assert1(!field);
-        return img;
+        av_assert1(!graph->field);
+        return frame;
     }
 
-    if (field == FIELD_BOTTOM) {
+    *tmp = *frame;
+
+    if (graph->field == FIELD_BOTTOM) {
         /* Odd rows, offset by one line */
         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
         for (int i = 0; i < 4; i++) {
-            if (img.data[i])
-                img.data[i] += img.linesize[i];
+            if (tmp->data[i])
+                tmp->data[i] += frame->linesize[i];
             if (desc->flags & AV_PIX_FMT_FLAG_PAL)
                 break;
         }
@@ -898,25 +898,25 @@ static SwsImg get_field(const AVFrame *frame, int field)
 
     /* Take only every second line */
     for (int i = 0; i < 4; i++)
-        img.linesize[i] <<= 1;
+        tmp->linesize[i] <<= 1;
 
-    return img;
+    return tmp;
 }
 
 void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
 {
     av_assert0(dst->format == graph->dst.hw_format || dst->format == 
graph->dst.format);
     av_assert0(src->format == graph->src.hw_format || src->format == 
graph->src.format);
-    SwsImg input  = get_field(src, graph->field);
-    SwsImg output = get_field(dst, graph->field);
+    const AVFrame *src_field = get_field(graph, src, graph->field_tmp[0]);
+    const AVFrame *dst_field = get_field(graph, dst, graph->field_tmp[1]);
 
     for (int i = 0; i < graph->num_passes; i++) {
         const SwsPass *pass = graph->passes[i];
         graph->exec.pass   = pass;
-        graph->exec.input  = pass->input ? pass->input->output->img : input;
-        graph->exec.output = pass->output->frame ? pass->output->img : output;
+        graph->exec.input  = pass->input ? pass->input->output->frame : 
src_field;
+        graph->exec.output = pass->output->frame ? pass->output->frame : 
dst_field;
         if (pass->setup)
-            pass->setup(&graph->exec.output, &graph->exec.input, pass);
+            pass->setup(graph->exec.output, graph->exec.input, pass);
         avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0);
     }
 }
diff --git a/libswscale/graph.h b/libswscale/graph.h
index 6d3db640fd..9ddf2ad1c9 100644
--- a/libswscale/graph.h
+++ b/libswscale/graph.h
@@ -29,16 +29,6 @@
 #include "swscale.h"
 #include "format.h"
 
-/**
- * Represents a view into a single field of frame data.
- */
-typedef struct SwsImg {
-    enum AVPixelFormat fmt;
-    uint8_t *data[4]; /* points to y=0 */
-    int linesize[4];
-    const AVFrame *frame_ptr; /* Pointer to the original AVframe */
-} SwsImg;
-
 static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int 
plane)
 {
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
@@ -52,16 +42,15 @@ typedef struct SwsGraph SwsGraph;
  * Output `h` lines of filtered data. `out` and `in` point to the
  * start of the image buffer for this pass.
  */
-typedef void (*sws_filter_run_t)(const SwsImg *out, const SwsImg *in,
+typedef void (*sws_filter_run_t)(const AVFrame *out, const AVFrame *in,
                                  int y, int h, const SwsPass *pass);
 
 /**
  * Represents an allocated output buffer for a filter pass.
  */
 typedef struct SwsPassBuffer {
-    SwsImg img;
     int width, height; /* dimensions of this buffer */
-    AVFrame *frame; /* backing storage for frame data */
+    AVFrame *frame;
 } SwsPassBuffer;
 
 /**
@@ -97,7 +86,7 @@ struct SwsPass {
     /**
      * Called once from the main thread before running the filter. Optional.
      */
-    void (*setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass);
+    void (*setup)(const AVFrame *out, const AVFrame *in, const SwsPass *pass);
 
     /**
      * Optional private state and associated free() function.
@@ -134,14 +123,20 @@ typedef struct SwsGraph {
     SwsFormat src, dst;
     int field;
 
+    /**
+     * Temporary storage to hold individual fields of the input frames.
+     * No actual ownership over the data.
+     */
+    AVFrame *field_tmp[2];
+
     /**
      * Temporary execution state inside ff_sws_graph_run(); used to pass
      * data to worker threads.
      */
     struct {
         const SwsPass *pass; /* current filter pass */
-        SwsImg input; /* current filter pass input/output */
-        SwsImg output;
+        const AVFrame *input; /* current filter pass input/output */
+        const AVFrame *output;
     } exec;
 } SwsGraph;
 
diff --git a/libswscale/ops.c b/libswscale/ops.c
index 8a93d93d00..b3db758682 100644
--- a/libswscale/ops.c
+++ b/libswscale/ops.c
@@ -945,11 +945,11 @@ static inline void get_row_data(const SwsOpPass *p, const 
int y,
         out[i] = base->out[i] + (y >> base->out_sub_y[i]) * 
base->out_stride[i];
 }
 
-static void op_pass_setup(const SwsImg *out, const SwsImg *in,
+static void op_pass_setup(const AVFrame *out, const AVFrame *in,
                           const SwsPass *pass)
 {
-    const AVPixFmtDescriptor *indesc  = av_pix_fmt_desc_get(in->fmt);
-    const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->fmt);
+    const AVPixFmtDescriptor *indesc  = av_pix_fmt_desc_get(in->format);
+    const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format);
 
     SwsOpPass *p = pass->priv;
     SwsOpExec *exec = &p->exec_base;
@@ -1009,8 +1009,8 @@ static void op_pass_setup(const SwsImg *out, const SwsImg 
*in,
         exec->out_bump[i] = exec->out_stride[i] - blocks_main * 
exec->block_size_out;
     }
 
-    exec->src_frame_ptr = in->frame_ptr;
-    exec->dst_frame_ptr = out->frame_ptr;
+    exec->src_frame_ptr = in;
+    exec->dst_frame_ptr = out;
 }
 
 /* Dispatch kernel over the last column of the image using memcpy */
@@ -1079,7 +1079,7 @@ handle_tail(const SwsOpPass *p, SwsOpExec *exec,
     }
 }
 
-static void op_pass_run(const SwsImg *out, const SwsImg *in, const int y,
+static void op_pass_run(const AVFrame *out, const AVFrame *in, const int y,
                         const int h, const SwsPass *pass)
 {
     const SwsOpPass *p = pass->priv;

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

Reply via email to