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

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

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.webm

The 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