Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#8056 closed defect (duplicate)

Convert BMP/JPG to YUV420p video color shift, but not PNG

Reported by: fireattack Owned by:
Priority: normal Component: undetermined
Version: unspecified Keywords:
Cc: rwijnsma@xs4all.nl Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:

The color become slightly yellow when converting 24-bit BMP to limited range video (YUV420p).

255,255,255 will become 252,254,252 or similar.

Not reproducible with pixel-exact png file (also attached).
Not reproducible with yuvj420p

How to reproduce:

F:\sync\Personal research\!视频\ffmpeg color bug>ffmpeg -loop 1 -i bmp.bmp -vf scale=out_color_matrix=bt709 -color_primaries 1 -co
lor_trc 1 -colorspace 1 -t 30 -pix_fmt yuv420p -y -report bmp.mp4
ffmpeg started on 2019-08-03 at 04:33:18
Report written to "ffmpeg-20190803-043318.log"
ffmpeg version N-94433-gf60b1211b2 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 9.1.1 (GCC) 20190716
  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-libtwolam
e --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enabl
e-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libsp
eex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nven
c --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
  libavutil      56. 32.100 / 56. 32.100
  libavcodec     58. 55.100 / 58. 55.100
  libavformat    58. 30.100 / 58. 30.100
  libavdevice    58.  9.100 / 58.  9.100
  libavfilter     7. 58.100 /  7. 58.100
  libswscale      5.  6.100 /  5.  6.100
  libswresample   3.  6.100 /  3.  6.100
  libpostproc    55.  6.100 / 55.  6.100
[bmp_pipe @ 0000000000383100] Stream #0: not enough frames to estimate rate; consider increasing probesize
Input #0, bmp_pipe, from 'bmp.bmp':
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: bmp, bgr24, 1920x1080, 25 tbr, 25 tbn, 25 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (bmp (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[libx264 @ 0000000000386c40] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0000000000386c40] profile High, level 4.0, 4:2:0, 8-bit
[libx264 @ 0000000000386c40] 264 - core 158 r2984 3759fcb - H.264/MPEG-4 AVC codec - Copyleft 2003-2019 - http://www.videolan.org/
x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 c
hroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0
 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open
_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0
qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'bmp.mp4':
  Metadata:
    encoder         : Lavf58.30.100
    Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p(bt709), 1920x1080, q=-1--1, 25 fps, 12800 tbn, 25 tbc
    Metadata:
      encoder         : Lavc58.55.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
frame=  750 fps= 75 q=-1.0 Lsize=      64kB time=00:00:29.88 bitrate=  17.5kbits/s speed=2.98x
video:54kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 17.723938%
[libx264 @ 0000000000386c40] frame I:3     Avg QP:12.00  size:   670
[libx264 @ 0000000000386c40] frame P:189   Avg QP:14.11  size:    77
[libx264 @ 0000000000386c40] frame B:558   Avg QP:18.33  size:    68
[libx264 @ 0000000000386c40] consecutive B-frames:  0.8%  0.0%  0.0% 99.2%
[libx264 @ 0000000000386c40] mb I  I16..4:  2.0% 98.0%  0.0%
[libx264 @ 0000000000386c40] mb P  I16..4:  0.0%  0.0%  0.0%  P16..4:  0.0%  0.0%  0.0%  0.0%  0.0%    skip:100.0%
[libx264 @ 0000000000386c40] mb B  I16..4:  0.0%  0.0%  0.0%  B16..8:  0.0%  0.0%  0.0%  direct: 0.0%  skip:100.0%  L0: 0.0% L1:10
0.0% BI: 0.0%
[libx264 @ 0000000000386c40] 8x8 transform intra:97.8%
[libx264 @ 0000000000386c40] coded y,uvDC,uvAC intra: 0.0% 0.0% 0.0% inter: 0.0% 0.0% 0.0%
[libx264 @ 0000000000386c40] i16 v,h,dc,p:  0% 78% 22%  0%
[libx264 @ 0000000000386c40] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu:  0% 67% 33%  0%  0%  0%  0%  0%  0%
[libx264 @ 0000000000386c40] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu:  0% 72% 28%  0%  0%  0%  0%  0%  0%
[libx264 @ 0000000000386c40] i8c dc,h,v,p: 98%  1%  0%  0%
[libx264 @ 0000000000386c40] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0000000000386c40] kb/s:14.61

Patches should be submitted to the ffmpeg-devel mailing list and not this bug tracker.

Attachments (3)

png.png (22.5 KB ) - added by fireattack 2 years ago.
png image (no issue)
bmp.bmp.7z (1.1 KB ) - added by fireattack 2 years ago.
bmp sample file (compressed)
colortest_hd.7z (23.5 KB ) - added by fireattack 2 years ago.
To test the color range and bt601/709 conversion

Download all attachments as: .zip

Change History (10)

by fireattack, 2 years ago

Attachment: png.png added

png image (no issue)

by fireattack, 2 years ago

Attachment: bmp.bmp.7z added

bmp sample file (compressed)

comment:1 by fireattack, 2 years ago

Summary: Convert BMP to YUV420p video color shift, but not PNGConvert BMP/JPG to YUV420p video color shift, but not PNG

This bug also happens to JPG.

And the video encoding method doesn't seem to matter, tried HEVC, same result.

comment:2 by CoRoNe, 2 years ago

Cc: rwijnsma@xs4all.nl added

