HDR video looks spectacular on a display that can handle it. On one that cannot, it looks worse than SDR — highlights are crushed, colors are oversaturated or washed out depending on the player, and skin tones take on an unnatural orange tint. If you have ever played an HDR video on an older TV or projector and found yourself wondering why everything looks wrong, you have experienced a failed HDR-to-SDR fallback.
Proper HDR to SDR conversion — called tone mapping — addresses this by intelligently compressing the wider dynamic range of HDR into the narrower range that standard displays can reproduce. Done well, the result looks better than the default SDR fallback most devices apply automatically. This guide covers the technical background, practical FFmpeg commands, and when to use which approach.
HDR Formats You Will Encounter
Not all HDR is the same format. Each has different metadata handling and requires slightly different conversion approaches.
| Format | Bit Depth | Metadata | Common On |
|---|---|---|---|
| HDR10 | 10-bit | Static, SMPTE ST 2086 | Blu-ray, streaming, cameras |
| HDR10+ | 10-bit | Dynamic, per-scene | Amazon Prime, Samsung TVs |
| Dolby Vision | 12-bit | Dynamic, per-frame | Netflix, Apple devices, Blu-ray |
| HLG (Hybrid Log-Gamma) | 10-bit | None (backward-compatible) | Broadcast, YouTube live |
| PQ (Perceptual Quantizer) | 10-bit | Embedded in stream | UHD Blu-ray, HDR10 base |
For most conversion purposes, HDR10 is what you will encounter. The transfer function is PQ (SMPTE ST 2084), the color primaries are Rec.2020, and the peak luminance is typically 1,000–4,000 nits depending on the mastering display.
Standard SDR content uses BT.709 color primaries and the BT.1886/gamma 2.4 transfer function, with a peak luminance of 100 nits. That is a 10× to 40× reduction in luminance range, which is why naive conversion looks so bad — the entire brightness scale needs to be remapped, not just clamped.
What Tone Mapping Does
Tone mapping is the process of fitting the HDR luminance curve into the SDR range. The naive approach (clipping) just cuts off anything above 100 nits, which blows out highlights and loses detail in bright areas. Good tone mapping algorithms apply a curve that:
- Preserves shadow detail at the low end
- Gradually compresses midtones
- Rolls off highlights gracefully instead of hard-clipping
- Shifts color saturation to account for the reduced luminance
Several tone mapping operators exist with different tradeoffs:
- Reinhard — Simple, mathematically elegant. Preserves overall brightness but produces a slightly flat look. Good default.
- Hable (Uncharted 2) — Preserves shadow detail and highlight rolloff better. Popular in game engines. Slightly more contrast.
- Mobius — Tries to preserve SDR-safe values unchanged and only compresses HDR highlights. Minimizes unwanted changes to already-SDR-range content.
- Luma — Tone maps brightness only, preserves hue and saturation relationships. Can over-saturate.
Converting HDR to SDR with FFmpeg
FFmpeg's zscale filter (from the zimg library) handles the color space math. The tonemapx filter or the tonemap filter in combination with zscale performs the actual luminance compression.
Basic HDR10 to SDR Conversion
ffmpeg -i input_hdr.mp4 \
-vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow \
-c:a copy \
output_sdr.mp4
This pipeline:
- Converts to linear light via
zscale - Changes the color primaries to BT.709
- Applies Hable tone mapping
- Sets the output transfer function to BT.709
- Encodes with H.264 at CRF 18 (high quality)
Pro Tip: Always copy the audio stream with -c:a copy unless you specifically need to re-encode it. Re-encoding audio adds processing time and quality loss with no benefit for color space conversion.
Dolby Vision / HDR10+ Conversion
For Dolby Vision content, FFmpeg needs to ignore the proprietary metadata layer. The conversion is the same as HDR10 but you may want to add -strict unofficial to handle some Dolby Vision streams:
ffmpeg -i input_dolby_vision.mp4 \
-vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=mobius:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow \
-c:a copy \
-strict unofficial \
output_sdr.mp4
HLG to SDR Conversion
HLG (Hybrid Log-Gamma) is designed to be backward-compatible with SDR displays, so many players handle it automatically. If you need explicit conversion:
ffmpeg -i input_hlg.mp4 \
-vf "zscale=t=linear:npl=400,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=reinhard,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libx264 -crf 18 \
-c:a copy \
output_sdr.mp4
Note the npl=400 — HLG is typically mastered to 400 nits peak, not 1,000 nits.
Choosing the Right Tone Map Operator
The best tone mapping operator depends on the content type:
| Content Type | Recommended Operator | Why |
|---|---|---|
| Live sports, documentaries | Hable | Natural highlight rolloff |
| Movies, narrative film | Reinhard or Mobius | Preserves director's intended look |
| Animation, CGI | Mobius | Preserves already-SDR values |
| Music videos, stylized content | Luma | Keeps vibrant saturation |
| General-purpose batch conversion | Reinhard | Predictable, fast |
The desat parameter controls color desaturation for very bright highlights. Setting desat=0 disables desaturation (highlights stay colorful), while higher values gradually desaturate toward white. For most content, desat=0 or desat=0.5 looks best.
Avoiding Washed-Out Colors
The most common complaint about HDR-to-SDR conversion is that the result looks washed out — low contrast, desaturated. This usually happens for one of three reasons:
1. Missing color primaries conversion. HDR10 uses Rec.2020 color primaries, which is a wider gamut than BT.709. If you skip the primaries conversion, colors that live outside the BT.709 gamut get clipped or wrapped, causing visible inaccuracies.
2. Incorrect peak nits setting. If your content was mastered at 4,000 nits but you tell zscale the peak is 100 nits (npl=100), everything gets crushed into the SDR range too aggressively. For HDR10 content, a value of npl=1000 to npl=4000 usually looks better.
3. Wrong transfer function output. Make sure the final zscale step specifies t=bt709. If this is missing or wrong, the output will have an incorrect gamma curve.
Here is a corrected command for 1,000 nit HDR content:
ffmpeg -i input_hdr.mp4 \
-vf "zscale=t=linear:npl=1000,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow \
-c:a copy \
output_sdr.mp4
Batch Converting Multiple HDR Files
If you have a folder of HDR videos to convert, a simple Bash loop handles the batch:
for f in /videos/hdr/*.mp4; do
base=$(basename "$f" .mp4)
ffmpeg -i "$f" \
-vf "zscale=t=linear:npl=1000,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow \
-c:a copy \
"/videos/sdr/${base}_sdr.mp4"
done
For browser-based batch conversion without FFmpeg, the video converter hub at ConvertIntoMP4 processes multiple files through the conversion pipeline. Upload your HDR files and select MP4 as the output; the backend applies tone mapping during encoding. If the source files are in MKV format, you can first use the MKV converter to remux to MP4 before the tone mapping step.
Pro Tip: Before committing to a full batch conversion, test your FFmpeg command on a 30-second clip cut with -t 30. Tone mapping parameters can produce subtly different results depending on the mastering style of the content.
HDR to SDR for Specific Use Cases
Streaming to Non-HDR Devices
If you are running a Plex or Jellyfin server with a mix of HDR and SDR clients, pre-converting your HDR library to SDR avoids the server having to tone-map in real time during playback (which requires significant CPU resources). Use CRF 18–20 for high-quality archival SDR copies.
Social Media Uploads
YouTube, Instagram, and TikTok accept HDR uploads and handle tone mapping on their end. However, if you have noticed that your HDR footage looks oversaturated or contrast-crushed after upload, pre-converting to SDR gives you control over the tone mapping. Use the output of the FFmpeg command above, then compress it for upload with the video compressor. For trimming the HDR source to just the segment you need before conversion, the video trimmer handles MKV and MP4 trim without re-encoding.
Broadcast and Professional Delivery
Broadcast standards typically require BT.709 SDR with specific peak levels. Use -color_primaries bt709 -color_trc bt709 -colorspace bt709 flags in your FFmpeg output to set the correct signaling metadata:
ffmpeg -i input_hdr.mp4 \
-vf "zscale=t=linear:npl=1000,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow \
-color_primaries bt709 -color_trc bt709 -colorspace bt709 \
-c:a copy \
output_broadcast_sdr.mp4
Understanding Codec Choice for SDR Output
When re-encoding HDR content as SDR, your choice of output codec affects both quality and file size. The H.264 vs H.265 vs AV1 guide covers the tradeoffs in depth, but the short version for tone-mapped content:
- H.264 / libx264: Best compatibility. Use CRF 18–22 for tone-mapped content.
- H.265 / libx265: 30–40% smaller at same quality. Good for local storage; some older devices cannot play it.
- AV1 / libaom-av1: Best quality-to-size ratio but extremely slow to encode. Practical only with GPU encoders.
Because tone-mapped SDR content is being re-encoded from a decoded HDR source (two generations of compression), use a higher quality setting than you would for a direct transcoding job. CRF 18 rather than CRF 23 is a safe choice.
Frequently Asked Questions
Why does my HDR video look washed out after conversion?
The most common cause is a mismatch between the declared peak luminance (npl value) and the actual mastering display brightness. Try increasing npl to 1000 or 4000 and re-run the conversion.
Can I convert Dolby Vision to SDR for free?
Yes, with FFmpeg. Dolby Vision's proprietary enhancement layer is ignored during the conversion — you are working from the HDR10 base layer. The result is valid SDR with no licensing fees.
Does HDR to SDR conversion lose quality?
It is lossy by definition — you are discarding the HDR luminance range that SDR cannot display. However, with proper tone mapping, the SDR result can look excellent and is a faithful representation of the content on SDR displays.
What is the difference between tone mapping and color grading?
Tone mapping is an automatic algorithm that mathematically remaps the luminance range. Color grading is a manual artistic process where a colorist makes creative decisions about how HDR should look in SDR. For most users, tone mapping is sufficient; professional video productions use color grading.
Do I need a GPU to convert HDR to SDR?
No. FFmpeg's zscale filter runs on CPU. GPU-accelerated options exist (using hardware tone mapping via NVIDIA NVENC or Intel QSV), but CPU processing is completely functional and produces better quality.
Conclusion
Good HDR-to-SDR conversion comes down to choosing the right tone mapping operator, setting the peak luminance correctly for your source material, and ensuring the color primaries conversion happens in the pipeline. The FFmpeg commands in this guide cover the most common scenarios. For the codec decisions that affect the final file size, the H.265 vs H.264 comparison and video bitrate guide provide the context you need to make the right call. If you want to skip the command line entirely, the video converter handles the conversion server-side. For 4K HDR sources that need rotation or cropping before tone mapping, the video crop tool and rotate video tool can prepare the clip first.



