Opened 5 years ago
Last modified 18 months ago
#7978 reopened defect
inaccurate conversion from YCbCr Narrow range to RGB Full range
Reported by: | cepesh | Owned by: | |
---|---|---|---|
Priority: | normal | Component: | undetermined |
Version: | unspecified | Keywords: | |
Cc: | Blocked By: | ||
Blocking: | Reproduced by developer: | no | |
Analyzed by developer: | no |
Description
Summary of the bug: inaccurate conversion from YCbCr Narrow range to RGB Full range
How to reproduce:
Command line: "C:\\tools\\ffmpeg-4.1.3\\bin\\ffmpeg.exe" -loglevel debug -report -s 3840x2160 -vcodec v210 -i YUV_pattern-2fr.v210 -vf "scale=in_color_matrix=bt2020:in_range=tv" -vframes 1 tiff_bug_00.tiff -y ffmpeg version 4.1.3 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 8.3.1 (GCC) 20190414 configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth libavutil 56. 22.100 / 56. 22.100 libavcodec 58. 35.100 / 58. 35.100 libavformat 58. 20.100 / 58. 20.100 libavdevice 58. 5.100 / 58. 5.100 libavfilter 7. 40.101 / 7. 40.101 libswscale 5. 3.100 / 5. 3.100 libswresample 3. 3.100 / 3. 3.100 libpostproc 55. 3.100 / 55. 3.100
100% White
Source YCbCr value = 0x03ac, 0x0200, 0x0200 (940, 512, 512)
Observed RGB value = 65283, 65283, 65283
Expected RGB value = 65535, 65535, 65535
58% White
Source YCbCr value = 0x023c, 0x0200, 0x0200 (572, 512, 512)
Observed RGB value = 37858, 37858, 37858
Expected RGB value = 38004, 38004, 38004
100% Magenta
Source YCbCr value = 0x015a, 0x343, 0x039c
Observed RGB value = 65280, 0, 65289
Expected RGB value = 65533, 0, 65535
Attachments (1)
Change History (14)
by , 5 years ago
Attachment: | 20190629-ffmpeg-bug.zip added |
---|
follow-up: 2 comment:1 by , 5 years ago
Priority: | important → normal |
---|---|
Version: | 4.1 → unspecified |
Please test current FFmpeg git head and provide the command line together with the complete, uncut console output to make this a valid ticket.
comment:2 by , 5 years ago
Replying to cehoyos:
Please test current FFmpeg git head and provide the command line together with the complete, uncut console output to make this a valid ticket.
Sure, no problem. Retested on N-94137-g89b96900fa
ffmpeg started on 2019-06-30 at 11:10:10 Report written to "ffmpeg-20190630-111010.log" Command line: "C:\\tools\\ffmpeg-20190629-89b9690-win64-static\\bin\\ffmpeg.exe" -loglevel debug -report -s 3840x2160 -vcodec v210 -i YUV_pattern-2fr.v210 -vf "scale=in_color_matrix=bt2020:in_range=tv" -vframes 1 tiff_bug_00.tiff -y ffmpeg version N-94137-g89b96900fa Copyright (c) 2000-2019 the FFmpeg developers built with gcc 9.1.1 (GCC) 20190621 configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt libavutil 56. 30.100 / 56. 30.100 libavcodec 58. 53.100 / 58. 53.100 libavformat 58. 28.101 / 58. 28.101 libavdevice 58. 7.100 / 58. 7.100 libavfilter 7. 55.100 / 7. 55.100 libswscale 5. 4.101 / 5. 4.101 libswresample 3. 4.100 / 3. 4.100 libpostproc 55. 4.100 / 55. 4.100 Splitting the commandline. Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'. Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'. Reading option '-s' ... matched as option 's' (set frame size (WxH or abbreviation)) with argument '3840x2160'. Reading option '-vcodec' ... matched as option 'vcodec' (force video codec ('copy' to copy stream)) with argument 'v210'. Reading option '-i' ... matched as input url with argument 'YUV_pattern-2fr.v210'. Reading option '-vf' ... matched as option 'vf' (set video filters) with argument 'scale=in_color_matrix=bt2020:in_range=tv'. Reading option '-vframes' ... matched as option 'vframes' (set the number of video frames to output) with argument '1'. Reading option 'tiff_bug_00.tiff' ... matched as output url. Reading option '-y' ... matched as option 'y' (overwrite output files) with argument '1'. Finished splitting the commandline. Parsing a group of options: global . Applying option loglevel (set logging level) with argument debug. Applying option report (generate a report) with argument 1. Applying option y (overwrite output files) with argument 1. Successfully parsed a group of options. Parsing a group of options: input url YUV_pattern-2fr.v210. Applying option s (set frame size (WxH or abbreviation)) with argument 3840x2160. Applying option vcodec (force video codec ('copy' to copy stream)) with argument v210. Successfully parsed a group of options. Opening an input file: YUV_pattern-2fr.v210. [NULL @ 000002c7c2a2b680] Opening 'YUV_pattern-2fr.v210' for reading [file @ 000002c7c2a2c700] Setting default whitelist 'file,crypto' [v210 @ 000002c7c2a2b680] Format v210 probed with size=2048 and score=50 [v210 @ 000002c7c2a2b680] Before avformat_find_stream_info() pos: 0 bytes read:32768 seeks:0 nb_streams:1 [v210 @ 000002c7c2a2b680] All info found [v210 @ 000002c7c2a2b680] Estimating duration from bitrate, this may be inaccurate [v210 @ 000002c7c2a2b680] After avformat_find_stream_info() pos: 22118400 bytes read:22118400 seeks:0 frames:1 Input #0, v210, from 'YUV_pattern-2fr.v210': Duration: 00:00:00.08, start: 0.000000, bitrate: 4423680 kb/s Stream #0:0, 1, 1/25: Video: v210, 1 reference frame, yuv422p10le, 3840x2160, 0/1, 4423680 kb/s, 25 tbr, 25 tbn, 25 tbc Successfully opened the file. Parsing a group of options: output url tiff_bug_00.tiff. Applying option vf (set video filters) with argument scale=in_color_matrix=bt2020:in_range=tv. Applying option vframes (set the number of video frames to output) with argument 1. Successfully parsed a group of options. Opening an output file: tiff_bug_00.tiff. Successfully opened the file. Stream mapping: Stream #0:0 -> #0:0 (v210 (native) -> tiff (native)) Press [q] to stop, [?] for help cur_dts is invalid st:0 (0) [init:0 i_done:0 finish:0] (this is harmless if it occurs once at the start per stream) detected 32 logical cores [Parsed_scale_0 @ 000002c7c2a34700] Setting 'in_color_matrix' to value 'bt2020' [Parsed_scale_0 @ 000002c7c2a34700] Setting 'in_range' to value 'tv' [Parsed_scale_0 @ 000002c7c2a34700] Setting 'flags' to value 'bicubic' [Parsed_scale_0 @ 000002c7c2a34700] w:iw h:ih flags:'bicubic' interl:0 [graph 0 input from stream 0:0 @ 000002c7c2a32d40] Setting 'video_size' to value '3840x2160' [graph 0 input from stream 0:0 @ 000002c7c2a32d40] Setting 'pix_fmt' to value '66' [graph 0 input from stream 0:0 @ 000002c7c2a32d40] Setting 'time_base' to value '1/25' [graph 0 input from stream 0:0 @ 000002c7c2a32d40] Setting 'pixel_aspect' to value '0/1' [graph 0 input from stream 0:0 @ 000002c7c2a32d40] Setting 'sws_param' to value 'flags=2' [graph 0 input from stream 0:0 @ 000002c7c2a32d40] Setting 'frame_rate' to value '25/1' [graph 0 input from stream 0:0 @ 000002c7c2a32d40] w:3840 h:2160 pixfmt:yuv422p10le tb:1/25 fr:25/1 sar:0/1 sws_param:flags=2 [format @ 000002c7c2a47880] Setting 'pix_fmts' to value 'rgb24|rgb48le|pal8|rgba|rgba64le|gray|ya8|gray16le|ya16le|monob|monow|yuv420p|yuv422p|yuv440p|yuv444p|yuv410p|yuv411p' [AVFilterGraph @ 000002c7c2a322c0] query_formats: 4 queried, 3 merged, 0 already done, 0 delayed [Parsed_scale_0 @ 000002c7c2a34700] picking rgb48le out of 17 ref:yuv422p10le alpha:0 [Parsed_scale_0 @ 000002c7c2a34700] w:3840 h:2160 fmt:yuv422p10le sar:0/1 -> w:3840 h:2160 fmt:rgb48le sar:0/1 flags:0x4 Output #0, image2, to 'tiff_bug_00.tiff': Metadata: encoder : Lavf58.28.101 Stream #0:0, 0, 1/25: Video: tiff, 1 reference frame, rgb48le, 3840x2160, 0/1, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc Metadata: encoder : Lavc58.53.100 tiff Clipping frame in rate conversion by 0.000008 No more output streams to write to, finishing. [image2 @ 000002c7c2a3e280] Opening 'tiff_bug_00.tiff' for writing [file @ 000002c7c2e6c880] Setting default whitelist 'file,crypto' [AVIOContext @ 000002c7c2a83580] Statistics: 0 seeks, 21 writeouts frame= 1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=0.103x video:5147kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown Input file #0 (YUV_pattern-2fr.v210): Input stream #0:0 (video): 1 packets read (22118400 bytes); 1 frames decoded; Total: 1 packets (22118400 bytes) demuxed Output file #0 (tiff_bug_00.tiff): Output stream #0:0 (video): 1 frames encoded; 1 packets muxed (5270238 bytes); Total: 1 packets (5270238 bytes) muxed 1 frames successfully decoded, 0 decoding errors [AVIOContext @ 000002c7c2a34940] Statistics: 22118400 bytes read, 0 seeks
comment:3 by , 5 years ago
Hi there. Is there any more information required from my side for this to go through your initial registration?
comment:4 by , 3 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
See downstream: https://github.com/sekrit-twc/zimg/issues/109
"found that you must add 'format=gbrp16le' after 'zscale'. Otherwise, FFmpeg instructs z.lib to perform a no-op conversion from YUV to YUV, and instead uses its internal code to convert to RGB. After I did this, I verified that I got '38004' when converting from '572'. This bug(?) exists in FFmpeg, not z.lib."
comment:5 by , 3 years ago
Okay, actually the real bug here is that the values inside YUV_pattern-2fr.v210 are not what you said they should be.
Check out: ffmpeg -video_size 3840x2160 -vcodec v210 -i YUV_pattern-2fr.v210 -vf extractplanes=y crazystuff.png
yuv422p10le that is used in v210 file are also a problem.
comment:6 by , 3 years ago
Resolution: | invalid |
---|---|
Status: | closed → reopened |
Okay, I was wrong, I used yuvview (hex view in settings) and your file is indeed using in hex 0x3ac 0x200 0x200. So the bug here is not about the scale: even normal production of a png will produce 65283 Y only png. I suppose the idea that 10 bit value in png 16 bit per component will be just multiply with 64 is wrong. Sigh.
comment:7 by , 3 years ago
Use zscale instead
ffmpeg -s 3840x2160 -vcodec v210 -i YUV_pattern-2fr.v210 -vf zscale=matrixin=2020_ncl,format=gbrp16le -an -frames:v 1 out_zscale.png
100% white
65535, 65535, 65535
58% white
38004, 38004, 38004
100% Magenta
65533, 0, 65535
comment:8 by , 3 years ago
So, yes. I was able to confirm the bug:
ffmpeg.exe -video_size 3840x2160 -vcodec v210 -i YUV_pattern-2fr.v210 -vf scale=in_color_matrix=bt2020:in_range=tv,format=gbrp10le -f rawvideo rawle.rgb
(Do not use gbrp10be, since YUVview does not support BE.)
Open in YUVview, first select it being GBR (not RGB, select it is planar, select it is 10 bit) then select it is 3840x2160, it will crash at least once. Then if you will activate hex viewer in settings and zoom in you will get the hex values. Indeed white is 1020 10 bit, just like in 16 bit png (65283 / 64 =1020). Now, as described in ITU docs it is normal to use 1020 instead of 1023 since that is what naïve implementation will give. WOW.
comment:9 by , 3 years ago
Same happens with BT.601 matrix too with white color that is of course not caring about matrix. And BT.709.
comment:10 by , 19 months ago
I've hit the same issue in https://stackoverflow.com/questions/75260266, and found this ticket while trying to answer it, and I was wondering is there were anybody currently working on updating this inside ffmpeg? Is there any way I can help?
I suppose the idea that 10 bit value in png 16 bit per component will be just multiply with 64 is wrong.
At least in my mind, all standards I know of assume 255 (8-bit) = 1023 (10-bit) = 65535 (16-bit) = 100% = 1.0 (float)...
For 10-bit signals the multiplication factor should therefore be slightly different (65535/1023 = 64.0616...). In binary math I think the closest is (v << 6) + (v >> 4)
with v
a 10-bit integer).
(Using a factor of 64 is indeed a common misconception: the roundoff error is at most 1 if the final output is downconverted to a smaller integer type, so it's not easily visible, especially combined with lossy encoding and chroma subsampling.)
Now, as described in ITU docs it is normal to use 1020 instead of 1023 since that is what naïve implementation will give.
Could you clarify which ITU recommendation (and which version) you were referring to, if you still have it?
At least in the case of ITU-R BT.2020-2, I believe this is an incorrect interpretation ; this recommendation only provides specifications for narrow-range signals, for which Y'=940 corresponds to 100% signal, and the maximum value of 1019 is still valid but maps to a signal that is much greater than 100%. It does not cover full-range conversions like what PNG images are supposed to contain.
ITU-R BT.2100 does add an explicit definition for full-range signals, where 100% = 1023 (in 10-bit), which seem to correspond to the usual assumption that 100% = maximum of the data type.
comment:11 by , 19 months ago
At least in my mind, all standards I know of assume 255 (8-bit) = 1023 (10-bit) = 65535 (16-bit) = 100% = 1.0 (float)..
That is not the case for limited range YCbCr or limited RGB (only for full RGB and YCBCr), they have values reserved for sync, 0 and 255 for 8 bit and 0, 1, 2, 3 and 1019, 1020, 1021, 1023 for all 3 components. We know from BT.601 the consensus is to use the following: 255.75 means that first 8 bit is before the dot and last two bits are after the dot, after is encoded as follows: 00 is 00, 25 is 01, 50 is 10, 75 is 11. If we omit .00 that means last two bits are 0, which means 8 bit 255 value is 255.00, not 255.75, with 255.75 being all ones. From this we see that if we say black level is at 16.00, it means that it is all ones for 8 bit, but for 10 bit it has last two bits as 0. In fact that means that in bitshift < 4 is used to convert from 8 bit to 10 bit, which is the case for 1.0 float value Y 235 and Cb, Cr 240 too. 240 * 4 is 960.
Ideally 960 was supposed to be 962, but ITU-R/CCIR decided otherwise.
They simply pad the 8bit number with two trailing zeros to convert to 8bit space. It's not perfect, but it's fast, simple and good enough (wasting 0.3% of available steps).
What also should be considered is that if we convert from RGB to 8 bit or 10 bit (limited) YCBCR it will not be just a bitshift between those, as clarified here: https://en.wikipedia.org/wiki/SMPTE_color_bars
So here we have a bug. We know to decode 10 bit YCbCr we need 12 bit RGB, so for white it should be 4095, 4095, 4095 already, then to convert from these RGB values to 16 bit RGB we need to (4095+1) * 4 -1 and we get 65536.
comment:12 by , 18 months ago
Possibly related.
(1) create 16-bit PNG filled with peak white
convert -size 3840x2160 xc:white png48:white.png
(2) convert to YUV 10-bit
ffmpeg -i white.png -pix_fmt yuv444p10 -f rawvideo white.yuv
The resulting Y code values are equal to 943. They should be equal to 940 = (219 * 1 + 16) * 4.
comment:13 by , 18 months ago
The resulting Y code values are equal to 943. They should be equal to 940
Yes, you are correct. Indeed, in RGB as it is full range in png, we have the 100% white at 65535 (counting from 0). Though again, the source of the image is using 2.2 gAMA (not even sRGB) and yuv will be assuming BT.709 transfer...
Zip archive includes both the source V210 file (2 frames inside. resolution 3840x2160) and TIFF output