I'm not an expert in this field of work, but I can confirm the "yellowness" (if it's really a bug).

While 'png.png' is marked as rgb24(pc) (full range), 'bmp.bmp' is marked as just bgr24 (no range set). So apparently you have to convert to full range yourself.

https://ffmpeg.org/ffmpeg-all.html#Codec-Options:

color_range integer (decoding/encoding,video)
If used as input parameter, it serves as a hint to the decoder, which color_range the input has.

ffmpeg -loop 1 -color_range pc -i bmp.bmp -t 10 -pix_fmt yuv420p -preset ultrafast bmp.mp4

With -color_range pc 'bmp.bmp' is now marked as bgr24(pc), but the "bmp decoder" seems to be ignorant of this hint, because 'bmp.mp4' is still 252,255,252 (#FCFFFC).

What does work which I found out:

ffmpeg -loop 1 -i bmp.bmp -t 10 -vf scale=out_range=pc -pix_fmt yuv420p -preset ultrafast bmp.mp4
ffmpeg -loop 1 -i bmp.bmp -t 10 -vf colorspace=iall=bt709:all=bt709:format=yuv420p -preset ultrafast bmp.mp4

(I noticed the first command to be twice as fast than the second)

Btw, there's no need for intermediate files. You can use FFplay:

ffplay -f lavfi color=white:s=1280x720,format=bgr24,format=yuv420p                      # 252,255,252 (#FCFFFC)
ffplay -f lavfi color=white:s=1280x720,format=rgb24,format=yuv420p                      # 255,255,255 (#FFFFFF)
ffplay -f lavfi color=white:s=1280x720,format=bgr24,scale=out_range=pc,format=yuv420p   # 255,255,255 (#FFFFFF)

comment:3 by Carl Eugen Hoyos, 2 years ago

Resolution: duplicate
Status: newclosed

Looks like a duplicate of ticket #979.

by fireattack, 2 years ago

Attachment: colortest_hd.7z added

To test the color range and bt601/709 conversion

comment:4 by fireattack, 2 years ago

CoRoNe, thank you very much for your help!

As marked by cehoyos, the reason seems to be input rgb24 vs. bgr24, so color range is not an issue (the range conversion is already done with "-pix_fmt yuv420p").

Actually, your first command:

ffmpeg -loop 1 -i bmp.bmp -t 10 -vf scale=out_range=pc -pix_fmt yuv420p -preset ultrafast bmp.mp4

Will clip the color range (instead of properly convert it), means colors between 236-255 will all crush to pure white. I think it may not actually fix the yellowish issue.

The second one

ffmpeg -loop 1 -i bmp.bmp -t 10 -vf colorspace=iall=bt709:all=bt709:format=yuv420p -preset ultrafast bmp.mp4

does fix the color shift issue, I suppose it is because we moved rgb->yuv conversion to colorspace filter from the problematic swscale I suppose?

But it does NOT convert from bgr24 to BT.709 properly, means pure red (255,0,0) in original will become 255,24,0 now. I tried to fix this, but I can't seem to make it work with colorspace filter.

I think you can fix it by changing to -vf colorspace=iall=bt601-6-625:all=bt709:format=yuv420p

If you want to do any further testing, please use the newly attached test image (I should use this sample image to begin with, but I want to highlight the yellow-ish issue with a pure white image).

Last edited 2 years ago by fireattack (previous) (diff)

comment:5 by CoRoNe, 2 years ago

Will clip the color range (instead of properly convert it), means colors between 236-255 will all crush to pure white.

I only tested the samples you provided, the color white. I haven't looked at other colors.

I suppose it is because we moved rgb->yuv conversion to colorspace filter from the problematic swscale

Who's we? Are you a FFmpeg developer?

Is this issue really 8 years old already? In all those years not a single FFmpeg coder was able to fix this?!

comment:6 by pdr0, 2 years ago

It's been "fixed" a long time ago with the proper flags. It's just not well documented

The popular way to do it these days is zscale . Format comes last in the filter chain, the earlier flags get passed to it

ffmpeg -i colortest_hd.bmp -vf zscale=matrix=709,format=yuv420p -c:v libx264 -crf 18 -x264opts colormatrix=bt709 zscale709.mp4

It's a good practice to flag the colormatrix as 709 (doesn't affect the actual conversion, just metadata)

Acceptable rounding error for 8bit conversions should be +/-3 for YUV<=>RGB conversions

If using swscale, you need -sws_flags full_chroma_int+accurate_rnd to reduce the rounding errors (accurate_rnd is the important one)

ffmpeg -i colortest_hd.bmp -vf scale=out_color_matrix=bt709:flags=full_chroma_int+accurate_rnd,format=yuv420p -c:v libx264 -crf 18 -x264opts colormatrix=bt709 swscale709accurate_rnd.mp4

ffmpeg -i colortest_hd.bmp -vf scale=out_color_matrix=bt709,format=yuv420p -c:v libx264 -crf 18 -x264opts colormatrix=bt709 swscale709.mp4

As you see, "white" is 255,255,255 with the sws accurate_rnd flag, but discolored (252,255, 252) without.

Last edited 2 years ago by pdr0 (previous) (diff)

comment:7 by fireattack, 2 years ago

Thank you for your informative reply. These commands are definitely handy in future.

I think that swscale's bug (without flag) (#979) still should be fixed as it only happens to bgr24 but not rgb24, which means it isn't just an accuracy problem.

Note: See TracTickets for help on using tickets.