From 32ba5c13de9183750796de3175dfc98b6f92a0e5 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sat, 28 Mar 2026 18:01:25 +0100 Subject: [PATCH] swscale/ops_chain: split generic setup helpers into op-specific helpers This has the side benefit of not relying on the q2pixel macro to avoid division by zero, since we can now explicitly avoid operating on undefined clear values. Signed-off-by: Niklas Haas --- libswscale/aarch64/ops.c | 6 +++-- libswscale/ops_chain.c | 45 +++++++++++++++++++++++++++--------- libswscale/ops_chain.h | 9 ++++---- libswscale/ops_tmpl_common.c | 8 +++---- libswscale/ops_tmpl_int.c | 4 ++-- libswscale/x86/ops.c | 8 +++---- 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/libswscale/aarch64/ops.c b/libswscale/aarch64/ops.c index 4b204efd08..753aef51ae 100644 --- a/libswscale/aarch64/ops.c +++ b/libswscale/aarch64/ops.c @@ -143,12 +143,14 @@ static int aarch64_setup(SwsOpList *ops, int block_size, int n, } break; case SWS_OP_CLEAR: + ff_sws_setup_clear(&(const SwsImplParams) { .op = op }, out); + break; case SWS_OP_MIN: case SWS_OP_MAX: - ff_sws_setup_q4(&(const SwsImplParams) { .op = op }, out); + ff_sws_setup_clamp(&(const SwsImplParams) { .op = op }, out); break; case SWS_OP_SCALE: - ff_sws_setup_q(&(const SwsImplParams) { .op = op }, out); + ff_sws_setup_scale(&(const SwsImplParams) { .op = op }, out); break; case SWS_OP_LINEAR: return aarch64_setup_linear(p, op, out); diff --git a/libswscale/ops_chain.c b/libswscale/ops_chain.c index 65bd3029d3..a2cfd3aaf9 100644 --- a/libswscale/ops_chain.c +++ b/libswscale/ops_chain.c @@ -263,33 +263,56 @@ int ff_sws_op_compile_tables(SwsContext *ctx, const SwsOpTable *const tables[], #define q2pixel(type, q) ((q).den ? (type) (q).num / (q).den : 0) -int ff_sws_setup_u8(const SwsImplParams *params, SwsImplResult *out) +int ff_sws_setup_shift(const SwsImplParams *params, SwsImplResult *out) { out->priv.u8[0] = params->op->c.u; return 0; } -int ff_sws_setup_q(const SwsImplParams *params, SwsImplResult *out) +int ff_sws_setup_scale(const SwsImplParams *params, SwsImplResult *out) { const SwsOp *op = params->op; + const AVRational factor = op->c.q; switch (op->type) { - case SWS_PIXEL_U8: out->priv.u8[0] = q2pixel(uint8_t, op->c.q); return 0; - case SWS_PIXEL_U16: out->priv.u16[0] = q2pixel(uint16_t, op->c.q); return 0; - case SWS_PIXEL_U32: out->priv.u32[0] = q2pixel(uint32_t, op->c.q); return 0; - case SWS_PIXEL_F32: out->priv.f32[0] = q2pixel(float, op->c.q); return 0; + case SWS_PIXEL_U8: out->priv.u8[0] = q2pixel(uint8_t, factor); break; + case SWS_PIXEL_U16: out->priv.u16[0] = q2pixel(uint16_t, factor); break; + case SWS_PIXEL_U32: out->priv.u32[0] = q2pixel(uint32_t, factor); break; + case SWS_PIXEL_F32: out->priv.f32[0] = q2pixel(float, factor); break; default: return AVERROR(EINVAL); } + + return 0; } -int ff_sws_setup_q4(const SwsImplParams *params, SwsImplResult *out) +int ff_sws_setup_clamp(const SwsImplParams *params, SwsImplResult *out) { const SwsOp *op = params->op; for (int i = 0; i < 4; i++) { + const AVRational limit = op->c.q4[i]; switch (op->type) { - case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, op->c.q4[i]); break; - case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, op->c.q4[i]); break; - case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, op->c.q4[i]); break; - case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, op->c.q4[i]); break; + case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, limit); break; + case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, limit); break; + case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, limit); break; + case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, limit); break; + default: return AVERROR(EINVAL); + } + } + + return 0; +} + +int ff_sws_setup_clear(const SwsImplParams *params, SwsImplResult *out) +{ + const SwsOp *op = params->op; + for (int i = 0; i < 4; i++) { + const AVRational value = op->c.q4[i]; + if (!value.den) + continue; + switch (op->type) { + case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, value); break; + case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, value); break; + case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, value); break; + case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, value); break; default: return AVERROR(EINVAL); } } diff --git a/libswscale/ops_chain.h b/libswscale/ops_chain.h index f9afe2b733..fc0cd930f8 100644 --- a/libswscale/ops_chain.h +++ b/libswscale/ops_chain.h @@ -140,10 +140,11 @@ typedef struct SwsOpEntry { bool (*check)(const SwsImplParams *params); /* optional, return true if supported */ } SwsOpEntry; -/* Setup helpers */ -int ff_sws_setup_u8(const SwsImplParams *params, SwsImplResult *out); -int ff_sws_setup_q(const SwsImplParams *params, SwsImplResult *out); -int ff_sws_setup_q4(const SwsImplParams *params, SwsImplResult *out); +/* Setup helpers for common/trivial operation types */ +int ff_sws_setup_shift(const SwsImplParams *params, SwsImplResult *out); +int ff_sws_setup_scale(const SwsImplParams *params, SwsImplResult *out); +int ff_sws_setup_clamp(const SwsImplParams *params, SwsImplResult *out); +int ff_sws_setup_clear(const SwsImplParams *params, SwsImplResult *out); static inline void ff_op_priv_free(SwsOpPriv *priv) { diff --git a/libswscale/ops_tmpl_common.c b/libswscale/ops_tmpl_common.c index 5a0a399f32..3817a437e5 100644 --- a/libswscale/ops_tmpl_common.c +++ b/libswscale/ops_tmpl_common.c @@ -85,7 +85,7 @@ DECL_IMPL(clear##_##X##Y##Z##W) } \ \ DECL_ENTRY(clear##_##X##Y##Z##W, \ - .setup = ff_sws_setup_q4, \ + .setup = ff_sws_setup_clear, \ .op = SWS_OP_CLEAR, \ .flexible = true, \ .unused = { !X, !Y, !Z, !W }, \ @@ -141,13 +141,13 @@ DECL_PATTERN(max) WRAP_COMMON_PATTERNS(min, .op = SWS_OP_MIN, - .setup = ff_sws_setup_q4, + .setup = ff_sws_setup_clamp, .flexible = true, ); WRAP_COMMON_PATTERNS(max, .op = SWS_OP_MAX, - .setup = ff_sws_setup_q4, + .setup = ff_sws_setup_clamp, .flexible = true, ); @@ -172,7 +172,7 @@ DECL_PATTERN(scale) WRAP_COMMON_PATTERNS(scale, .op = SWS_OP_SCALE, - .setup = ff_sws_setup_q, + .setup = ff_sws_setup_scale, .flexible = true, ); diff --git a/libswscale/ops_tmpl_int.c b/libswscale/ops_tmpl_int.c index 960d0d9527..b010513bc5 100644 --- a/libswscale/ops_tmpl_int.c +++ b/libswscale/ops_tmpl_int.c @@ -383,13 +383,13 @@ DECL_PATTERN(rshift) WRAP_COMMON_PATTERNS(lshift, .op = SWS_OP_LSHIFT, - .setup = ff_sws_setup_u8, + .setup = ff_sws_setup_shift, .flexible = true, ); WRAP_COMMON_PATTERNS(rshift, .op = SWS_OP_RSHIFT, - .setup = ff_sws_setup_u8, + .setup = ff_sws_setup_shift, .flexible = true, ); #endif /* BIT_DEPTH != 8 */ diff --git a/libswscale/x86/ops.c b/libswscale/x86/ops.c index 51c65c8ebb..734ffbac27 100644 --- a/libswscale/x86/ops.c +++ b/libswscale/x86/ops.c @@ -185,20 +185,20 @@ static int setup_shift(const SwsImplParams *params, SwsImplResult *out) #define DECL_MIN_MAX(EXT) \ DECL_COMMON_PATTERNS(F32, min##EXT, \ .op = SWS_OP_MIN, \ - .setup = ff_sws_setup_q4, \ + .setup = ff_sws_setup_clamp, \ .flexible = true, \ ); \ \ DECL_COMMON_PATTERNS(F32, max##EXT, \ .op = SWS_OP_MAX, \ - .setup = ff_sws_setup_q4, \ + .setup = ff_sws_setup_clamp, \ .flexible = true, \ ); #define DECL_SCALE(EXT) \ DECL_COMMON_PATTERNS(F32, scale##EXT, \ .op = SWS_OP_SCALE, \ - .setup = ff_sws_setup_q, \ + .setup = ff_sws_setup_scale, \ .flexible = true, \ ); @@ -941,7 +941,7 @@ static void normalize_clear(SwsOp *op) int i; } c; - ff_sws_setup_q4(&(const SwsImplParams) { .op = op }, &res); + ff_sws_setup_clear(&(const SwsImplParams) { .op = op }, &res); for (int i = 0; i < 4; i++) { if (!op->c.q4[i].den)