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

Git pushed a commit to branch master
in repository ffmpeg.

commit d86f0ae534da6eeb80f05686bb744f0bb19fdf32
Author:     Niklas Haas <[email protected]>
AuthorDate: Sat Jun 20 16:17:27 2026 +0200
Commit:     Niklas Haas <[email protected]>
CommitDate: Tue Jun 23 11:48:13 2026 +0000

    swscale/ops_dispatch: don't assume first operation is a read
    
    Makes ff_sws_compile_pass() more robust; will be needed for plane splitting.
    Besides, it's perfectly valid to have an operation list that starts with
    e.g. SWS_OP_CLEAR.
    
    Sponsored-by: Sovereign Tech Fund
    Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops_dispatch.c | 32 ++++++++++++++++++--------------
 libswscale/ops_dispatch.h |  3 +--
 2 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c
index ac14a5eaf3..c8f4dcbbcc 100644
--- a/libswscale/ops_dispatch.c
+++ b/libswscale/ops_dispatch.c
@@ -496,7 +496,7 @@ static int rw_pixel_bits(const SwsOp *op)
 static void align_pass(SwsPass *pass, int block_size, const int *over_rw,
                        int pixel_bits)
 {
-    if (!pass)
+    if (!pass || pixel_bits <= 0)
         return;
 
     /* Add at least as many pixels as needed to cover the padding requirement 
*/
@@ -541,18 +541,23 @@ static int compile(SwsGraph *graph, const SwsOpBackend 
*backend,
 
     const AVPixFmtDescriptor *indesc  = av_pix_fmt_desc_get(src->format);
     const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(dst->format);
-    const SwsOp *read  = ff_sws_op_list_input(ops);
     const SwsOp *write = ff_sws_op_list_output(ops);
-    p->palette_idx = read->rw.mode == SWS_RW_PALETTE ? ops->plane_src[1] : -1;
-    p->planes_in  = rw_data_planes(read);
-    p->planes_out = rw_data_planes(write);
-    p->pixel_bits_in  = rw_pixel_bits(read);
+    p->planes_out     = rw_data_planes(write);
     p->pixel_bits_out = rw_pixel_bits(write);
+    p->palette_idx    = -1;
     p->exec_base = (SwsOpExec) {
         .width  = dst->width,
         .height = dst->height,
     };
 
+    const SwsOp *read = ff_sws_op_list_input(ops);
+    if (read) {
+        p->planes_in     = rw_data_planes(read);
+        p->pixel_bits_in = rw_pixel_bits(read);
+        if (read->rw.mode == SWS_RW_PALETTE)
+            p->palette_idx = ops->plane_src[1];
+    }
+
     const int64_t block_bits_in  = (int64_t) comp->block_size * 
p->pixel_bits_in;
     const int64_t block_bits_out = (int64_t) comp->block_size * 
p->pixel_bits_out;
     if (block_bits_in & 0x7 || block_bits_out & 0x7) {
@@ -586,8 +591,8 @@ static int compile(SwsGraph *graph, const SwsOpBackend 
*backend,
         p->idx_out[i] = idx;
     }
 
-    const SwsFilterWeights *filter = read->rw.filter.kernel;
-    if (read->rw.filter.op == SWS_OP_FILTER_V) {
+    const SwsFilterWeights *filter = read ? read->rw.filter.kernel : NULL;
+    if (read && read->rw.filter.op == SWS_OP_FILTER_V) {
         p->offsets_y = av_refstruct_ref(filter->offsets);
 
         /* Compute relative pointer bumps for each output line */
@@ -605,7 +610,7 @@ static int compile(SwsGraph *graph, const SwsOpBackend 
*backend,
         }
         bump[filter->dst_size - 1] = 0;
         p->exec_base.in_bump_y = bump;
-    } else if (read->rw.filter.op == SWS_OP_FILTER_H) {
+    } else if (read && read->rw.filter.op == SWS_OP_FILTER_H) {
         /* Compute pixel offset map for each output line */
         const int pixels = FFALIGN(filter->dst_size, p->comp.block_size);
         int32_t *offset = av_malloc_array(pixels, sizeof(*offset));
@@ -640,8 +645,9 @@ static int compile(SwsGraph *graph, const SwsOpBackend 
*backend,
         return ret;
 
     (*output)->backend = comp->backend->flags;
-    align_pass(input,   comp->block_size, comp->over_read,  p->pixel_bits_in);
     align_pass(*output, comp->block_size, comp->over_write, p->pixel_bits_out);
+    if (read)
+        align_pass(input, comp->block_size, comp->over_read,  
p->pixel_bits_in);
     return 0;
 
 fail:
@@ -665,11 +671,9 @@ int ff_sws_compile_pass(SwsGraph *graph, const 
SwsOpBackend *backend,
         goto out;
     }
 
-    const SwsOp *read  = ff_sws_op_list_input(ops);
     const SwsOp *write = ff_sws_op_list_output(ops);
-    if (!read || !write) {
-        av_log(ctx, AV_LOG_ERROR, "First and last operations must be a read "
-               "and write, respectively.\n");
+    if (!write) {
+        av_log(ctx, AV_LOG_ERROR, "Last operation must be SWS_OP_WRITE.\n");
         ret = AVERROR(EINVAL);
         goto out;
     }
diff --git a/libswscale/ops_dispatch.h b/libswscale/ops_dispatch.h
index 4097b8e947..b08d030d73 100644
--- a/libswscale/ops_dispatch.h
+++ b/libswscale/ops_dispatch.h
@@ -163,8 +163,7 @@ int ff_sws_ops_compile(SwsContext *ctx, const SwsOpBackend 
*backend,
                        const SwsOpList *ops, SwsCompiledOp *out);
 
 /**
- * Resolves an operation list to a graph pass. The first and last operations
- * must be a read/write respectively.
+ * Resolves an operation list to a graph pass. The last op must be a write.
  *
  * @param backend Force the use of a specific backend (Optional)
  * @param ops Operations to compile. Ownership passes to this function, and

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

Reply via email to