This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 814f862832359165f7835d0cfa007b6ffd43a742 Author: Niklas Haas <[email protected]> AuthorDate: Fri Mar 6 19:19:28 2026 +0100 Commit: Niklas Haas <[email protected]> CommitDate: Sat Mar 28 18:50:14 2026 +0100 swscale/graph: add scaling ops when required The question of whether to do vertical or horizontal scaling first is a tricky one. There are several valid philosophies: 1. Prefer horizontal scaling on the smaller pixel size, since this lowers the cost of gather-based kernels. 2. Prefer minimizing the number of total filter taps, i.e. minimizing the size of the intermediate image. 3. Prefer minimizing the number of rows horizontal scaling is applied to. Empirically, I'm still not sure which approach is best overall, and it probably depends at least a bit on the exact filter kernels in use. But for now, I opted to implement approach 3, which seems to work well. I will re-evaluate this once the filter kernels are actually finalized. The 'scale' in 'libswscale' can now stand for 'scaling'. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/graph.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index f65f338229..1c36ea3957 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -553,11 +553,75 @@ static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src, return init_legacy_subpass(graph, sws, input, output); } -/********************* - * Format conversion * - *********************/ +/********************************* + * Format conversion and scaling * + *********************************/ #if CONFIG_UNSTABLE +static SwsScaler get_scaler_fallback(SwsContext *ctx) +{ + if (ctx->scaler != SWS_SCALE_AUTO) + return ctx->scaler; + + /* Backwards compatibility with legacy flags API */ + if (ctx->flags & SWS_BILINEAR) { + return SWS_SCALE_BILINEAR; + } else if (ctx->flags & (SWS_BICUBIC | SWS_BICUBLIN)) { + return SWS_SCALE_BICUBIC; + } else if (ctx->flags & SWS_POINT) { + return SWS_SCALE_POINT; + } else if (ctx->flags & SWS_AREA) { + return SWS_SCALE_AREA; + } else if (ctx->flags & SWS_GAUSS) { + return SWS_SCALE_GAUSSIAN; + } else if (ctx->flags & SWS_SINC) { + return SWS_SCALE_SINC; + } else if (ctx->flags & SWS_LANCZOS) { + return SWS_SCALE_LANCZOS; + } else if (ctx->flags & SWS_SPLINE) { + return SWS_SCALE_SPLINE; + } else { + return SWS_SCALE_AUTO; + } +} + +static int add_filter(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, + SwsOpType filter, int src_size, int dst_size) +{ + if (src_size == dst_size) + return 0; /* no-op */ + + SwsFilterParams params = { + .scaler = get_scaler_fallback(ctx), + .src_size = src_size, + .dst_size = dst_size, + }; + + for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++) + params.scaler_params[i] = ctx->scaler_params[i]; + + SwsFilterWeights *kernel; + int ret = ff_sws_filter_generate(ctx, ¶ms, &kernel); + if (ret == AVERROR(ENOTSUP)) { + /* Filter size exceeds limit; cascade with geometric mean size */ + int mean = sqrt((int64_t) src_size * dst_size); + if (mean == src_size || mean == dst_size) + return AVERROR_BUG; /* sanity, prevent infinite loop */ + ret = add_filter(ctx, type, ops, filter, src_size, mean); + if (ret < 0) + return ret; + return add_filter(ctx, type, ops, filter, mean, dst_size); + } else if (ret < 0) { + return ret; + } + + return ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = filter, + .filter.kernel = kernel, + }); +} + static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, SwsPass *input, SwsPass **output) @@ -572,10 +636,6 @@ static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, if (!(ctx->flags & SWS_UNSTABLE)) goto fail; - /* The new format conversion layer cannot scale for now */ - if (src->width != dst->width || src->height != dst->height) - goto fail; - /* The new code does not yet support alpha blending */ if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA && ctx->alpha_blend != SWS_ALPHA_BLEND_NONE) @@ -593,6 +653,19 @@ static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete); if (ret < 0) goto fail; + + /** + * Always perform horizontal scaling first, since it's much more likely to + * benefit from small integer optimizations; we should maybe flip the order + * here if we're downscaling the vertical resolution by a lot, though. + */ + ret = add_filter(ctx, type, ops, SWS_OP_FILTER_H, src->width, dst->width); + if (ret < 0) + goto fail; + ret = add_filter(ctx, type, ops, SWS_OP_FILTER_V, src->height, dst->height); + if (ret < 0) + goto fail; + ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete); if (ret < 0) goto fail; _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
