PR #25200 opened by nmoinvaz URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25200 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25200.patch
`compute_sat_hue_metrics8()` called `hypotf()`, `atan2f()`, `floorf()` and `fmodf()` for every chroma sample. Both results depend only on the 8-bit (u, v) pair, so this builds two 64K tables once with the same expressions, and the per-sample loop becomes two loads. Higher bit depths keep the current code. The frames and every `lavfi.signalstats.*` value are identical to master for yuv420p, yuv422p, yuv444p and yuvj420p input, and with the `tout`, `vrep` and `brng` options. | 1080p, 48 frames, 1 thread | master | this PR | time | |---|---|---|---| | yuv420p | 1.03 s | 0.28 s | -71% | | yuv444p | 3.52 s | 0.72 s | -79% | Measured on an i7-1185G7 with GCC 16. >From d00c185727d63cdae1c7c6c3c051a9b6b5e15b7a Mon Sep 17 00:00:00 2001 From: Nathan Moinvaziri <[email protected]> Date: Sun, 18 Oct 2026 13:33:09 -0700 Subject: [PATCH] avfilter/vf_signalstats: look up the saturation and hue of 8-bit chroma Every chroma sample called hypotf(), atan2f(), floorf() and fmodf(). Tables of both values for every 8-bit (u, v) pair, built once with the same expressions, keep the statistics identical and make the filter about 3.5 times faster on 4:2:0 input. --- libavfilter/vf_signalstats.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/libavfilter/vf_signalstats.c b/libavfilter/vf_signalstats.c index 5859b46478..b2e91da7be 100644 --- a/libavfilter/vf_signalstats.c +++ b/libavfilter/vf_signalstats.c @@ -24,6 +24,7 @@ #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/thread.h" #include "filters.h" enum FilterMode { @@ -87,11 +88,28 @@ static const AVOption signalstats_options[] = { AVFILTER_DEFINE_CLASS(signalstats); +/* saturation and hue of every 8-bit (u, v) pair, indexed by u << 8 | v */ +static uint8_t sat8[256 * 256]; +static int16_t hue8[256 * 256]; + +static av_cold void init_sat_hue8(void) +{ + for (int yuvu = 0; yuvu < 256; yuvu++) { + for (int yuvv = 0; yuvv < 256; yuvv++) { + sat8[yuvu << 8 | yuvv] = hypotf(yuvu - 128, yuvv - 128); // int or round? + hue8[yuvu << 8 | yuvv] = fmodf(floorf((180.f / M_PI) * atan2f(yuvu-128, yuvv-128) + 180.f), 360.f); + } + } +} + static av_cold int init(AVFilterContext *ctx) { + static AVOnce init_static_once = AV_ONCE_INIT; uint8_t r, g, b; SignalstatsContext *s = ctx->priv; + ff_thread_once(&init_static_once, init_sat_hue8); + if (s->outfilter != FILTER_NONE) s->filters |= 1 << s->outfilter; @@ -479,10 +497,9 @@ static int compute_sat_hue_metrics8(AVFilterContext *ctx, void *arg, int jobnr, for (j = slice_start; j < slice_end; j++) { for (i = 0; i < s->chromaw; i++) { - const int yuvu = p_u[i]; - const int yuvv = p_v[i]; - p_sat[i] = hypotf(yuvu - 128, yuvv - 128); // int or round? - ((int16_t*)p_hue)[i] = fmodf(floorf((180.f / M_PI) * atan2f(yuvu-128, yuvv-128) + 180.f), 360.f); + const int uv = p_u[i] << 8 | p_v[i]; + p_sat[i] = sat8[uv]; + ((int16_t*)p_hue)[i] = hue8[uv]; } p_u += lsz_u; p_v += lsz_v; -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
