PR #25246 opened by SurbhiAgarwal1 URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25246 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25246.patch
Fixes #25234 ## Summary For input formats deeper than 8 bits, `prec[c]` points directly to `ref->data[c]`. Previously, `get_wsse()` hard-coded the stride of `rec` to `s->plane_width[c]`, ignoring `ref->linesize[c]`. When the reference frame's linesize carries padding (`linesize != 2 * plane_width`), rows after the first were read at incorrect offsets, resulting in near-zero XPSNR values (< 1 dB). This patch passes the per-plane stride of the reference frame into `get_wsse()`: `plane_width[c]` for packed 8-bit buffers and `ref->linesize[c] / bpp` for the high-bit-depth zero-copy path. Additionally, fixes a bug in `calc_squared_error_and_weight()` where the return value of `highds()` was discarded for `b_val > 1 && w_act <= 12`, leaving `sa_act` at 0 on narrow edge blocks. >From 32df5f5d92356d5d952cdd9a415c70bcdb17e162 Mon Sep 17 00:00:00 2001 From: Surbhi Agarwal <[email protected]> Date: Tue, 20 Oct 2026 09:42:17 +0530 Subject: [PATCH 1/2] avfilter/vf_xpsnr: use reference frame linesize for high-bit-depth stride For input formats deeper than 8 bits, prec[c] points directly to ref->data[c]. Previously, get_wsse() hard-coded the stride of rec to s->plane_width[c], ignoring ref->linesize[c]. When the reference frame linesize carries padding (linesize != 2 * plane_width), rows after the first were read at incorrect offsets. Pass the per-plane stride of the reference frame to get_wsse(): plane_width[c] for packed 8-bit buffers and ref->linesize[c] / bpp for high-bit-depth inputs. Fixes: #25234 Signed-off-by: Surbhi Agarwal <[email protected]> --- libavfilter/vf_xpsnr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libavfilter/vf_xpsnr.c b/libavfilter/vf_xpsnr.c index 89f4f279ba4..017a07ead46 100644 --- a/libavfilter/vf_xpsnr.c +++ b/libavfilter/vf_xpsnr.c @@ -267,7 +267,7 @@ static inline double get_avg_xpsnr (const double sqrt_wsse_val, const double su } static int get_wsse(AVFilterContext *ctx, int16_t **org, int16_t *org_m1, - int16_t *org_m2, int16_t **rec, uint64_t *const wsse64) + int16_t *org_m2, int16_t **rec, const int *stride_rec, uint64_t *const wsse64) { XPSNRContext *const s = ctx->priv; const uint32_t w = s->plane_width [0]; /* luma image width in pixels */ @@ -298,7 +298,7 @@ static int get_wsse(AVFilterContext *ctx, int16_t **org, int16_t *org_m1, const int16_t *p_org = org[0]; const uint32_t s_org = stride_org[0] / s->bpp; const int16_t *p_rec = rec[0]; - const uint32_t s_rec = s->plane_width[0]; + const uint32_t s_rec = stride_rec[0]; double wsse_luma = 0.0; for (y = 0; y < h; y += b) { /* calculate block SSE and perceptual weights */ @@ -349,7 +349,7 @@ static int get_wsse(AVFilterContext *ctx, int16_t **org, int16_t *org_m1, const int16_t *p_org = org[c]; const uint32_t s_org = stride_org[c] / s->bpp; const int16_t *p_rec = rec[c]; - const uint32_t s_rec = s->plane_width[c]; + const uint32_t s_rec = stride_rec[c]; const uint32_t w_pln = s->plane_width[c]; const uint32_t h_pln = s->plane_height[c]; @@ -405,6 +405,7 @@ static int do_xpsnr(FFFrameSync *fs) AVFrame *master, *ref = NULL; int16_t *porg [3]; int16_t *prec [3]; + int stride_rec [3]; uint64_t wsse64 [3] = {0, 0, 0}; double cur_xpsnr[3] = {INFINITY, INFINITY, INFINITY}; int c, ret_value, stride_org_bpp; @@ -445,6 +446,7 @@ static int do_xpsnr(FFFrameSync *fs) porg[c] = s->buf_org[c]; prec[c] = s->buf_rec[c]; + stride_rec[c] = s->plane_width[c]; for (int y = 0; y < s->plane_height[c]; y++) { for (int x = 0; x < s->plane_width[c]; x++) { @@ -457,11 +459,12 @@ static int do_xpsnr(FFFrameSync *fs) for (c = 0; c < s->num_comps; c++) { porg[c] = (int16_t *) master->data[c]; prec[c] = (int16_t *) ref->data[c]; + stride_rec[c] = ref->linesize[c] / s->bpp; } } /* extended perceptually weighted peak signal-to-noise ratio (XPSNR) value */ - ret_value = get_wsse(ctx, porg, s->buf_org_m1, s->buf_org_m2, prec, wsse64); + ret_value = get_wsse(ctx, porg, s->buf_org_m1, s->buf_org_m2, prec, stride_rec, wsse64); if ( ret_value < 0 ) return ret_value; /* an error here means something went wrong earlier! */ -- 2.54.0 >From dadabe9ab4384db12bd530548c2aafebeba9d99b Mon Sep 17 00:00:00 2001 From: Surbhi Agarwal <[email protected]> Date: Tue, 20 Oct 2026 09:43:13 +0530 Subject: [PATCH 2/2] avfilter/vf_xpsnr: fix discarded return value of highds() When b_val > 1 and w_act <= 12, the return value of highds() was discarded, leaving sa_act at 0 for edge blocks. Signed-off-by: Surbhi Agarwal <[email protected]> --- libavfilter/vf_xpsnr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavfilter/vf_xpsnr.c b/libavfilter/vf_xpsnr.c index 017a07ead46..71e1f2fb7dd 100644 --- a/libavfilter/vf_xpsnr.c +++ b/libavfilter/vf_xpsnr.c @@ -194,7 +194,7 @@ static inline double calc_squared_error_and_weight (XPSNRContext const *s, if (w_act > 12) sa_act = s->dsp.highds_func(x_act, y_act, w_act, h_act, o_m0, o); else - highds(x_act, y_act, w_act, h_act, o_m0, o); + sa_act = highds(x_act, y_act, w_act, h_act, o_m0, o); } else { /* <=HD highpass without downsampling */ for (int y = y_act; y < h_act; y++) { for (int x = x_act; x < w_act; x++) { -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
