swscale/filters: hard-code radius for trivial kernels

box() and triangle() have well-defined, trivially verifiable numerical
inverses.

We could actually pre-compute and hard-code the numerical inverse of all
non-parametric kernels, but I'm a bit reluctant to do this as I have plans to
adjust the value of SWS_MAX_REDUCE_CUTOFF based on the desired bit depth of the
output, which makes a hard-coding approach unfeasible.

(It would also be a brittle solution that may break whenever we extend the
scaler configuration API, as well as making it harder to add new filters)

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas
2026-04-22 17:07:15 +02:00
parent 837cf8e38f
commit c1ff2c24b5
+20 -2
View File
@@ -154,7 +154,11 @@ static bool validate_params(const SwsFilterFunction *fun, SwsScaler scaler)
}
}
static double filter_radius(const SwsFilterFunction *fun)
/**
* Numerically estimate the last intersection between the function value
* and the cutoff domain [-SWS_MAX_REDUCE_CUTOFF, SWS_MAX_REDUCE_CUTOFF].
*/
static double est_filter_radius(const SwsFilterFunction *fun)
{
const double bound = fun->radius;
const double step = 1e-2;
@@ -225,7 +229,21 @@ int ff_sws_filter_generate(void *log, const SwsFilterParams *params,
if (fun.radius < 0.0) /* tunable width kernels like lanczos */
fun.radius = fun.params[0];
const double radius = filter_radius(&fun) * stretch;
double radius;
switch (scaler) {
case SWS_SCALE_POINT:
radius = 0.5;
break;
case SWS_SCALE_BILINEAR:
radius = 1.0 - SWS_MAX_REDUCE_CUTOFF;
break;
default:
/* Numerically estimate radius of nontrivial or parametric kernels */
radius = est_filter_radius(&fun);
break;
}
radius *= stretch;
int filter_size = ceil(radius * 2.0);
filter_size = FFMIN(filter_size, params->src_size);
av_assert0(filter_size >= 1);