How does mpv convert BT.2020 to BT.709?
When playing Ultra High Definition (UHD) video on a standard dynamic
range (SDR) display, the media player mpv must convert
the video’s wide BT.2020 color gamut and high dynamic range (HDR)
metadata to fit the narrow BT.709 color space and standard gamma curve.
To achieve this without losing detail or introducing major color
distortion, mpv utilizes hardware-accelerated video outputs
(vo=gpu or vo=gpu-next) powered by
libplacebo. The player processes the transformation by
decoding the YCbCr video stream into a linear, non-clipped RGB color
space, performing necessary dynamic range adjustments via tone mapping,
and then compressing the wider gamut down to the BT.709 primaries.
1. Decoding YCbCr to Linear Light
The conversion process begins at the pixel level. HDR video is typically encoded using the BT.2020 Non-Constant Luminance (NCL) color matrix and the Perceptual Quantizer (PQ) transfer function. mpv reads this metadata and executes the following steps:
- Matrix Transformation: The player converts the compressed 10-bit or 12-bit YCbCr signal into non-linear digital \(R'G'B'\) values using the standard BT.2020 transformation matrix.
- Linearization: Because color and tone adjustments cannot be accurately computed on gamma-encoded or PQ-encoded data, mpv applies the inverse transfer function to transform the \(R'G'B'\) data into a linear RGB color space where the values map directly to physical light intensities.
2. Tone Mapping and Dynamic Range Reduction
Before shifting the colors into the target space, mpv must address the massive difference in luminance between HDR and SDR. HDR content is frequently mastered for peaks up to 1,000 or 4,000 nits, whereas standard BT.709 displays target roughly 100 nits.
Using algorithms such as spline, bt.2390,
or mobius, mpv calculates how to compress the highlights
while preserving midtone contrast. This tone mapping step adjusts the
brightness of the linear RGB values so they do not clip aggressively
when squeezed into standard dynamic range boundaries.
3. Gamut Mapping to BT.709 Primaries
Once the luminance is scaled appropriately, mpv targets the color gamut itself. Because BT.2020 can represent highly saturated colors that physically do not exist within the BT.709 spectrum, the player must map the coordinates.
By default, mpv calculates a 3x3 color transformation matrix derived
from the difference between the BT.2020 and BT.709 primary coordinates
and white points. To prevent out-of-gamut colors from clipping
harshly—which causes a loss of detail in highly saturated areas, like
bright neon lights—mpv’s rendering engine utilizes advanced gamut
mapping modes. Under modern configurations using
vo=gpu-next, it handles colors outside the target boundary
smoothly, balancing desaturation with hue preservation to ensure the
resulting output looks rich and natural on a standard monitor.