user1950: I'm doing an animation for a projection mapping that simulates the sun casting shadows on a structure as it moves through the sky. Basically it's just big flat areas of colour that change over about five minutes as the "sun" rises and sets (in another projection). It's played off a Brightsign playback gizmo, and I'm using h.264 main profile as the codec in an mp4.
The problem I'm having is that the encoding isn't dealing very well with the content. Even though the colour is completely flat, when the pixels all change value over time I'm getting bands of noise and blocks appearing. They're subtle, but they're annoying.
Is there any tuning I can do using libx264 to optimise it for large flat areas of colour where all the pixels simultaneously change over time? There is absolutely no movement in the frame, just the colour of the whole area changing, quite slowly.
My current ffmpeg command is pretty generic:
ffmpg -i input.mov -c:v libx264 -preset slow -profile main -crf 20 -pix_fmt yuv420p -an output.mp4


user5750: The bands you're referring to could well just be a limitation of the 8-bit colour space.
In theory the way to solve this is to use 10- or 12-bit colour space through every stage from rendering, to editing and mastering, through to output and even in the screen or projector.  However your final output is probably going to be displayed in an 8 bits per channel space whether you like it or not.
So the practical way to do this is to render at 10- or 12-bit colour and dither down to 8-bit from the master.  The dithering will prevent the visual appearance of banding when displayed at 8 bits per channel.
Note that this is not a limitation of h.264 or any encoder but of the colour space used and the noise-free nature of the rendered animation; if real life was this noise-free it would also show this banding in 8-bit colour spaces.  There is unlikely to be any setting you could choose in your encoder in order to solve this.  To confirm, render to an uncompressed format and you will probably still see the banding.
Note: dithering from a 10- or 12-bit render is not the same as just adding some noise to an existing 8-bit dither - while this may disguise the banding a little bit simply by making it less distinct it doesn't solve it.  But you could do it in a pinch.

user5226: Depending how the content was made, the banding might be introduced when you're converting your content from RGB colorspace to YUV. You can try to make an h264 while keeping RGB colorspace, although I've read it's not easy. Are you able to use another codec?

user6294: The first thing I would try is to add -force_key_frames to your original command, drop the preset and lower the -crf value. The following example sets a key frame every second.
ffmpg -i input.mov -c:v libx264 -profile main \
    -force_key_frames expr:gte(t,n_forced*1) \
    -crf 15 -pix_fmt yuv420p -an output.mp4

As a second resort I would use a series of png images (instead of mov) as the input and use a very low crf. This way you can really make sure that there is no banding in your input and the highest quality in the end material. If you can't directly render to png, then convert the original material.
Here is an example:
# turn the original into pngs
ffmpeg -i input.mov -f image2 -threads 0 /tmp/%05d.png

# turn the pngs back into mp4 (assuming 25 fps)
ffmpeg -ar 48000 -ac 2 -f s16le -i /dev/zero -r 25/1 -f image2 \
  -i /tmp/%05d.png -c:a libfdk_aac -c:v libx264 \ 
  -profile main -vf "fps=fps=25" -force_key_frames expr:gte(t,n_forced*1) \
  -crf 10 -threads 0 -pix_fmt yuv420p output.mp4

ps. You should get in the habit of including a silent audio track for media device playback because of syncing issues.

1950: <p>I'm doing an animation for a projection mapping that simulates the sun casting shadows on a structure as it moves through the sky. Basically it's just big flat areas of colour that change over about five minutes as the "sun" rises and sets (in another projection). It's played off a Brightsign playback gizmo, and I'm using h.264 main profile as the codec in an mp4.</p>

<p>The problem I'm having is that the encoding isn't dealing very well with the content. Even though the colour is completely flat, when the pixels all change value over time I'm getting bands of noise and blocks appearing. They're subtle, but they're annoying.</p>

<p>Is there any tuning I can do using libx264 to optimise it for large flat areas of colour where all the pixels simultaneously change over time? There is absolutely no movement in the frame, just the colour of the whole area changing, quite slowly.</p>

<p>My current ffmpeg command is pretty generic:</p>

<pre><code>ffmpg -i input.mov -c:v libx264 -preset slow -profile main -crf 20 -pix_fmt yuv420p -an output.mp4
</code></pre>
 5750: <p>The bands you're referring to could well just be a limitation of the 8-bit colour space.</p>

<p>In theory the way to solve this is to use 10- or 12-bit colour space through every stage from rendering, to editing and mastering, through to output and even in the screen or projector.  However your final output is probably going to be displayed in an 8 bits per channel space whether you like it or not.</p>

<p>So the practical way to do this is to render at 10- or 12-bit colour and dither down to 8-bit from the master.  The dithering will prevent the visual appearance of banding when displayed at 8 bits per channel.</p>

<p>Note that this is not a limitation of h.264 or any encoder but of the colour space used and the noise-free nature of the rendered animation; if real life was this noise-free it would also show this banding in 8-bit colour spaces.  There is unlikely to be any setting you could choose in your encoder in order to solve this.  To confirm, render to an uncompressed format and you will probably still see the banding.</p>

<p>Note: dithering from a 10- or 12-bit render is not the same as just adding some noise to an existing 8-bit dither - while this may disguise the banding a little bit simply by making it less distinct it doesn't solve it.  But you could do it in a pinch.</p>
 5226: <p>Depending how the content was made, the banding might be introduced when you're converting your content from RGB colorspace to YUV. You can try to make an h264 while keeping RGB colorspace, although I've read it's not easy. Are you able to use another codec?</p>
 6294: <p>The first thing I would try is to add <code>-force_key_frames</code> to your original command, drop the preset and lower the <code>-crf</code> value. The following example sets a key frame every second.</p>

<pre><code>ffmpg -i input.mov -c:v libx264 -profile main \
    -force_key_frames expr:gte(t,n_forced*1) \
    -crf 15 -pix_fmt yuv420p -an output.mp4
</code></pre>

<p>As a second resort I would use a series of png images (instead of mov) as the input and use a very low crf. This way you can really make sure that there is no banding in your input and the highest quality in the end material. If you can't directly render to png, then convert the original material.</p>

<p>Here is an example:</p>

<pre><code># turn the original into pngs
ffmpeg -i input.mov -f image2 -threads 0 /tmp/%05d.png

# turn the pngs back into mp4 (assuming 25 fps)
ffmpeg -ar 48000 -ac 2 -f s16le -i /dev/zero -r 25/1 -f image2 \
  -i /tmp/%05d.png -c:a libfdk_aac -c:v libx264 \ 
  -profile main -vf "fps=fps=25" -force_key_frames expr:gte(t,n_forced*1) \
  -crf 10 -threads 0 -pix_fmt yuv420p output.mp4
</code></pre>

<p>ps. You should get in the habit of including a silent audio track for media device playback because of syncing issues.</p>
