<p>Apparently FFmpeg doesn't set input color attributes correctly for BMP input (probably because the file doesn't contain that metadata) and the BMP decoder doesn't check for manually flagged attributes. However, we can force it using the format filter.</p>

<pre><code>ffmpeg -i 000.bmp -vf format=rgb24 -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 first.mp4
</code></pre>

CC BY-SA 3.0
2016-11-25T15:32:02.330Z
This works perfectly! It gets the same result as using a PNG input. Thank you so much! Still, this is kinda crazy because BMP files can *only* be RGB24, nothing else...
Nayuki
CC BY-SA 3.0
2016-11-25T15:40:56.150Z
According to the decoder, BMPs can have pixel format of an 8-bit palette or 5-bit RGB or 6-bit G..etc (also, can have alpha). But yes, colorspace is RGB. The decoder is originally from 2005 and its the decoder's job to populate the AVFrame struct passed on to filters with relevant attributes. Since BMP hasn't changed much & isn't used much, no one's bothered to retrofit the code with new flags added since.
Gyan
CC BY-SA 3.0
2016-11-25T07:59:46.983Z
2016-11-25T12:34:37.313Z
2016-11-25T12:34:37.313Z
Gyan
<p>When I encode a particular sequence of BMP image files to AVC/H.264, the colors get shifted. Why does this happen?</p>

<p>But if I convert the BMPs to PNGs before running ffmpeg, the video conversion appears correct. My source material is in BMPs, and would prefer not to manually convert everything to PNGs to perform the workaround.</p>

<hr>

<p>For the purpose of this question, I took the sequence of images and summarized them into these main colors being used:</p>

<p><a href="https://i.sstatic.net/PEowN.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/PEowN.png" alt="enter image description here"></a></p>

<p>First attempt at encoding (the pure white becomes noticeably green): <code>ffmpeg -i 000.bmp -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 first.mp4</code></p>

<p><a href="https://i.sstatic.net/w5YNB.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/w5YNB.png" alt="enter image description here"></a></p>

<p>Second attempt (even worse): <code>ffmpeg -i 000.bmp -vf "colormatrix=bt601:bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 second.mp4</code></p>

<p><a href="https://i.sstatic.net/5I7L6.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/5I7L6.png" alt="enter image description here"></a></p>

<p>Third attempt (too bright): <code>ffmpeg -i 000.bmp -vf "scale=in_range=full:in_color_matrix=bt709:out_range=full:out_color_matrix=bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 third.mp4</code></p>

<p><a href="https://i.sstatic.net/xKJta.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/xKJta.png" alt="enter image description here"></a></p>

<p>However, using a PNG version of the same input image works great: <code>ffmpeg -i 000.png -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 fourth.mp4</code></p>

<p><a href="https://i.sstatic.net/QwdPW.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/QwdPW.png" alt="enter image description here"></a></p>

<hr>

<p>I am using the latest <a href="https://ffmpeg.zeranoe.com/builds/" rel="nofollow noreferrer">FFmpeg Windows</a> x86-64 build (2016-11-22 Git d316b21):</p>

<pre><code>C:\Temp&gt; ffmpeg.exe -version
ffmpeg version N-82597-gd316b21 Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 5.4.0 (GCC)
configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2
    --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig
    --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray
    --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme
    --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame
    --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264
    --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger
    --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora
    --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis
    --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264
    --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma
    --enable-decklink --enable-zlib
libavutil      55. 40.100 / 55. 40.100
libavcodec     57. 66.106 / 57. 66.106
libavformat    57. 58.100 / 57. 58.100
libavdevice    57.  2.100 / 57.  2.100
libavfilter     6. 67.100 /  6. 67.100
libswscale      4.  3.101 /  4.  3.101
libswresample   2.  4.100 /  2.  4.100
libpostproc    54.  2.100 / 54.  2.100
</code></pre>

<p>To rephrase my question, how can I convert the sequence of BMP images to an H.264 video without unwanted color shifts?</p>

