Convert RGB to YUV420p with FFmpeg Zscale
This article explains how to convert an RGB video to the widely
compatible YUV420p format using FFmpeg’s high-quality
zscale filter. While the standard scale filter
(swscale) is commonly used for color space conversion, the
zscale filter leverages the zimg library to
provide superior color accuracy, high-bit-depth precision, and advanced
dithering algorithms to prevent color banding.
Why Use Zscale Instead of Scale?
FFmpeg’s default scale filter can sometimes introduce
color shifting, ringing artifacts, or banding when converting from RGB
to YUV. The zscale filter solves these issues by using
floating-point precision for internal calculations and offering superior
algorithms for chroma subsampling and color space transformation.
The Basic Command
To convert an RGB video to YUV420p (using the BT.709 color standard, which is standard for HD video), use the following FFmpeg command:
ffmpeg -i input_rgb.mp4 -vf "zscale=matrix=709:primaries=709:transfer=709:range=limited,format=yuv420p" -c:v libx264 -crf 18 -c:a copy output_yuv420p.mp4Parameter Breakdown
zscale=...: Invokes the zscale filter.matrix=709: Defines the color space matrix coefficients as BT.709. This is critical for converting the RGB channels into correct luminance (Y) and chrominance (U/V) values.primaries=709: Sets the color primaries to BT.709, ensuring the colors are mapped correctly for modern HD displays.transfer=709: Sets the transfer characteristics (gamma curve) to BT.709.range=limited: Standardizes the output to limited (broadcast) color range (16-235), which is required for maximum compatibility with hardware players and streaming platforms.format=yuv420p: Force-outputs the final pixel format to 8-bit planar YUV 4:2:0.
Advanced: Adding Dithering to Prevent Banding
When downsampling from RGB (which often acts as 10-bit or
high-precision color internally) to 8-bit YUV420p, color banding can
occur in gradients (like skies or shadows). You can enable dithering
within zscale to eliminate this:
ffmpeg -i input_rgb.mp4 -vf "zscale=matrix=709:primaries=709:transfer=709:range=limited:dither=ordered,format=yuv420p" -c:v libx264 -crf 18 output_dithered.mp4By adding :dither=ordered (or
:dither=error_diffusion), zscale will apply a
high-quality dither pattern to smooth out transitions, resulting in a
visually flawless 8-bit YUV420p file.