# Colorimetry: inspect before encoding

Canonical URL: https://encode.wiki/reference/colorimetry/intro/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 3c69dba40c59f9a0438e32e13298d193bb4674fc96016c26e12720838ddc09d5

A decoded video frame is just numbers. Four pieces of metadata tell the player how to turn those numbers into light, and a fifth tells it where the chroma samples sit. If any of them is missing or wrong, the encode still "works" but the colors shift, blacks lift or crush, or HDR looks flat — which is why color mistakes so often go unnoticed until someone watches the result on another player.

| Property | What it answers | ffprobe field | Typical HD SDR | Typical HDR10 |
| --- | --- | --- | --- | --- |
| [Primaries](/reference/colorimetry/primaries/) | Which red, green, blue and white the RGB values refer to | `color_primaries` | `bt709` | `bt2020` |
| [Transfer](/reference/colorimetry/transfer/) | How code values map to light | `color_transfer` | `bt709` | `smpte2084` (PQ) |
| [Matrix](/reference/colorimetry/matrix/) | How Y′CbCr is converted back to R′G′B′ | `color_space` | `bt709` | `bt2020nc` |
| [Range](/reference/colorimetry/range/) | Which code values are black and white | `color_range` | `tv` (limited) | `tv` (limited) |
| Chroma location | Where subsampled chroma sits relative to luma | `chroma_location` | `left` | `left` or `topleft` |

The values are the integer code points from [ITU-T H.273](https://www.itu.int/rec/T-REC-H.273-202407-I), which AVC, HEVC, VVC, AV1, Matroska and MP4 all reuse. Tools give them different names — FFmpeg says `bt2020nc`, SVT-AV1 says `bt2020-ncl`, VapourSynth says `2020ncl` — but the number underneath is the same. How the [pixel format](/reference/colorimetry/format/) stores the samples (bit depth, subsampling, planar or packed) is a separate question.

## Read the source

```sh
ffprobe -v error -select_streams v:0 -show_entries stream=pix_fmt,color_range,color_space,color_transfer,color_primaries,chroma_location -of default=nw=1 input.mkv
```

For an HD Blu-ray remux this prints something like:

```text
pix_fmt=yuv420p
color_range=tv
color_space=bt709
color_transfer=bt709
color_primaries=bt709
chroma_location=left
```

`unknown` means the file does not say. HDR mastering metadata and Dolby Vision or HDR10+ data are usually carried per frame in the bitstream, so inspect the first frame as well:

```sh
ffprobe -v error -select_streams v:0 -read_intervals "%+#1" -show_frames input.mkv
```

Look for `side_data_type=Mastering display metadata`, `Content light level metadata`, `Dolby Vision Metadata` or `HDR Dynamic Metadata SMPTE2094-40 (HDR10+)`. See [HDR formats](/hdr/) for what each means.

## What players do with untagged video

When a field is `unknown` the player guesses, and players guess differently. mpv 0.41, for example:

- **Matrix:** BT.709 if the width is at least 1280 or the height is above 576, otherwise BT.601.
- **Primaries:** BT.2020 if the matrix is BT.2020, BT.709 if the matrix is BT.709; otherwise by height (576 → PAL, 480/486 → NTSC, anything else → BT.709).
- **Transfer:** BT.1886 for limited-range video, sRGB for full-range.

Browsers, TVs and other players use their own rules. An untagged 720×480 file therefore looks right in one player and slightly green-shifted in another. Tag every encode, and never assume an untagged source is BT.709 just because most HD material is — check where it came from.

## Tagging is not converting

There are three different operations, and confusing them is the most common color mistake:

- **Preserve:** keep the samples and carry the same tags to the output. This is what you want for almost every encode.
- **Retag:** change the metadata, leave the samples alone. Correct only when the source was tagged wrongly or not at all.
- **Convert:** change the samples from one color system to another (matrix, range, primaries, transfer, tone mapping), then tag the result as the new system.

Tagging BT.601 pixels as BT.709 does not convert them; it makes the colors wrong. Tagging PQ video as `bt709` does not tone-map it; it makes it look washed out. Scaling SD to HD does not change the matrix by itself — if you want an HD BT.709 output, convert the matrix while you scale.

[Preserve color and HDR metadata](/guides/preserve-color-and-hdr/) has the commands for each case in FFmpeg, VapourSynth and the standalone encoders.
