mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-06-11 08:13:06 +00:00
avfilter/vf_unsharp: fix amount scaling in the high-bit-depth path
The 16-bit kernel is dispatched for every non-8-bit pixel format
(9/10/12/16-bit content, all stored in uint16_t). It's supposed to
undo the Q16 scaling that set_filter_param() applies to `amount`:
fp->amount = amount * 65536.0;
but the shift written in the kernel is `>> (8+nbits)`, which for the
nbits=16 instantiation of the macro comes out to `>> 24` instead of
`>> 16`. Because of this, on any non-8-bit input, unsharp applies ~1/256
of the user's requested strength and is effectively a no-op. The
8-bit kernel (nbits=8) happens to be correct because 8+8 == 16.
This commit also widens the intermediate product to int64 before the
shift, to avoid a potential overflow. Take a 16-bit pixel at the
edge of a sharp white/black region, with the user-facing `amount`
set to its declared maximum of 5.0.
*srx = 65535
blur = 32768
diff = *srx - blur = 32767
amount_q16 = 5.0 * 65536 = 327680
Then the kernel computes:
product = diff * amount_q16
= 32767 * 327680 = 10,737,090,560 (~1.07e10)
which overflows INT32_MAX. Widening to int64 keeps the
multiplication in range; the subsequent `>> 16` brings it back to
sample range and the final cast to int32 is then safe. The widening
is a semantic no-op for 8/9/10/12-bit content where the product
always fits in int32 (worst case at 12-bit: 4095 * 327680 ~ 1.34e9).
Introduced by ee792ebe08 (2019-11-08, "avfilter/vf_unsharp: add 10bit
support"). The fate-filter-unsharp-yuv420p10 reference added in the
same series was generated from the broken kernel and is regenerated
here. fate-filter-unsharp (8-bit) is unaffected.
Repro:
python3 -c "import numpy as np; y=np.tile(np.where(np.arange(128)//8 & 1, 512, 256).astype('<u2'), (128,1)); c=np.full((64,64), 512, '<u2'); open('in.yuv','wb').write(y.tobytes()+c.tobytes()*2)"
ffmpeg -f rawvideo -pix_fmt yuv420p10le -s 128x128 -i in.yuv \
-lavfi "split=2[a][b];[b]unsharp=la=1[bs];[a][bs]psnr" \
-f null - 2>&1 | grep PSNR
Before: `PSNR y:66.50 ...` -- the filter is effectively a no-op,
so the sharpened output matches the input almost exactly.
After: `PSNR y:28.27 ...` -- the filter actually sharpens, so
output and input differ as expected.
Signed-off-by: Nil Fons Miret <nilf@netflix.com>
Made-with: Cursor
This commit is contained in:
committed by
Kyle Swanson
co-authored by
Kyle Swanson
parent
68ea660d83
commit
e294b390a0
@@ -157,9 +157,9 @@ static int name##_##nbits(AVFilterContext *ctx, void *arg, int jobnr, int nb_job
|
||||
const uint##nbits##_t *srx = src - steps_y * src_stride + x - steps_x; \
|
||||
uint##nbits##_t *dsx = dst - steps_y * dst_stride + x - steps_x; \
|
||||
\
|
||||
res = (int32_t)*srx + ((((int32_t) * srx - \
|
||||
(int32_t)((tmp1 + halfscale) >> scalebits)) * amount) >> (8+nbits)); \
|
||||
*dsx = av_clip_uint##nbits(res); \
|
||||
res = (int32_t)*srx + (int32_t)(((int64_t)((int32_t)*srx - \
|
||||
(int32_t)((tmp1 + halfscale) >> scalebits)) * amount) >> 16); \
|
||||
*dsx = av_clip_uintp2(res, s->bitdepth); \
|
||||
} \
|
||||
} \
|
||||
if (y >= 0) { \
|
||||
|
||||
@@ -3,23 +3,23 @@
|
||||
#codec_id 0: rawvideo
|
||||
#dimensions 0: 320x240
|
||||
#sar 0: 1/1
|
||||
0, 0, 0, 1, 230400, 0x5166b2b0
|
||||
0, 1, 1, 1, 230400, 0x1fcc8e0e
|
||||
0, 2, 2, 1, 230400, 0xce04db47
|
||||
0, 3, 3, 1, 230400, 0xc25661af
|
||||
0, 4, 4, 1, 230400, 0x727f06aa
|
||||
0, 5, 5, 1, 230400, 0x2e0f9cc5
|
||||
0, 6, 6, 1, 230400, 0x407fb93b
|
||||
0, 7, 7, 1, 230400, 0xc19c2087
|
||||
0, 8, 8, 1, 230400, 0xacacb223
|
||||
0, 9, 9, 1, 230400, 0x1277e355
|
||||
0, 10, 10, 1, 230400, 0xcd36c65d
|
||||
0, 11, 11, 1, 230400, 0x6c530182
|
||||
0, 12, 12, 1, 230400, 0x803b2da3
|
||||
0, 13, 13, 1, 230400, 0x82638dc2
|
||||
0, 14, 14, 1, 230400, 0x2064904b
|
||||
0, 15, 15, 1, 230400, 0xce3a7092
|
||||
0, 16, 16, 1, 230400, 0x374abb39
|
||||
0, 17, 17, 1, 230400, 0xf8b37d16
|
||||
0, 18, 18, 1, 230400, 0xb3d1c642
|
||||
0, 19, 19, 1, 230400, 0xc9b392d1
|
||||
0, 0, 0, 1, 230400, 0xccb5ffac
|
||||
0, 1, 1, 1, 230400, 0x6aed4ef7
|
||||
0, 2, 2, 1, 230400, 0xc7bc3502
|
||||
0, 3, 3, 1, 230400, 0x2a7b9fa5
|
||||
0, 4, 4, 1, 230400, 0x29cf1fe7
|
||||
0, 5, 5, 1, 230400, 0x1b457849
|
||||
0, 6, 6, 1, 230400, 0x42fd4a9e
|
||||
0, 7, 7, 1, 230400, 0xccec0881
|
||||
0, 8, 8, 1, 230400, 0x9b6cca80
|
||||
0, 9, 9, 1, 230400, 0xee3d5ff1
|
||||
0, 10, 10, 1, 230400, 0x794d9319
|
||||
0, 11, 11, 1, 230400, 0x5196b793
|
||||
0, 12, 12, 1, 230400, 0x239d7933
|
||||
0, 13, 13, 1, 230400, 0x02ea92ee
|
||||
0, 14, 14, 1, 230400, 0x111b2c9b
|
||||
0, 15, 15, 1, 230400, 0x5fbf8810
|
||||
0, 16, 16, 1, 230400, 0x96afa114
|
||||
0, 17, 17, 1, 230400, 0x3b587382
|
||||
0, 18, 18, 1, 230400, 0xb6aa9d42
|
||||
0, 19, 19, 1, 230400, 0xd463c17e
|
||||
|
||||
Reference in New Issue
Block a user