Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-11-25T15:32:02.330Z
Answers.Text: 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...
Answers.UserDisplayName: Nayuki
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-11-25T15:40:56.150Z
Answers.Text: 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.
Answers.UserDisplayName: Gyan
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-11-25T07:59:46.983Z
Answers.LastActivityDate: 2016-11-25T12:34:37.313Z
Answers.LastEditDate: 2016-11-25T12:34:37.313Z
Answers.UserDisplayName: Gyan
Body: <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>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-11-25T05:25:48.150Z
Comments.Text: I'm note sure, so please confirm before I consider this as an answer. Please try with '-vcodec libx264rgb' instead of '-vcodec libx264'
Comments.UserDisplayName: RawBean
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-11-25T06:08:26.997Z
Comments.Text: 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.
Comments.UserDisplayName: Gyan
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-11-25T06:09:30.037Z
Comments.Text: To the OP. how did you convert BMPs to PNG? And how were the BMPs generated?
Comments.UserDisplayName: Gyan
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-11-25T07:03:27.973Z
Comments.Text: @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.
Comments.UserDisplayName: Nayuki
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-11-25T07:11:32.760Z
Comments.Text: @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.
Comments.UserDisplayName: Nayuki
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-10-30T22:22:50.553Z
Comments.Text: @RawBean Aftertrying different things for several hours, using `libx264rgb` instread of `libx264` fixed the issue for me. Thanks so much!!
Comments.UserDisplayName: étale-cohomology
Tags: <video><ffmpeg><encoding><colorspace>
Title: FFmpeg BMP to YUV x264 color shift
UserDisplayName: Nayuki
ThreadText: # 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:
  
  [![enter image description here](https://i.sstatic.net/PEowN.png)](https://i.sstatic.net/PEowN.png)
  
  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`
  
  [![enter image description here](https://i.sstatic.net/w5YNB.png)](https://i.sstatic.net/w5YNB.png)
  
  Second attempt (even worse): `ffmpeg -i 000.bmp -vf "colormatrix=bt601:bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 second.mp4`
  
  [![enter image description here](https://i.sstatic.net/5I7L6.png)](https://i.sstatic.net/5I7L6.png)
  
  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`
  
  [![enter image description here](https://i.sstatic.net/xKJta.png)](https://i.sstatic.net/xKJta.png)
  
  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`
  
  [![enter image description here](https://i.sstatic.net/QwdPW.png)](https://i.sstatic.net/QwdPW.png)
  
  ---
  
  I am using the latest [FFmpeg Windows](https://ffmpeg.zeranoe.com/builds/) 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.  
  
  ---
  
  