Retain Rec 2020 Color Space in libvpx-vp9

Retaining the Rec. 2020 color space when transcoding video to the VP9 codec using FFmpeg’s libvpx-vp9 encoder requires explicit configuration of color metadata. This article provides a straightforward guide on how to configure your FFmpeg command-line parameters—specifically pixel format, color primaries, transfer characteristics, and color space matrix—to ensure your wide color gamut (WCG) or High Dynamic Range (HDR) metadata is fully preserved during the conversion process.

Why Color Metadata is Lost During Transcoding

By default, FFmpeg does not always automatically copy or write color space metadata into the output bitstream or WebM container during transcoding. When players read a VP9 file missing this metadata, they usually fall back to standard definition (Rec. 601) or high definition (Rec. 709) color spaces, resulting in washed-out or heavily distorted colors. To prevent this, you must explicitly flag the color properties in your FFmpeg command.

Key FFmpeg Parameters for Rec. 2020

To properly preserve and signal the Rec. 2020 color space, you must include the following four parameters in your FFmpeg command:

  1. -pix_fmt yuv420p10le: Rec. 2020 requires a 10-bit color depth to prevent banding. This flag forces the encoder to use 10-bit YUV 4:2:0.
  2. -color_primaries bt2020: Identifies the color gamut as Rec. 2020.
  3. -color_trc: Defines the transfer characteristics (gamma curve).
    • Use smpte2084 for HDR10 (PQ).
    • Use arib-std-b67 for HLG (Hybrid Log-Gamma).
    • Use bt2020-10 for SDR (Standard Dynamic Range) 10-bit Rec. 2020.
  4. -colorspace bt2020nc: Sets the color matrix to Rec. 2020 non-constant luminance, which is the standard for most consumer video.

Step-by-Step Command Examples

Example 1: Transcoding HDR10 (PQ) to VP9

If your source video is HDR10, use the following command to encode it to VP9 while retaining the Rec. 2020 color space and Perceptual Quantizer (PQ) transfer curve:

ffmpeg -i input.mp4 \
  -c:v libvpx-vp9 \
  -pix_fmt yuv420p10le \
  -color_primaries bt2020 \
  -color_trc smpte2084 \
  -colorspace bt2020nc \
  -b:v 5M -crf 18 \
  output.webm

Example 2: Transcoding HLG to VP9

If your source is HLG, adjust the -color_trc parameter to match the HLG transfer function:

ffmpeg -i input.mp4 \
  -c:v libvpx-vp9 \
  -pix_fmt yuv420p10le \
  -color_primaries bt2020 \
  -color_trc arib-std-b67 \
  -colorspace bt2020nc \
  -b:v 5M -crf 18 \
  output.webm

Verifying the Output File

Once the transcoding is complete, you can verify that the Rec. 2020 metadata has been successfully embedded by running ffprobe on your output file:

ffprobe -select_streams v:0 -show_entries stream=color_space,color_transfer,color_primaries output.webm

Your terminal should output the following values, confirming the color space was successfully retained:

color_range=tv
color_space=bt2020nc
color_transfer=smpte2084 (or arib-std-b67)
color_primaries=bt2020