HDR vs SDR
HDR (High Dynamic Range) is the newer and more advanced version of display technology that shows more colorful and brighter pictures on displays that support it. It is much superior to its predecessor SDR.
Videos in HDR format use 10-bits for storing color information and use different color transfer functions compared to SDR videos. For example SDR videos use the BT.709 color space whereas HDR uses BT.2020 along with SMPTE2084 color transfer function.
If you are working with an hdr video, there could be a number of reasons to convert it to SDR. If you are working on a system that does not support HDR, then the colors might look washed out (pale/faded). The only way to work around this to convert the video to SDR which will make it look similar (but inferior) to the HDR version without loosing too much color information.
In this post we shall take a look at how to convert an hdr video to sdr video using ffmpeg from the command line.
Check with ffprobe
The original video details as shown by ffprobe:
ffprobe .\costa_rica_4k_60fps_hdr_uhd.webm -hide_banner Input #0, matroska,webm, from '.\costa_rica_4k_60fps_hdr_uhd.webm': Metadata: ENCODER : Lavf59.27.100 Duration: 00:05:13.80, start: -0.007000, bitrate: 28952 kb/s Stream #0:0(eng): Video: vp9 (Profile 2), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn (default) Metadata: DURATION : 00:05:13.780000000 Side data: Content Light Level Metadata, MaxCLL=1100, MaxFALL=180 Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6780,0.3220) g(0.2450,0.7030) b(0.1380 0.0520) wp(0.3127, 0.3290) min_luminance=0.000000, max_luminance=1000.000000 Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default) Metadata: DURATION : 00:05:13.801000000 >
Note the stream details indicating HDR:
yuv420p10le(tv, bt2020nc/bt2020/smpte2084)
It indicates 10-bit color in bt2020 colorspace using smpte2084 color transfer function which is commonly used in HDR videos. If you see these details in any video then it is very likely saved in HDR format (and consequently needs an hdr capable display and media program to play properly).
The same details can be checked with VLC Player as well.
Converting to SDR
First try converting a small duration of the clip with the ss and t options to verify if the output quality is acceptable or not.
ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -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 -ss 5 -t 10 .\costa_rica_4k_60fps_sdr_uhd-10s.libx264.mp4
The above command will try to preserve the color and keep them as similar to the original, though it can never be like hdr quality. The filter process is a chain of multiple processing stages over here:
- 1. zscale=t=linear:npl=100
- 2. format=gbrpf32le
- 3. zscale=p=bt709
- 4. tonemap=tonemap=hable:desat=0
- 5. zscale=t=bt709:m=bt709:r=tv
- 6. format=yuv420p
Check the documentation of zscale filter and tonemap filter and format filter
Fast Decoding Format: To optimise the video for fast decoding, we can use the -tune option and set it to fastdecode. Though this is not necessary.
ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -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 -tune fastdecode -ss 5 -t 10 .\costa_rica_4k_60fps_sdr_uhd.mp4
Other options: Can also use options like crf and preset for quality control and size optimisation
ffmpeg -i video-input.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 libx265 -crf 22 -preset medium -tune fastdecode video-output.mp4
Other Commands
If you try to convert like this:
ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v libx264 -pix_fmt "yuv420p" -ss 5 -t 10 .\costa-10s.libx264.mp4
It will still retain the HDR format.
Hi! This is great! Can you help put together a guide for using QSV and tonemapping hdr to sdr? I’m really struggling!
Here’s what I have right now that works:
ffmpeg -init_hw_device qsv=hw -filter_hw_device hw -i input.mkv -vf zscale=transfer=linear,tonemap=clip,zscale=transfer=bt709,format=yuv420p,scale=1280:-2 -vcodec h264_qsv -map 0:v -map 0:a:0 -map 0:a:1 -c:a copy -map 0:s:0 -c:s copy outputfile720p.mkv
What this is doing:
1)UHD HDR hevc source
2)Tonemapping
3)Scaling to 720p
4) Encoding to h264
5) Copying the first two audio tracks and the first subtitle track using the map function. I have to map video as well or else it fails.
This correctly tonemaps, and I can tell via intel_gpu_top that some gpu is being used, but the filter is not going through qsv.
Bonus question: I can’t get global_quality to work, how does that work with -vcodec h264_qsv