FFmpeg zscale HDR10 to Rec 709 SDR Conversion

This article explains how to use the zscale filter in FFmpeg to tone-map and convert High Dynamic Range (HDR10 / Rec. 2020) video into Standard Dynamic Range (SDR / Rec. 709) video. You will learn the exact command-line syntax required to perform this conversion using dynamic peak detection for optimal visual quality.

Converting HDR10 to SDR requires translating high-luminance color spaces into a narrower range without losing image detail. The zscale filter (which uses the ZImg library) is highly recommended for this task because of its superior scaling, dithering, and color space conversion accuracy compared to the default scale filter.

The FFmpeg Command

To convert Rec. 2020 HDR10 to Rec. 709 SDR using zscale and peak detection, run the following command:

ffmpeg -i input_hdr.mp4 -vf "zscale=t=linear,tonemap=tonemap=hable:peak=0,zscale=p=bt709:t=bt709:m=bt709:r=limited,format=yuv420p" -c:v libx264 -crf 20 -c:a copy output_sdr.mp4

How the Filter Chain Works

The video filter chain (-vf) is broken down into four distinct steps to ensure accurate color mapping:

  1. zscale=t=linear This step converts the input transfer characteristics (typically SMPTE 2084 / PQ for HDR10) into linear light. Tone mapping algorithms require linear light to correctly calculate brightness adjustments.

  2. tonemap=tonemap=hable:peak=0 This performs the actual tone mapping.

    • tonemap=hable: Uses the Hable (film-like) tone-mapping algorithm, which preserves highlights and shadow details effectively. You can also use reinhard or mobius.
    • peak=0: This is the parameter for peak detection. Setting the peak to 0 instructs FFmpeg to automatically and dynamically detect the peak luminance of the video frames, preventing the image from becoming washed out or overly dark.
  3. zscale=p=bt709:t=bt709:m=bt709:r=limited Once tone-mapped, this second zscale pass converts the linear video into the standard Rec. 709 color space:

    • p=bt709: Sets the color primaries to BT.709.
    • t=bt709: Sets the transfer characteristics (gamma curve) to BT.709.
    • m=bt709: Sets the matrix coefficients to BT.709.
    • r=limited: Forces limited color range, which is the standard for web and television playback.
  4. format=yuv420p HDR10 videos are encoded in 10-bit color (usually yuv420p10le). This final filter converts the pixel format down to standard 8-bit yuv420p to guarantee compatibility with all standard SDR displays and players.