PR #25757 opened by Ramiro Polla (ramiro) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25757 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25757.patch
Range only applies to integer formats, so float formats should always be full range. This series documents that, then fixes the places in legacy swscale that still treated float gray as limited range. >From 3fd675f8fe7e067812a09be938615823dc1a8268 Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Thu, 29 Oct 2026 19:43:15 +0100 Subject: [PATCH 1/7] avutil/pixfmt: document color range for floating point formats The narrow and full range definitions only exist for integer representations: H.273 (VideoFullRangeFlag), BT.709, BT.2020 and BT.2100 all specify them as equations on n-bit integer code values, and none of them define range for floating point. Floating point samples hold the normalized signal E directly, and may lie outside of its nominal range (e.g. HDR highlights above 1.0, out-of-gamut colors below 0.0). This matches other implementations: zimg applies pixel_range to integer formats only, and VapourSynth uses fixed float bounds regardless of _Range (Y in [0, 1], chroma centered on 0). Since AVFrame and AVCodecContext still carry a range for these formats, document that it should be set to AVCOL_RANGE_UNSPECIFIED, matching what libavfilter already does for them, and that readers must treat it as full range whatever its value, since some decoders tag these formats as AVCOL_RANGE_JPEG. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Ramiro Polla <[email protected]> --- libavcodec/avcodec.h | 5 +++++ libavutil/frame.h | 5 +++++ libavutil/pixfmt.h | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index bb654ec5a6f..de99df778d8 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -678,6 +678,11 @@ typedef struct AVCodecContext { * output format. * - decoding: Set by libavcodec, can be set by the user to propagate the * color range to components reading from the decoder context. + * + * @note Floating point pixel formats are always full range. For them, + * this should be set to AVCOL_RANGE_UNSPECIFIED, and must be + * treated as full range when reading, whatever its value. See + * AVColorRange. */ enum AVColorRange color_range; diff --git a/libavutil/frame.h b/libavutil/frame.h index 1fd296aa835..40a51294d6c 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -726,6 +726,11 @@ typedef struct AVFrame { * MPEG vs JPEG YUV range. * - encoding: Set by user * - decoding: Set by libavcodec + * + * @note Floating point pixel formats are always full range. For them, + * this should be set to AVCOL_RANGE_UNSPECIFIED, and must be + * treated as full range when reading, whatever its value. See + * AVColorRange. */ enum AVColorRange color_range; diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index 750e05b644f..b0bf9524c9a 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -749,6 +749,10 @@ enum AVColorSpace { * - 'n' is the output bit depth. * - For additional definitions such as rounding and clipping to valid n * bit unsigned integer range, please refer to BT.2100 (Table 9). + * + * These definitions only apply to integer representations. Floating point + * representations hold 'E' directly, without any scaling or offset, and are + * not limited to its nominal range. */ enum AVColorRange { AVCOL_RANGE_UNSPECIFIED = 0, -- 2.54.0 >From 1ab7d2efb24d66ccf18c7328ea460cfce9de4c36 Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Sat, 31 Oct 2026 17:53:13 +0100 Subject: [PATCH 2/7] swscale: treat float gray formats as full range Legacy swscale was still reading float gray values as limited range, whereas swscale2 correctly ignores the range for float gray formats. Reproducible with sample EXR file with 2 levels of gray: $ ffmpeg -f lavfi \ -i "color=black:s=128x64,format=grayf32,geq=lum='if(lt(X,64),1,0.93)'" \ -frames:v 1 grayf32.exr Legacy only shows 1 level $ ffplay -sws_backends legacy grayf32.exr swscale2 shows the 2 levels $ ffplay -sws_backends c grayf32.exr Signed-off-by: Ramiro Polla <[email protected]> --- libswscale/utils.c | 9 +++++++++ tests/ref/fate/exr-ya-scanline-zip-half-12x8 | 2 +- tests/ref/fate/jpeg-mpf-gainmap | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libswscale/utils.c b/libswscale/utils.c index c148813cd14..2361bb94c0e 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -836,6 +836,15 @@ static int handle_jpeg(/* enum AVPixelFormat */ int *format) case AV_PIX_FMT_GRAY16BE: case AV_PIX_FMT_YA16BE: case AV_PIX_FMT_YA16LE: + /* Floating point formats */ + case AV_PIX_FMT_GRAYF16BE: + case AV_PIX_FMT_GRAYF16LE: + case AV_PIX_FMT_GRAYF32BE: + case AV_PIX_FMT_GRAYF32LE: + case AV_PIX_FMT_YAF16BE: + case AV_PIX_FMT_YAF16LE: + case AV_PIX_FMT_YAF32BE: + case AV_PIX_FMT_YAF32LE: return 1; default: return 0; diff --git a/tests/ref/fate/exr-ya-scanline-zip-half-12x8 b/tests/ref/fate/exr-ya-scanline-zip-half-12x8 index 6c07f198461..4861eda52fd 100644 --- a/tests/ref/fate/exr-ya-scanline-zip-half-12x8 +++ b/tests/ref/fate/exr-ya-scanline-zip-half-12x8 @@ -3,4 +3,4 @@ #codec_id 0: rawvideo #dimensions 0: 12x8 #sar 0: 1/1 -0, 0, 0, 1, 1536, 0xa33f5f69 +0, 0, 0, 1, 1536, 0x826d7637 diff --git a/tests/ref/fate/jpeg-mpf-gainmap b/tests/ref/fate/jpeg-mpf-gainmap index 2c2cadac2cf..17f3723651c 100644 --- a/tests/ref/fate/jpeg-mpf-gainmap +++ b/tests/ref/fate/jpeg-mpf-gainmap @@ -1,5 +1,5 @@ -a94724be0101759474066d233ef14001 *tests/data/fate/jpeg-mpf-gainmap.jpeg_mpf -5649 tests/data/fate/jpeg-mpf-gainmap.jpeg_mpf +dcf02a726b98394f2084bb83c3f45311 *tests/data/fate/jpeg-mpf-gainmap.jpeg_mpf +5607 tests/data/fate/jpeg-mpf-gainmap.jpeg_mpf #tb 0: 1/25 #media_type 0: video #codec_id 0: rawvideo @@ -11,7 +11,7 @@ a94724be0101759474066d233ef14001 *tests/data/fate/jpeg-mpf-gainmap.jpeg_mpf #dimensions 1: 64x48 #sar 1: 1/1 0, 0, 0, 1, 9216, 0xe5834dd7 -1, 0, 0, 1, 9216, 0x662fcc6a +1, 0, 0, 1, 9216, 0x23c5fae7 frame|stream_index=0 frame|stream_index=1|side_datum/gain_map_parameters:side_data_type=Gain map parameters|side_datum/gain_map_parameters:version=0|side_datum/gain_map_parameters:use_base_color_space=1|side_datum/gain_map_parameters:base_hdr_headroom=0/1|side_datum/gain_map_parameters:alternate_hdr_headroom=5895489/1048576|component_entry/rgb:gain_map_min=-3392315/4194304|component_entry/rgb:gain_map_max=13278945/2097152|component_entry/rgb:gamma=691797/1048576|component_entry/rgb:base_offset=1/64|component_entry/rgb:alternate_offset=1/64 stream_group|index=0|nb_streams=2|type=Gain Map (Split base rendition and gain map) -- 2.54.0 >From 704c10a50b1cb250e5d4a270fe68a37082153966 Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Thu, 29 Oct 2026 18:09:47 +0100 Subject: [PATCH 3/7] Revert "swscale/swscale: Do not crash on floats" This reverts commit d16a058dbc9974f5919da3315e8cb41f8e6102f0. The crashes it addressed came from init_range_convert_constants() deriving the range constants from a bit depth of 32. That had already been fixed at the source by 8ab40ca984 ("swscale: fix gray -> grayf32 SIGFPE"), which clamps the bit depth to 16 to match the 19-bit intermediates these outputs use, and which was committed before this one. Instead of fixing the computation, this commit disabled range conversion for all 32-bit outputs. This had no effect while float gray outputs were treated as limited range, but now that they are treated as full range, it leaves limited range input unexpanded in the float output. With the clamp in place, the 16-bit range converters handle these outputs correctly. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Ramiro Polla <[email protected]> --- libswscale/swscale.c | 2 +- tests/ref/fate/filter-pixdesc-grayf32be | 2 +- tests/ref/fate/filter-pixdesc-grayf32le | 2 +- tests/ref/fate/filter-pixfmts-copy | 4 ++-- tests/ref/fate/filter-pixfmts-crop | 4 ++-- tests/ref/fate/filter-pixfmts-field | 4 ++-- tests/ref/fate/filter-pixfmts-fieldorder | 4 ++-- tests/ref/fate/filter-pixfmts-hflip | 4 ++-- tests/ref/fate/filter-pixfmts-il | 4 ++-- tests/ref/fate/filter-pixfmts-null | 4 ++-- tests/ref/fate/filter-pixfmts-scale | 4 ++-- tests/ref/fate/filter-pixfmts-transpose | 4 ++-- tests/ref/fate/filter-pixfmts-vflip | 4 ++-- tests/ref/lavf/grayf32be.pfm | 4 ++-- tests/ref/lavf/grayf32le.pfm | 4 ++-- tests/ref/lavf/none.grayf32le.exr | 2 +- tests/ref/lavf/rle.grayf32le.exr | 2 +- tests/ref/lavf/zip1.grayf32le.exr | 2 +- tests/ref/lavf/zip16.grayf32le.exr | 2 +- 19 files changed, 31 insertions(+), 31 deletions(-) diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 05a59a5d330..a7715a79a96 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -653,7 +653,7 @@ av_cold void ff_sws_init_range_convert(SwsInternal *c) { c->lumConvertRange = NULL; c->chrConvertRange = NULL; - if (c->opts.src_range != c->opts.dst_range && !isAnyRGB(c->opts.dst_format) && c->dstBpc < 32) { + if (c->opts.src_range != c->opts.dst_range && !isAnyRGB(c->opts.dst_format)) { init_range_convert_constants(c); if (c->dstBpc <= 14) { if (c->opts.src_range) { diff --git a/tests/ref/fate/filter-pixdesc-grayf32be b/tests/ref/fate/filter-pixdesc-grayf32be index 171475483ad..2f870674f5d 100644 --- a/tests/ref/fate/filter-pixdesc-grayf32be +++ b/tests/ref/fate/filter-pixdesc-grayf32be @@ -1 +1 @@ -pixdesc-grayf32be 9b23c74e8e8ffae5d7c7e82bbf5929da +pixdesc-grayf32be f271715b20c9d6eb1315f0a47f0b0e5d diff --git a/tests/ref/fate/filter-pixdesc-grayf32le b/tests/ref/fate/filter-pixdesc-grayf32le index d598d123b4e..2a2b6522f98 100644 --- a/tests/ref/fate/filter-pixdesc-grayf32le +++ b/tests/ref/fate/filter-pixdesc-grayf32le @@ -1 +1 @@ -pixdesc-grayf32le 291f074a24c44799a1f437d1c55556f1 +pixdesc-grayf32le e611536308fa5f74e64dbf30c4d8513f diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy index 15e4aee8cf6..25e8a6c5863 100644 --- a/tests/ref/fate/filter-pixfmts-copy +++ b/tests/ref/fate/filter-pixfmts-copy @@ -59,8 +59,8 @@ gray16be 5b71eb9a890a3c52210512b9622231eb gray16le 7d159a5c1735ffe4ebd01f84ffffa2d7 gray9be 2bcfb9b929ed9fa0ed4577ed0500a7eb gray9le 0171e3a1dfa892fb881207d43ae54997 -grayf32be f3bf178835f8146aa09d1da94bba4d8a -grayf32le fb6ea85bfbc8cd21c51fc0e110197294 +grayf32be 1bbc4ae0407753553e802c5a740d62e6 +grayf32le 6982b2fd5319bcbcb185d1aa08ec8eae monob 8b04f859fee6a0be856be184acd7a0b5 monow 54d16d2c01abfd72ecdb5e51e283937c nv12 8e24feb2c544dc26a20047a71e4c27aa diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop index 09e0a1e9ea2..53b74ffbfbb 100644 --- a/tests/ref/fate/filter-pixfmts-crop +++ b/tests/ref/fate/filter-pixfmts-crop @@ -59,8 +59,8 @@ gray16be 9a87fd9facebf9858b61e2996a701a75 gray16le 8b23f96b32c91654f5d8698372c4fc6a gray9be 77a834b1795d540074a64d9fb6452b91 gray9le 1ef37496619ba80bfb870da6573178e6 -grayf32be cf40ec06a8abe54852b7f85a00549eec -grayf32le b672526c9da9c8959ab881f242f6890a +grayf32be 6a702a8e026b81692cda21b5704391d0 +grayf32le e80eaddbf234d6cbe9bad1692b778eaa nv12 92cda427f794374731ec0321ee00caac nv16 3264b16aaae554c21f052102b491c13b nv20be a69262f462f71973860ab08f2789ee6b diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field index 8ed99eb5751..9f30c636489 100644 --- a/tests/ref/fate/filter-pixfmts-field +++ b/tests/ref/fate/filter-pixfmts-field @@ -59,8 +59,8 @@ gray16be 3f9a4ee6683542a840a8767c4da2158a gray16le b258756e59051a2d0a51905df56d1c69 gray9be 2cf4a1297d5231917669df224712b582 gray9le 46c9cc0de8525d36ed6052afa70de6c3 -grayf32be 72fbfa47b2863658a8a80d588f23b3e7 -grayf32le 6b856bdbf2a2bfcd2bc7d50f109daaf0 +grayf32be 6c4c5e8a8c132ef8687bf8fa474c489a +grayf32le 4e9a3ed7c56218fc1df60aaeb3cf7a7e monob 2129cc72a484d7e10a44de9117aa9f80 monow 03d783611d265cae78293f88ea126ea1 nv12 16f7a46708ef25ebd0b72e47920cc11e diff --git a/tests/ref/fate/filter-pixfmts-fieldorder b/tests/ref/fate/filter-pixfmts-fieldorder index 3a0e28db5d5..2245eebc9e3 100644 --- a/tests/ref/fate/filter-pixfmts-fieldorder +++ b/tests/ref/fate/filter-pixfmts-fieldorder @@ -59,8 +59,8 @@ gray16be 507d141b00748b23457ae5c61c4ca548 gray16le d4327602da9343272ecb7ca5e9b43129 gray9be 2bf69a7bae4954221d9f7f18cd5bb390 gray9le c45eb848ab86f63f30ceb7206fb41be9 -grayf32be 1aa7960131f880c54fe3c77f13448674 -grayf32le 4029ac9d197f255794c1b9e416520fc7 +grayf32be c68bf0d74437d70a8d238bbf895b1dca +grayf32le d0c1066d3750739b433f5fbb218f53e7 nv16 085deb984ab986eb5cc961fe265e30c0 nv20be 16998bc4aa2bfa3255d115a0a19ad80e nv20le c8bd359ec00903dd2b5526b4d8ecb09f diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip index caa817caeeb..cfa86f776c8 100644 --- a/tests/ref/fate/filter-pixfmts-hflip +++ b/tests/ref/fate/filter-pixfmts-hflip @@ -59,8 +59,8 @@ gray16be 20fc0cc0894d2fca3d86dcdea47acc90 gray16le 50b8a0225c2866e7b16c56cb58efdf48 gray9be 7747115e0cb893bd62ddba43c2009cb7 gray9le f5a7332cb42857a87290f87b1ddbbc0e -grayf32be a69add7bbf892a71fe81b3b75982dbe2 -grayf32le 4563e176a35dc8a8a07e0829fad5eb88 +grayf32be 47b748257f49e6a0b28a5564addaff0f +grayf32le a965138bc51c3a4f8a9134631c34a355 nv12 801e58f1be5fd0b5bc4bf007c604b0b4 nv16 06ba714cb8b220c203f5898ef39abf93 nv20be 979181e11f7bb74ad2d891daeebb7649 diff --git a/tests/ref/fate/filter-pixfmts-il b/tests/ref/fate/filter-pixfmts-il index 71ca6160a68..dde63f7dd65 100644 --- a/tests/ref/fate/filter-pixfmts-il +++ b/tests/ref/fate/filter-pixfmts-il @@ -59,8 +59,8 @@ gray16be 06703c79bc5f2a19649ffd5920898174 gray16le 288f58021aa00237ebbf2b399ad19756 gray9be 1e398c2af40ea86f0db4998793e7a633 gray9le 43029010dad140bf06d71d5811dc3049 -grayf32be f36197c9e2ef5c50a995e980c1a37203 -grayf32le 8bf3d295c3ffd53da0e06d0702e7c1ca +grayf32be 89d482c3b638875f79e20899a5176535 +grayf32le a30835dd8e98166a018bd68c754e440d monob faba75df28033ba7ce3d82ff2a99ee68 monow 6e9cfb8d3a344c5f0c3e1d5e1297e580 nv12 3c3ba9b1b4c4dfff09c26f71b51dd146 diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null index 15e4aee8cf6..25e8a6c5863 100644 --- a/tests/ref/fate/filter-pixfmts-null +++ b/tests/ref/fate/filter-pixfmts-null @@ -59,8 +59,8 @@ gray16be 5b71eb9a890a3c52210512b9622231eb gray16le 7d159a5c1735ffe4ebd01f84ffffa2d7 gray9be 2bcfb9b929ed9fa0ed4577ed0500a7eb gray9le 0171e3a1dfa892fb881207d43ae54997 -grayf32be f3bf178835f8146aa09d1da94bba4d8a -grayf32le fb6ea85bfbc8cd21c51fc0e110197294 +grayf32be 1bbc4ae0407753553e802c5a740d62e6 +grayf32le 6982b2fd5319bcbcb185d1aa08ec8eae monob 8b04f859fee6a0be856be184acd7a0b5 monow 54d16d2c01abfd72ecdb5e51e283937c nv12 8e24feb2c544dc26a20047a71e4c27aa diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale index cf362676581..d6ea9496d37 100644 --- a/tests/ref/fate/filter-pixfmts-scale +++ b/tests/ref/fate/filter-pixfmts-scale @@ -59,8 +59,8 @@ gray16be 4be62cba0e89e8121fcfe257b8fd270f gray16le 74dac11c70aa42e7b782dba73cd8855d gray9be 82586e4dd7c141493dd445c900a7bdcb gray9le 787f5c48ad9008636ba78de2cade71e1 -grayf32be 5e4c715519f53c15f1345df90481e5f5 -grayf32le 2ff1b84023e820307b1ba7a9550115bc +grayf32be 5f41ae12f606c85b99772ce89606dbbd +grayf32le fbb4010a4fce44c8b133556410162017 monob f01cb0b623357387827902d9d0963435 monow 35c68b86c226d6990b2dcb573a05ff6b nv12 b118d24a3653fe66e5d9e079033aef79 diff --git a/tests/ref/fate/filter-pixfmts-transpose b/tests/ref/fate/filter-pixfmts-transpose index bc3173c1817..e4f87841789 100644 --- a/tests/ref/fate/filter-pixfmts-transpose +++ b/tests/ref/fate/filter-pixfmts-transpose @@ -59,8 +59,8 @@ gray16be 570c9f15778f767cd5cca8fb7908f119 gray16le b497d74284c38464e18cf5692c523a1c gray9be 6ef99621245fcc00806e520a0a4419d4 gray9le 6bbd43b7d385b5c3e299bee18a88f9e2 -grayf32be 823288e1ec497bb1f22c070e502e5272 -grayf32le 6e9ec0e1cac3617f3041e681afd2c575 +grayf32be 6d9f450742f24d969dd935f943e52b74 +grayf32le e6188ebafd89996fb264d1f6da592f34 nv12 1965e3826144686748f2f6b516fca5ba nv21 292adaf5271c5c8516b71640458c01f4 nv24 ea9de8b47faed722ee40182f89489beb diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip index 87a1b268e8a..8e6ea439b4a 100644 --- a/tests/ref/fate/filter-pixfmts-vflip +++ b/tests/ref/fate/filter-pixfmts-vflip @@ -59,8 +59,8 @@ gray16be 483c6e570d97fbed9e51a61212910632 gray16le 65d76c53eef28ba6e74990760c57f98a gray9be cd524d242f2ac6ea39ef4bb85c9691f3 gray9le 8a3264fc4192fcd9ca2008ca4782a451 -grayf32be c1ba5943a0d24d70e6a280f37e4f4593 -grayf32le 8e6c048a5b3b8b26d3a5ddfce255f3f6 +grayf32be 982544dfa8cfab9e0911cdf9fa652173 +grayf32le 41c495aeb4d2e2c8c8e36cc46f07097e monob 7810c4857822ccfc844d78f5e803269a monow 90a947bfcd5f2261e83b577f48ec57b1 nv12 261ebe585ae2aa4e70d39a10c1679294 diff --git a/tests/ref/lavf/grayf32be.pfm b/tests/ref/lavf/grayf32be.pfm index 3ce4ad51337..c1999bb796d 100644 --- a/tests/ref/lavf/grayf32be.pfm +++ b/tests/ref/lavf/grayf32be.pfm @@ -1,3 +1,3 @@ -d2c3a37f7bf52be25f3f56239b5fdd92 *tests/data/images/grayf32be.pfm/02.grayf32be.pfm +e215d84196bccbb649e55954fd5423dc *tests/data/images/grayf32be.pfm/02.grayf32be.pfm 405524 tests/data/images/grayf32be.pfm/02.grayf32be.pfm -tests/data/images/grayf32be.pfm/%02d.grayf32be.pfm CRC=0xe3fda443 +tests/data/images/grayf32be.pfm/%02d.grayf32be.pfm CRC=0x6e324f85 diff --git a/tests/ref/lavf/grayf32le.pfm b/tests/ref/lavf/grayf32le.pfm index 3a883ad2ac6..01a18ee72bb 100644 --- a/tests/ref/lavf/grayf32le.pfm +++ b/tests/ref/lavf/grayf32le.pfm @@ -1,3 +1,3 @@ -ea7aad8650d06c7cc8c80cc57cbac672 *tests/data/images/grayf32le.pfm/02.grayf32le.pfm +0dd9c6c475b28a91158acb316a493a93 *tests/data/images/grayf32le.pfm/02.grayf32le.pfm 405525 tests/data/images/grayf32le.pfm/02.grayf32le.pfm -tests/data/images/grayf32le.pfm/%02d.grayf32le.pfm CRC=0x5443a443 +tests/data/images/grayf32le.pfm/%02d.grayf32le.pfm CRC=0x03714f85 diff --git a/tests/ref/lavf/none.grayf32le.exr b/tests/ref/lavf/none.grayf32le.exr index 9db5bb78ef9..54dc59e9525 100644 --- a/tests/ref/lavf/none.grayf32le.exr +++ b/tests/ref/lavf/none.grayf32le.exr @@ -1 +1 @@ -tests/data/images/none.grayf32le.exr/%02d.none.grayf32le.exr CRC=0x5443a443 +tests/data/images/none.grayf32le.exr/%02d.none.grayf32le.exr CRC=0x03714f85 diff --git a/tests/ref/lavf/rle.grayf32le.exr b/tests/ref/lavf/rle.grayf32le.exr index 5f44e019378..5846dc77ae2 100644 --- a/tests/ref/lavf/rle.grayf32le.exr +++ b/tests/ref/lavf/rle.grayf32le.exr @@ -1 +1 @@ -tests/data/images/rle.grayf32le.exr/%02d.rle.grayf32le.exr CRC=0x5443a443 +tests/data/images/rle.grayf32le.exr/%02d.rle.grayf32le.exr CRC=0x03714f85 diff --git a/tests/ref/lavf/zip1.grayf32le.exr b/tests/ref/lavf/zip1.grayf32le.exr index c74f2aed4de..db601f45bc5 100644 --- a/tests/ref/lavf/zip1.grayf32le.exr +++ b/tests/ref/lavf/zip1.grayf32le.exr @@ -1 +1 @@ -tests/data/images/zip1.grayf32le.exr/%02d.zip1.grayf32le.exr CRC=0x5443a443 +tests/data/images/zip1.grayf32le.exr/%02d.zip1.grayf32le.exr CRC=0x03714f85 diff --git a/tests/ref/lavf/zip16.grayf32le.exr b/tests/ref/lavf/zip16.grayf32le.exr index 25cb361be7e..c642e972d81 100644 --- a/tests/ref/lavf/zip16.grayf32le.exr +++ b/tests/ref/lavf/zip16.grayf32le.exr @@ -1 +1 @@ -tests/data/images/zip16.grayf32le.exr/%02d.zip16.grayf32le.exr CRC=0x5443a443 +tests/data/images/zip16.grayf32le.exr/%02d.zip16.grayf32le.exr CRC=0x03714f85 -- 2.54.0 >From d61ae1aeb6415e244549495ce9958c3ce54549b2 Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Sat, 31 Oct 2026 17:53:32 +0100 Subject: [PATCH 4/7] swscale/graph: do not flag an unspecified float or RGB range as incomplete Legacy swscale was still expecting range information and rejecting float formats that had the value unspecified under SWS_STRICT, whereas swscale2 correctly ignores the range for float gray formats. Reproducible with: $ ffmpeg -f lavfi \ -i "color=gray:s=64x64,format=grayf32,setparams=color_primaries=bt709:color_trc=bt709:colorspace=unknown" \ -frames:v 1 -sws_flags strict -sws_backends legacy -vf "scale=out_range=pc:out_chroma_loc=left,format=yuv420p" -f null - Signed-off-by: Ramiro Polla <[email protected]> --- libswscale/graph.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index f4ae0f5871d..abb107f1c6e 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -612,8 +612,10 @@ static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src, ff_sws_chroma_pos(src, &graph->incomplete, &sws->src_h_chr_pos, &sws->src_v_chr_pos); ff_sws_chroma_pos(dst, &graph->incomplete, &sws->dst_h_chr_pos, &sws->dst_v_chr_pos); - graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED; - graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED; + if (!isFloat(src->format) && !isAnyRGB(src->format)) + graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED; + if (!isFloat(dst->format) && !isAnyRGB(dst->format)) + graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED; /* Allow overriding chroma position with the legacy API */ legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned); -- 2.54.0 >From 3e715c24119326e713b0e1b3833fefe7d8b3ffe6 Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Wed, 4 Nov 2026 18:31:55 +0100 Subject: [PATCH 5/7] swscale/format: leave the range of float formats unspecified Color range does not apply to floating point formats. Float gray formats were already sanitized to AVCOL_RANGE_UNSPECIFIED, but float RGB formats were sanitized to AVCOL_RANGE_JPEG along with the rest of the RGB family. Move the float check out of the gray branch so that it applies to all float formats. This does not change any output: legacy swscale ignores the range of RGB formats, and the ops backend passes floats through regardless of range. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Ramiro Polla <[email protected]> --- libswscale/format.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libswscale/format.c b/libswscale/format.c index fbe2d813f9c..447f11a894f 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -315,12 +315,12 @@ static void sanitize_fmt(SwsFormat *fmt, const AVPixFmtDescriptor *desc) /* Grayscale formats */ fmt->color.prim = AVCOL_PRI_UNSPECIFIED; fmt->csp = AVCOL_SPC_UNSPECIFIED; - if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) - fmt->range = AVCOL_RANGE_UNSPECIFIED; - else - fmt->range = AVCOL_RANGE_JPEG; // FIXME: this restriction should be lifted + fmt->range = AVCOL_RANGE_JPEG; // FIXME: this restriction should be lifted } + if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) + fmt->range = AVCOL_RANGE_UNSPECIFIED; + switch (av_pix_fmt_desc_get_id(desc)) { case AV_PIX_FMT_YUVJ420P: case AV_PIX_FMT_YUVJ411P: -- 2.54.0 >From 9aa880397c7d712a78306d766cab336c9ffbe6ef Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Wed, 4 Nov 2026 19:26:51 +0100 Subject: [PATCH 6/7] swscale/utils: keep float gray formats full range in sws_setColorspaceDetails() sws_init_context() treats float gray formats as full range, but a later call to sws_setColorspaceDetails() could set them to limited range, enabling range conversion on float values. Force them to full range there as well, as is already done with a fixed range for RGB formats. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Ramiro Polla <[email protected]> --- libswscale/utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libswscale/utils.c b/libswscale/utils.c index 2361bb94c0e..eaa352a30c1 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -919,8 +919,12 @@ int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4], if(range_override_needed(sws->dst_format)) dstRange = 0; + else if (isFloat(sws->dst_format)) + dstRange = 1; /* float gray formats are always full range */ if(range_override_needed(sws->src_format)) srcRange = 0; + else if (isFloat(sws->src_format)) + srcRange = 1; if (sws->src_range != srcRange || sws->dst_range != dstRange || -- 2.54.0 >From ef6358018c03506f65011fc7f0d469e2447cf715 Mon Sep 17 00:00:00 2001 From: Ramiro Polla <[email protected]> Date: Wed, 4 Nov 2026 19:26:51 +0100 Subject: [PATCH 7/7] swscale/utils: remove the float exception from the unscaled range check It allowed the gray8 <-> grayf32 unscaled converters to be used while grayf32 was treated as limited range. Float gray formats are now always full range, like gray8, so the range check passes on its own. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- libswscale/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libswscale/utils.c b/libswscale/utils.c index eaa352a30c1..6aabce39aba 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -1700,7 +1700,7 @@ av_cold int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, /* unscaled special cases */ if (unscaled && !usesHFilter && !usesVFilter && (sws->src_range == sws->dst_range || isAnyRGB(dstFormat) || - isFloat(srcFormat) || isFloat(dstFormat) || isBayer(srcFormat))){ + isBayer(srcFormat))){ ff_get_unscaled_swscale(c); -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