CC BY-SA 3.0
2016-11-25T05:25:48.150Z
I'm note sure, so please confirm before I consider this as an answer. Please try with '-vcodec libx264rgb' instead of '-vcodec libx264'
RawBean
CC BY-SA 3.0
2016-11-25T06:08:26.997Z
Given that the title of the question is about a color shift when encoding to YUV format, how will encoding to RGB address the issue. The issue here is to correctly and fully specify the attributes of the source, so that swscale can correctly transform it. Also needed is to flag the output stream for lazy/sloppy players.
Gyan
CC BY-SA 3.0
2016-11-25T06:09:30.037Z
To the OP. how did you convert BMPs to PNG? And how were the BMPs generated?
Gyan
CC BY-SA 3.0
2016-11-25T07:03:27.973Z
@Mulvya For my [MCVE](http://stackoverflow.com/help/mcve) in this question, I generated the BMPs by hand in MS Paint. I converted to PNG using IrfanView. Looking at the files in a hex editor, the BMP has no color profile or related metadata. The PNG appears to have a gAMA chunk and sRGB chunk added by default.
Nayuki
CC BY-SA 3.0
2016-11-25T07:11:32.760Z
@RawBean Interesting suggestion. Using `-vcodec libx264rgb -profile:v high444` (minus -pix_fmt), I get a video with perfect colors with *zero* deviation. However it is only playable in MPC-HC, not Windows Explorer or Mozilla Firefox. I think it would be good to stay within H.264 main profile.
Nayuki
CC BY-SA 4.0
2019-10-30T22:22:50.553Z
@RawBean Aftertrying different things for several hours, using `libx264rgb` instread of `libx264` fixed the issue for me. Thanks so much!!
étale-cohomology
<video><ffmpeg><encoding><colorspace>
FFmpeg BMP to YUV x264 color shift
Nayuki
# FFmpeg BMP to YUV x264 color shift

(Asked by: username_0 on 2016-11-24)

When I encode a particular sequence of BMP image files to AVC/H.264, the colors get shifted. Why does this happen?
But if I convert the BMPs to PNGs before running ffmpeg, the video conversion appears correct. My source material is in BMPs, and would prefer not to manually convert everything to PNGs to perform the workaround.

For the purpose of this question, I took the sequence of images and summarized them into these main colors being used:

First attempt at encoding (the pure white becomes noticeably green): ffmpeg -i 000.bmp -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 first.mp4

Second attempt (even worse): ffmpeg -i 000.bmp -vf "colormatrix=bt601:bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 second.mp4

Third attempt (too bright): ffmpeg -i 000.bmp -vf "scale=in_range=full:in_color_matrix=bt709:out_range=full:out_color_matrix=bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 third.mp4

However, using a PNG version of the same input image works great: ffmpeg -i 000.png -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 fourth.mp4


I am using the latest FFmpeg Windows x86-64 build (2016-11-22 Git d316b21):
C:\Temp> ffmpeg.exe -version
ffmpeg version N-82597-gd316b21 Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 5.4.0 (GCC)
configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2
    --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig
    --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray
    --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme
    --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame
    --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264
    --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger
    --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora
    --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis
    --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264
    --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma
    --enable-decklink --enable-zlib
libavutil      55. 40.100 / 55. 40.100
libavcodec     57. 66.106 / 57. 66.106
libavformat    57. 58.100 / 57. 58.100
libavdevice    57.  2.100 / 57.  2.100
libavfilter     6. 67.100 /  6. 67.100
libswscale      4.  3.101 /  4.  3.101
libswresample   2.  4.100 /  2.  4.100
libpostproc    54.  2.100 / 54.  2.100

To rephrase my question, how can I convert the sequence of BMP images to an H.264 video without unwanted color shifts?

**Tags:** video, ffmpeg, encoding, colorspace

> **Comments:**
> **username_1**: I'm note sure, so please confirm before I consider this as an answer. Please try with '-vcodec libx264rgb' instead of '-vcodec libx264'  
> **username_2**: Given that the title of the question is about a color shift when encoding to YUV format, how will encoding to RGB address the issue. The issue here is to correctly and fully specify the attributes of the source, so that swscale can correctly transform it. Also needed is to flag the output stream for lazy/sloppy players.  
> **username_2**: To the OP. how did you convert BMPs to PNG? And how were the BMPs generated?  
> **username_0**: @Mulvya For my [MCVE](http://stackoverflow.com/help/mcve) in this question, I generated the BMPs by hand in MS Paint. I converted to PNG using IrfanView. Looking at the files in a hex editor, the BMP has no color profile or related metadata. The PNG appears to have a gAMA chunk and sRGB chunk added by default.  
> **username_0**: @username_1 Interesting suggestion. Using `-vcodec libx264rgb -profile:v high444` (minus -pix_fmt), I get a video with perfect colors with *zero* deviation. However it is only playable in MPC-HC, not Windows Explorer or Mozilla Firefox. I think it would be good to stay within H.264 main profile.  
> **username_3**: @username_1 Aftertrying different things for several hours, using `libx264rgb` instread of `libx264` fixed the issue for me. Thanks so much!!  

---

## 1 answers

### Answer by username_2 on 2016-11-25. Score: 3 | Accepted answer

Apparently FFmpeg doesn't set input color attributes correctly for BMP input (probably because the file doesn't contain that metadata) and the BMP decoder doesn't check for manually flagged attributes. However, we can force it using the format filter.
ffmpeg -i 000.bmp -vf format=rgb24 -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 first.mp4

> **Comments:**
> **username_0**: This works perfectly! It gets the same result as using a PNG input. Thank you so much! Still, this is kinda crazy because BMP files can *only* be RGB24, nothing else...  
> **username_2**: According to the decoder, BMPs can have pixel format of an 8-bit palette or 5-bit RGB or 6-bit G..etc (also, can have alpha). But yes, colorspace is RGB. The decoder is originally from 2005 and its the decoder's job to populate the AVFrame struct passed on to filters with relevant attributes. Since BMP hasn't changed much & isn't used much, no one's bothered to retrofit the code with new flags added since.  

---

