Skip to content

HDR formats and tone mapping

current

HDR video is ordinary video with three things changed: a transfer function that can describe much brighter highlights (PQ or HLG), wide-gamut BT.2020 primaries, and at least 10 bits per sample. HDR10, HDR10+ and Dolby Vision add metadata on top of that to help a display that is dimmer than the mastering monitor. None of them is a codec — the same HDR10 signal can be carried in HEVC, AV1, VP9 or AVC.

FormatTransferMetadataOn a display without supportWhere you meet it
HDR10PQ (smpte2084)Static: mastering display (SMPTE ST 2086) and MaxCLL/MaxFALLSDR displays need a tone-mapped versionUHD Blu-ray, streaming, games
HDR10+PQHDR10 static metadata plus per-scene SMPTE ST 2094-40 dynamic metadataPlays as HDR10Some UHD Blu-rays and streaming services
Dolby VisionPQ (profiles 5, 7, 8.1, 10.1) or HLG (8.4)Per-frame RPU, plus HDR10 static metadata in compatible profilesDepends on profile, see belowUHD Blu-ray, streaming, phone cameras
HLGHLG (arib-std-b67)None requiredDesigned to look acceptable on SDR displays tooBroadcast and live TV, phone cameras

Newer systems — HDR10+ Advanced (a backward-compatible extension of HDR10+), Dolby Vision 2 (a display-side engine announced in September 2025) and the ETSI SL-HDR family (an SDR or HDR base signal plus reconstruction metadata) — have no support in the open-source encoders and tools covered on this wiki.

Terminal window
ffprobe -v error -select_streams v:0 -show_entries stream=pix_fmt,color_transfer,color_primaries,color_space -of default=nw=1 input.mkv
ffprobe -v error -select_streams v:0 -read_intervals "%+#1" -show_frames input.mkv
ffprobe showsIt is
color_transfer=smpte2084, Mastering display metadata, Content light level metadataHDR10
The above plus HDR Dynamic Metadata SMPTE2094-40 (HDR10+)HDR10+
DOVI configuration record on the stream; Dolby Vision Metadata on framesDolby Vision; the record’s dv_profile and dv_bl_signal_compatibility_id give the profile (8 and 1 → 8.1)
color_transfer=arib-std-b67HLG
dv_profile=5, with color tags unknown or ipt-c2Dolby Vision profile 5: no standard base layer

A file can be several at once: an HDR10+ and Dolby Vision 8.1 stream is still valid HDR10 underneath. dovi_tool info and hdr10plus_tool --verify extract give a fuller picture of the dynamic metadata.

Two SEI messages (or AV1 metadata OBUs), normally repeated at every keyframe:

  • Mastering display color volume (SMPTE ST 2086): the primaries, white point and minimum/maximum luminance of the monitor the content was graded on — for example P3-D65 at 1000 cd/m² peak.
  • Content light level (CTA-861.3): MaxCLL, the brightest pixel anywhere in the program, and MaxFALL, the highest frame-average light level, both in cd/m².

The display uses these to decide how to compress highlights it cannot reproduce. They describe the grade, so copy them from the source; never make them up. The exact x265, SVT-AV1 and FFmpeg syntax is in preserving HDR10 metadata. x265 has --hdr10-opt (block-level QP adjustment for PQ content), which it recommends using together with adaptive quantization.

HDR10+ adds SMPTE ST 2094-40 metadata — per-scene brightness statistics and a tone-mapping curve — to an HDR10 stream. In HEVC it is an ITU-T T.35 SEI message, normally on every frame; AV1 carries the same payload in a metadata OBU. Because the base is HDR10, a display without HDR10+ support just ignores it.

Encoders don’t create HDR10+ metadata from the picture, so it has to be carried over from the source: FFmpeg’s libaom-av1 passes it through, libx265 and libsvtav1 drop it, and for HEVC you extract it with hdr10plus_tool and give it to x265. The commands are in the color and HDR guide.

Dolby Vision adds an RPU (reference processing unit) to every frame: per-shot brightness (L1), trims for target displays (L2, L8), active-area offsets (L5) and static values (L6), among others. The profile defines the base layer and therefore what a non-Dolby Vision player sees.

ProfileCodec and layersBase layerNotes
5HEVC, single layerIPTPQc2 (proprietary)Streaming. Without Dolby Vision processing the picture has wrong, typically green and purple, colors.
7HEVC, base + enhancement layerHDR10UHD Blu-ray. The enhancement layer is either MEL (metadata only) or FEL (extra picture data).
8.1HEVC, single layerHDR10The usual target for re-encodes; falls back to HDR10.
8.2HEVC, single layerSDR BT.709
8.4HEVC, single layerHLGPhone cameras.
10AV1, single layer10.1 HDR10, 10.4 HLG, 10.0 IPTPQc2What FFmpeg writes when re-encoding Dolby Vision to AV1.

A re-encode keeps the source’s RPU and has to match it frame for frame: extract it with dovi_tool (converting profile 7 to 8.1 on the way), then let x265 write it or inject it into the new stream; FFmpeg can also pass single-layer Dolby Vision through with -dolbyvision 1. Converting profile 7 FEL to 8.1 discards the enhancement layer’s picture data; with MEL nothing visible is lost. The steps are in the color and HDR guide and on the dovi_tool page.

HLG (arib-std-b67, transfer code 18) is relative rather than absolute: its signal describes scene light, and the display scales it to its own peak brightness. It needs no metadata, which is why broadcasters use it for live production. Encode it as 10-bit with bt2020 primaries, bt2020nc matrix and arib-std-b67 transfer, and do not add HDR10 mastering metadata unless the source has it.

Converting HDR to SDR is a real conversion — linearize, compress the highlights, map BT.2020 colors into BT.709, re-encode with the SDR transfer. Retagging PQ as bt709 only produces a gray, washed-out picture.

With a Vulkan-capable GPU, libplacebo does this in one filter and also applies Dolby Vision RPUs, so it handles profile 5 sources correctly:

Terminal window
ffmpeg -i hdr.mkv -vf "libplacebo=colorspace=bt709:color_primaries=bt709:color_trc=bt709:range=tv:format=yuv420p,sidedata=mode=delete:type=MASTERING_DISPLAY_METADATA,sidedata=mode=delete:type=CONTENT_LIGHT_LEVEL" -c:v libx264 -crf 18 sdr.mkv

On the CPU, zscale plus tonemap is the classic chain. The tonemap filter needs linear-light floating-point input, which the first two steps provide:

Terminal window
ffmpeg -i hdr.mkv -vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p,sidedata=mode=delete:type=MASTERING_DISPLAY_METADATA,sidedata=mode=delete:type=CONTENT_LIGHT_LEVEL" -c:v libx264 -crf 18 sdr.mkv

npl=100 maps 100 cd/m² in the source to SDR white; raise it to darken the result. This chain ignores Dolby Vision metadata, so a profile 5 source comes out with wrong colors.

Automatic tone mapping is a compromise. A dark scene and a bright scene need different curves, and a fixed curve that suits one will clip or dull the other, so watch the result on an SDR display. When an official SDR version exists, it is usually better than any automatic conversion.