mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-06-04 22:50:24 +00:00
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
|
||
|---|---|---|
| .. | ||
| api | ||
| checkasm | ||
| fate | ||
| filtergraphs | ||
| maps | ||
| ref | ||
| streamgroups | ||
| .gitignore | ||
| audiogen.c | ||
| audiomatch.c | ||
| base64.c | ||
| copycooker.sh | ||
| extended.ffconcat | ||
| fate-run.sh | ||
| fate-valgrind.supp | ||
| fate.sh | ||
| Makefile | ||
| md5.sh | ||
| refcmp-metadata.awk | ||
| reference.pnm | ||
| rotozoom.c | ||
| simple1.ffconcat | ||
| simple2.ffconcat | ||
| test.ffmeta | ||
| tiny_psnr.c | ||
| tiny_ssim.c | ||
| utils.c | ||
| videogen.c | ||