FFmpeg libvpx-vp9 Color Space Tagging
When encoding video to VP9 using the libvpx-vp9 encoder
in FFmpeg, managing color space tagging is crucial for ensuring accurate
color reproduction across different media players and web browsers. This
article explains how FFmpeg processes color metadata, the specific flags
required to define color space parameters during the encoding process,
and how to apply these settings for both Standard Dynamic Range (SDR)
and High Dynamic Range (HDR) workflows.
How FFmpeg Handles VP9 Color Metadata
By default, FFmpeg does not automatically write color space metadata into the VP9 bitstream unless it is explicitly defined in the command line or successfully passed through from a strictly defined source. VP9 stores color description parameters in both the container level (such as WebM or MKV) and the coded bitstream level.
If these tags are missing, players like VLC, Chrome, or YouTube will fall back to default assumptions (usually BT.601 for SD and BT.709 for HD), which can cause noticeable color shifts, such as washed-out colors or incorrect gamma.
To guarantee accurate color rendering, you must explicitly define
three core parameters: 1. Color Primaries
(-color_primaries): Defines the color gamut (e.g.,
BT.709, BT.2020). 2. Transfer Characteristics
(-color_trc): Defines the opto-electronic transfer
function (e.g., BT.709, SMPTE 2084/PQ, ARIB STD-B67/HLG). 3.
Color Space Matrix (-colorspace): Defines
the matrix coefficients used to derive luma and chroma signals from red,
green, and blue primaries (e.g., BT.709, BT.2020 non-constant
luminance).
Tagging SDR Video (BT.709)
For standard high-definition video, you should tag the output using the BT.709 color space.
To encode an 8-bit SDR video with proper BT.709 tagging, use the following FFmpeg command:
ffmpeg -i input.mp4 -c:v libvpx-vp9 -pix_fmt yuv420p -colorspace bt709 -color_primaries bt709 -color_trc bt709 output.webm-pix_fmt yuv420p: Sets the pixel format to standard 8-bit YUV 4:2:0.-colorspace bt709: Sets the matrix coefficients to BT.709.-color_primaries bt709: Sets the color primaries to BT.709.-color_trc bt709: Sets the transfer characteristics to BT.709.
Tagging HDR Video (BT.2020 & PQ/HDR10)
Encoding HDR video requires 10-bit depth, which corresponds to VP9 Profile 2. You must specify the 10-bit pixel format and use the BT.2020 color space along with the appropriate transfer function (typically SMPTE 2084 for HDR10).
To encode an HDR10 video with proper tagging, use this command:
ffmpeg -i input.mp4 -c:v libvpx-vp9 -pix_fmt yuv420p10le -profile:v 2 -colorspace bt2020nc -color_primaries bt2020 -color_trc smpte2084 output.webm-pix_fmt yuv420p10le: Selects 10-bit YUV 4:2:0.-profile:v 2: Forces VP9 Profile 2, which is required for 10-bit and 12-bit color depths.-colorspace bt2020nc: Sets the matrix coefficients to BT.2020 non-constant luminance.-color_primaries bt2020: Sets the color primaries to BT.2020.-color_trc smpte2084: Sets the transfer function to SMPTE ST 2084 (PQ curve used for HDR10).
Verifying Color Space Tags
After rendering, you can verify that the color space tags were
successfully embedded into your VP9 file using ffprobe. Run
the following command:
ffprobe -v error -select_streams v:0 -show_entries stream=color_space,color_primaries,color_transfer,color_range -of default=noprint_wrappers=1 output.webmThe output should display the exact parameters you specified during encoding, confirming that browsers and media players will read and display the colors correctly:
color_range=tv
color_space=bt709
color_primaries=bt709
color_transfer=bt709