PR #22422 opened by Niklas Haas (haasn) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22422 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22422.patch
A grab bag of trivial, easily reviewable cosmetic/minor changes. >From 2b669745f5aab36f28cdb28b4a4b1640931d1386 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Thu, 12 Feb 2026 10:44:19 +0100 Subject: [PATCH 01/13] swscale/ops: use SwsCompFlags typedef instead of plain int This improves the debugging experience. These are all internal structs so there is no need to worry about ABI stability as a result of adding flags. Signed-off-by: Niklas Haas <[email protected]> --- libswscale/ops.c | 14 +++++++------- libswscale/ops.h | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index 9961f4f791..f8447f284c 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -213,11 +213,11 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4]) } /* merge_comp_flags() forms a monoid with flags_identity as the null element */ -static const unsigned flags_identity = SWS_COMP_ZERO | SWS_COMP_EXACT; -static unsigned merge_comp_flags(unsigned a, unsigned b) +static const SwsCompFlags flags_identity = SWS_COMP_ZERO | SWS_COMP_EXACT; +static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b) { - const unsigned flags_or = SWS_COMP_GARBAGE; - const unsigned flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT; + const SwsCompFlags flags_or = SWS_COMP_GARBAGE; + const SwsCompFlags flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT; return ((a & b) & flags_and) | ((a | b) & flags_or); } @@ -320,7 +320,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) } break; case SWS_OP_PACK: { - unsigned flags = flags_identity; + SwsCompFlags flags = flags_identity; for (int i = 0; i < 4; i++) { if (op->pack.pattern[i]) flags = merge_comp_flags(flags, prev.flags[i]); @@ -356,7 +356,7 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) break; case SWS_OP_LINEAR: for (int i = 0; i < 4; i++) { - unsigned flags = flags_identity; + SwsCompFlags flags = flags_identity; AVRational min = Q(0), max = Q(0); for (int j = 0; j < 4; j++) { const AVRational k = op->lin.m[i][j]; @@ -681,7 +681,7 @@ static const char *describe_lin_mask(uint32_t mask) return "ERR"; } -static char describe_comp_flags(unsigned flags) +static char describe_comp_flags(SwsCompFlags flags) { if (flags & SWS_COMP_GARBAGE) return 'X'; diff --git a/libswscale/ops.h b/libswscale/ops.h index 64a4a6dd61..8868d88bed 100644 --- a/libswscale/ops.h +++ b/libswscale/ops.h @@ -69,12 +69,12 @@ typedef enum SwsOpType { SWS_OP_TYPE_NB, } SwsOpType; -enum SwsCompFlags { +typedef enum SwsCompFlags { SWS_COMP_GARBAGE = 1 << 0, /* contents are undefined / garbage data */ SWS_COMP_EXACT = 1 << 1, /* value is an exact integer */ SWS_COMP_ZERO = 1 << 2, /* known to be a constant zero */ SWS_COMP_SWAPPED = 1 << 3, /* byte order is swapped */ -}; +} SwsCompFlags; typedef union SwsConst { /* Generic constant value */ @@ -87,8 +87,8 @@ static_assert(sizeof(SwsConst) == sizeof(AVRational) * 4, "First field of SwsConst should span the entire union"); typedef struct SwsComps { - unsigned flags[4]; /* knowledge about (output) component contents */ - bool unused[4]; /* which input components are definitely unused */ + SwsCompFlags flags[4]; /* knowledge about (output) component contents */ + bool unused[4]; /* which input components are definitely unused */ /* Keeps track of the known possible value range, or {0, 0} for undefined * or (unknown range) floating point inputs */ -- 2.52.0 >From 6aea0cc60b2b59ee24abef0bcec341689204b49e Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Mon, 16 Feb 2026 11:09:11 +0100 Subject: [PATCH 02/13] swscale/ops: add ff_sws_op_type_name Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/ops.c | 26 ++++++++++++++++++++++++++ libswscale/ops.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/libswscale/ops.c b/libswscale/ops.c index f8447f284c..07c2080e97 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -92,6 +92,32 @@ bool ff_sws_pixel_type_is_int(SwsPixelType type) return false; } +const char *ff_sws_op_type_name(SwsOpType op) +{ + switch (op) { + case SWS_OP_READ: return "SWS_OP_READ"; + case SWS_OP_WRITE: return "SWS_OP_WRITE"; + case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES"; + case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE"; + case SWS_OP_UNPACK: return "SWS_OP_UNPACK"; + case SWS_OP_PACK: return "SWS_OP_PACK"; + case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT"; + case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT"; + case SWS_OP_CLEAR: return "SWS_OP_CLEAR"; + case SWS_OP_CONVERT: return "SWS_OP_CONVERT"; + case SWS_OP_MIN: return "SWS_OP_MIN"; + case SWS_OP_MAX: return "SWS_OP_MAX"; + case SWS_OP_SCALE: return "SWS_OP_SCALE"; + case SWS_OP_LINEAR: return "SWS_OP_LINEAR"; + case SWS_OP_DITHER: return "SWS_OP_DITHER"; + case SWS_OP_INVALID: return "SWS_OP_INVALID"; + case SWS_OP_TYPE_NB: break; + } + + av_unreachable("Invalid operation type!"); + return "ERR"; +} + /* biased towards `a` */ static AVRational av_min_q(AVRational a, AVRational b) { diff --git a/libswscale/ops.h b/libswscale/ops.h index 8868d88bed..37e8f06331 100644 --- a/libswscale/ops.h +++ b/libswscale/ops.h @@ -69,6 +69,8 @@ typedef enum SwsOpType { SWS_OP_TYPE_NB, } SwsOpType; +const char *ff_sws_op_type_name(SwsOpType op); + typedef enum SwsCompFlags { SWS_COMP_GARBAGE = 1 << 0, /* contents are undefined / garbage data */ SWS_COMP_EXACT = 1 << 1, /* value is an exact integer */ -- 2.52.0 >From 16e7a8253609bf6febb781cf29479051dd368913 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Mon, 16 Feb 2026 12:04:09 +0100 Subject: [PATCH 03/13] swscale/ops: simplify ff_sws_op_list_print Using the new ff_sws_op_type_name() helper. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/ops.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index 07c2080e97..9bea2f0b4f 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -760,8 +760,9 @@ void ff_sws_op_list_print(void *log, int lev, int lev_extra, } for (int i = 0; i < ops->num_ops; i++) { - const SwsOp *op = &ops->ops[i]; + const SwsOp *op = &ops->ops[i]; const SwsOp *next = i + 1 < ops->num_ops ? &ops->ops[i + 1] : op; + const char *name = ff_sws_op_type_name(op->op); char buf[32]; av_log(log, lev, " [%3s %c%c%c%c -> %c%c%c%c] ", @@ -777,68 +778,62 @@ void ff_sws_op_list_print(void *log, int lev, int lev_extra, switch (op->op) { case SWS_OP_INVALID: - av_log(log, lev, "SWS_OP_INVALID\n"); + case SWS_OP_SWAP_BYTES: + av_log(log, lev, "%s\n", name); break; case SWS_OP_READ: case SWS_OP_WRITE: - av_log(log, lev, "%-20s: %d elem(s) %s >> %d%s\n", - op->op == SWS_OP_READ ? "SWS_OP_READ" - : "SWS_OP_WRITE", + av_log(log, lev, "%-20s: %d elem(s) %s >> %d%s\n", name, op->rw.elems, op->rw.packed ? "packed" : "planar", op->rw.frac, describe_order(op->op == SWS_OP_READ ? ops->order_src : ops->order_dst, op->rw.packed ? 1 : op->rw.elems, buf)); break; - case SWS_OP_SWAP_BYTES: - av_log(log, lev, "SWS_OP_SWAP_BYTES\n"); - break; case SWS_OP_LSHIFT: - av_log(log, lev, "%-20s: << %u\n", "SWS_OP_LSHIFT", op->c.u); + av_log(log, lev, "%-20s: << %u\n", name, op->c.u); break; case SWS_OP_RSHIFT: - av_log(log, lev, "%-20s: >> %u\n", "SWS_OP_RSHIFT", op->c.u); + av_log(log, lev, "%-20s: >> %u\n", name, op->c.u); break; case SWS_OP_PACK: case SWS_OP_UNPACK: - av_log(log, lev, "%-20s: {%d %d %d %d}\n", - op->op == SWS_OP_PACK ? "SWS_OP_PACK" - : "SWS_OP_UNPACK", + av_log(log, lev, "%-20s: {%d %d %d %d}\n", name, op->pack.pattern[0], op->pack.pattern[1], op->pack.pattern[2], op->pack.pattern[3]); break; case SWS_OP_CLEAR: - av_log(log, lev, "%-20s: {%s %s %s %s}\n", "SWS_OP_CLEAR", + av_log(log, lev, "%-20s: {%s %s %s %s}\n", name, op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_", op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_", op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_", op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_"); break; case SWS_OP_SWIZZLE: - av_log(log, lev, "%-20s: %d%d%d%d\n", "SWS_OP_SWIZZLE", + av_log(log, lev, "%-20s: %d%d%d%d\n", name, op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w); break; case SWS_OP_CONVERT: - av_log(log, lev, "%-20s: %s -> %s%s\n", "SWS_OP_CONVERT", + av_log(log, lev, "%-20s: %s -> %s%s\n", name, ff_sws_pixel_type_name(op->type), ff_sws_pixel_type_name(op->convert.to), op->convert.expand ? " (expand)" : ""); break; case SWS_OP_DITHER: - av_log(log, lev, "%-20s: %dx%d matrix + {%d %d %d %d}\n", "SWS_OP_DITHER", + av_log(log, lev, "%-20s: %dx%d matrix + {%d %d %d %d}\n", name, 1 << op->dither.size_log2, 1 << op->dither.size_log2, op->dither.y_offset[0], op->dither.y_offset[1], op->dither.y_offset[2], op->dither.y_offset[3]); break; case SWS_OP_MIN: - av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", "SWS_OP_MIN", + av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", name, op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_", op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_", op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_", op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_"); break; case SWS_OP_MAX: - av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", "SWS_OP_MAX", + av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", name, op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_", op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_", op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_", @@ -849,15 +844,14 @@ void ff_sws_op_list_print(void *log, int lev, int lev_extra, "[%s %s %s %s %s] " "[%s %s %s %s %s] " "[%s %s %s %s %s]]\n", - "SWS_OP_LINEAR", describe_lin_mask(op->lin.mask), + name, describe_lin_mask(op->lin.mask), PRINTQ(op->lin.m[0][0]), PRINTQ(op->lin.m[0][1]), PRINTQ(op->lin.m[0][2]), PRINTQ(op->lin.m[0][3]), PRINTQ(op->lin.m[0][4]), PRINTQ(op->lin.m[1][0]), PRINTQ(op->lin.m[1][1]), PRINTQ(op->lin.m[1][2]), PRINTQ(op->lin.m[1][3]), PRINTQ(op->lin.m[1][4]), PRINTQ(op->lin.m[2][0]), PRINTQ(op->lin.m[2][1]), PRINTQ(op->lin.m[2][2]), PRINTQ(op->lin.m[2][3]), PRINTQ(op->lin.m[2][4]), PRINTQ(op->lin.m[3][0]), PRINTQ(op->lin.m[3][1]), PRINTQ(op->lin.m[3][2]), PRINTQ(op->lin.m[3][3]), PRINTQ(op->lin.m[3][4])); break; case SWS_OP_SCALE: - av_log(log, lev, "%-20s: * %s\n", "SWS_OP_SCALE", - PRINTQ(op->c.q)); + av_log(log, lev, "%-20s: * %s\n", name, PRINTQ(op->c.q)); break; case SWS_OP_TYPE_NB: break; -- 2.52.0 >From 1372223da0eb23c7c47685611d941bc8b7452b4e Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Thu, 26 Feb 2026 15:05:09 +0100 Subject: [PATCH 04/13] swscale/vulkan/ops: log op name in generated shader I think this just makes for a marginally nicer debugging experience. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/vulkan/ops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c index b52f5d9d3d..b423683120 100644 --- a/libswscale/vulkan/ops.c +++ b/libswscale/vulkan/ops.c @@ -234,6 +234,8 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s, const char *type_s = op->type == SWS_PIXEL_F32 ? "float" : op->type == SWS_PIXEL_U32 ? "uint32_t" : op->type == SWS_PIXEL_U16 ? "uint16_t" : "uint8_t"; + av_bprintf(&shd->src, " // %s\n", ff_sws_op_type_name(op->op)); + switch (op->op) { case SWS_OP_READ: { if (op->rw.packed) { -- 2.52.0 >From a8e62ecf65d541d2b719dfd29dead2fdd549bcd1 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Fri, 6 Mar 2026 18:05:14 +0100 Subject: [PATCH 05/13] swscale/vulkan/ops: fix undefined behavior on SWS_OP_CLEAR op->rw.frac dereferences nonsense on clear ops. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/vulkan/ops.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c index b423683120..db59e123ef 100644 --- a/libswscale/vulkan/ops.c +++ b/libswscale/vulkan/ops.c @@ -182,8 +182,7 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s, for (int n = 0; n < ops->num_ops; n++) { const SwsOp *op = &ops->ops[n]; /* Set initial type */ - if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE || - op->op == SWS_OP_CLEAR) { + if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) { if (op->rw.frac) return AVERROR(ENOTSUP); } -- 2.52.0 >From 461098ef38454cca99002462224ed21f073c5825 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Fri, 6 Mar 2026 18:07:12 +0100 Subject: [PATCH 06/13] swscale/vulkan/ops: move buffer desc setting to helper function And call it on the read/write ops directly, rather than this awkward loop. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/vulkan/ops.c | 57 +++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/libswscale/vulkan/ops.c b/libswscale/vulkan/ops.c index db59e123ef..9c9b91ed98 100644 --- a/libswscale/vulkan/ops.c +++ b/libswscale/vulkan/ops.c @@ -157,6 +157,28 @@ static void free_fn(void *priv) av_free(priv); } +static void add_desc_read_write(FFVulkanDescriptorSetBinding *out_desc, + enum FFVkShaderRepFormat *out_rep, + const SwsOp *op) +{ + const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f" : + op->type == SWS_PIXEL_U32 ? "rgba32ui" : + op->type == SWS_PIXEL_U16 ? "rgba16ui" : + "rgba8ui"; + + *out_desc = (FFVulkanDescriptorSetBinding) { + .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .mem_layout = img_type, + .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly", + .dimensions = 2, + .elems = op->rw.packed ? 1 : op->rw.elems, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + }; + + *out_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : FF_VK_REP_UINT; +} + #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s, SwsOpList *ops, FFVulkanShader *shd) @@ -179,36 +201,11 @@ static int add_ops_glsl(VulkanPriv *p, FFVulkanOpsCtx *s, int nb_desc = 0; FFVulkanDescriptorSetBinding buf_desc[8]; - for (int n = 0; n < ops->num_ops; n++) { - const SwsOp *op = &ops->ops[n]; - /* Set initial type */ - if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) { - if (op->rw.frac) - return AVERROR(ENOTSUP); - } - if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) { - const char *img_type = op->type == SWS_PIXEL_F32 ? "rgba32f" : - op->type == SWS_PIXEL_U32 ? "rgba32ui" : - op->type == SWS_PIXEL_U16 ? "rgba16ui" : - "rgba8ui"; - buf_desc[nb_desc++] = (FFVulkanDescriptorSetBinding) { - .name = op->op == SWS_OP_WRITE ? "dst_img" : "src_img", - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .mem_layout = img_type, - .mem_quali = op->op == SWS_OP_WRITE ? "writeonly" : "readonly", - .dimensions = 2, - .elems = (op->rw.packed ? 1 : op->rw.elems), - .stages = VK_SHADER_STAGE_COMPUTE_BIT, - }; - if (op->op == SWS_OP_READ) - p->src_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : - FF_VK_REP_UINT; - else - p->dst_rep = op->type == SWS_PIXEL_F32 ? FF_VK_REP_FLOAT : - FF_VK_REP_UINT; - } - } - + const SwsOp *read = ff_sws_op_list_input(ops); + const SwsOp *write = ff_sws_op_list_output(ops); + if (read) + add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, read); + add_desc_read_write(&buf_desc[nb_desc++], &p->src_rep, write); ff_vk_shader_add_descriptor_set(&s->vkctx, shd, buf_desc, nb_desc, 0, 0); GLSLC(0, void main() ); -- 2.52.0 >From 3f3ef8b24dfb000f49be9bc50425b1a1f11580a8 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Mon, 2 Mar 2026 00:30:18 +0100 Subject: [PATCH 07/13] swscale/ops_dispatch: avoid redundant ff_sws_op_list_update_comps() This is already called by compile_backend(), and nothing else in this file depends on accurate values. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/ops_dispatch.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c index 67ce225b82..64abea27f3 100644 --- a/libswscale/ops_dispatch.c +++ b/libswscale/ops_dispatch.c @@ -387,8 +387,6 @@ int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, ret = ff_sws_op_list_optimize(ops); if (ret < 0) return ret; - } else { - ff_sws_op_list_update_comps(ops); } return compile(graph, ops, dst, input, output); -- 2.52.0 >From c99c66c2911ea0ee66d4470c1e608e5d843ef64c Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Thu, 5 Mar 2026 18:30:02 +0100 Subject: [PATCH 08/13] swscale/ops_dispatch: print op list on successful compile Instead of once at the start of add_convert_pass(). This makes much more sense in light of the fact that we want to start e.g. splitting passes apart. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/graph.c | 4 +--- libswscale/ops_dispatch.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 8e8fb01f95..0901e8d984 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -598,10 +598,8 @@ static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n"); ff_sws_op_list_print(ctx, AV_LOG_DEBUG, AV_LOG_TRACE, ops); - av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n"); - ff_sws_op_list_optimize(ops); - ff_sws_op_list_print(ctx, AV_LOG_VERBOSE, AV_LOG_TRACE, ops); + ff_sws_op_list_optimize(ops); ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output); if (ret < 0) goto fail; diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c index 64abea27f3..0a6911f9b5 100644 --- a/libswscale/ops_dispatch.c +++ b/libswscale/ops_dispatch.c @@ -85,6 +85,8 @@ int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n", backend->name, out->block_size, out->over_read, out->over_write, out->cpu_flags); + + ff_sws_op_list_print(ctx, AV_LOG_VERBOSE, AV_LOG_TRACE, ops); return 0; } -- 2.52.0 >From 55d22400988dd7973c1ce9f04f03fd9bd1ad8d97 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Thu, 26 Feb 2026 15:29:45 +0100 Subject: [PATCH 09/13] swscale/graph: pass SWS_OP_FLAG_OPTIMIZE Instead of optimizing it with an explicit call. May enable more optimizations in the future. Signed-off-by: Niklas Haas <[email protected]> --- libswscale/graph.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 0901e8d984..65cc920588 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -599,8 +599,7 @@ static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n"); ff_sws_op_list_print(ctx, AV_LOG_DEBUG, AV_LOG_TRACE, ops); - ff_sws_op_list_optimize(ops); - ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output); + ret = ff_sws_compile_pass(graph, ops, SWS_OP_FLAG_OPTIMIZE, dst, input, output); if (ret < 0) goto fail; -- 2.52.0 >From af92e27fc45fc076fa6184778bc175761f6fe688 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Wed, 4 Mar 2026 15:53:33 +0100 Subject: [PATCH 10/13] tests/checkasm/sw_ops: fix exec.slice_h assignment This should match the number of lines. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- tests/checkasm/sw_ops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c index 6615f63354..aea183b820 100644 --- a/tests/checkasm/sw_ops.c +++ b/tests/checkasm/sw_ops.c @@ -30,9 +30,9 @@ #include "checkasm.h" enum { - LINES = 2, - NB_PLANES = 4, - PIXELS = 64, + NB_PLANES = 4, + PIXELS = 64, + LINES = 16, }; enum { @@ -174,7 +174,7 @@ static void check_ops(const char *report, const unsigned ranges[NB_PLANES], SwsOpExec exec = {0}; exec.width = PIXELS; - exec.height = exec.slice_h = 1; + exec.height = exec.slice_h = LINES; for (int i = 0; i < NB_PLANES; i++) { exec.in_stride[i] = sizeof(src0[i][0]); exec.out_stride[i] = sizeof(dst0[i][0]); -- 2.52.0 >From 8a2bf903db39470bc5dc9db7ea931aa68e0d5d4c Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Sun, 22 Feb 2026 19:30:34 +0100 Subject: [PATCH 11/13] swscale: restructure sws_scale_frame() slightly Results in IMHO slightly more readable code flow, and will be useful in an upcoming commit (that adds logic to ref individual planes). Signed-off-by: Niklas Haas <[email protected]> --- libswscale/swscale.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 94d9102f97..c7d8ef309d 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -1368,28 +1368,21 @@ int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src) if (!src->data[0]) return 0; - if (c->graph[FIELD_TOP]->noop && - (!c->graph[FIELD_BOTTOM] || c->graph[FIELD_BOTTOM]->noop) && - src->buf[0] && !dst->buf[0] && !dst->data[0]) - { - /* Lightweight refcopy */ - ret = frame_ref(dst, src); - if (ret < 0) - return ret; - } else { - if (!dst->data[0]) { - ret = av_frame_get_buffer(dst, 0); - if (ret < 0) - return ret; - } + const SwsGraph *top = c->graph[FIELD_TOP]; + const SwsGraph *bot = c->graph[FIELD_BOTTOM]; + if (dst->data[0]) /* user-provided buffers */ + goto process_frame; - for (int field = 0; field < 2; field++) { - SwsGraph *graph = c->graph[field]; - ff_sws_graph_run(graph, dst, src); - if (!graph->dst.interlaced) - break; - } - } + if (src->buf[0] && top->noop && (!bot || bot->noop)) + return frame_ref(dst, src); + + ret = av_frame_get_buffer(dst, 0); + if (ret < 0) + return ret; + +process_frame: + for (int field = 0; field < (bot ? 2 : 1); field++) + ff_sws_graph_run(c->graph[field], dst, src); return 0; } -- 2.52.0 >From d35cda4e0df6d5c05024a8c0a7fe37ab1f590e0a Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Fri, 6 Mar 2026 18:47:48 +0100 Subject: [PATCH 12/13] swscale: add sanity clear on AVFrame *dst Before allocating/referencing buffers, make sure these fields are in a defined state. Signed-off-by: Niklas Haas <[email protected]> --- libswscale/swscale.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libswscale/swscale.c b/libswscale/swscale.c index c7d8ef309d..911d10390c 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -1373,6 +1373,12 @@ int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src) if (dst->data[0]) /* user-provided buffers */ goto process_frame; + /* Sanity */ + memset(dst->buf, 0, sizeof(dst->buf)); + memset(dst->data, 0, sizeof(dst->data)); + memset(dst->linesize, 0, sizeof(dst->linesize)); + dst->extended_data = dst->data; + if (src->buf[0] && top->noop && (!bot || bot->noop)) return frame_ref(dst, src); -- 2.52.0 >From 92ccfab959648124bf594ba9cc063091ce9eeaa8 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Fri, 6 Mar 2026 18:48:57 +0100 Subject: [PATCH 13/13] swscale: don't pointlessly loop over NULL buffers This array is defined as contiguous. Signed-off-by: Niklas Haas <[email protected]> --- libswscale/swscale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 911d10390c..b3387fff6f 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -1327,7 +1327,7 @@ static int frame_ref(AVFrame *dst, const AVFrame *src) /* ref the buffers */ for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { if (!src->buf[i]) - continue; + break; dst->buf[i] = av_buffer_ref(src->buf[i]); if (!dst->buf[i]) return AVERROR(ENOMEM); -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
