How to Preserve HDR10 Metadata in FFmpeg HEVC

Transcoding HDR10 video using FFmpeg often results in a loss of dynamic range, causing the output video to look washed out because the essential HDR10 metadata is discarded by default. This guide provides a direct, step-by-step method to extract the original HDR10 metadata—specifically the Mastering Display Color Volume and Content Light Level—and inject it back into your newly transcoded HEVC/x265 video.

Step 1: Extract the Original HDR10 Metadata

Before transcoding, you must extract the metadata from the source file. Run the following ffprobe command to read the side data of the first frame:

ffprobe -v error -select_streams v:0 -show_frames -read_intervals "%+#1" -show_entries frame=side_data_list -of default=noprint_wrappers=1 input.mp4

Look for two specific blocks in the output:

  1. Mastering Display Metadata: This looks like G(x,y) B(x,y) R(x,y) WP(x,y) L(min,max).
    • Example output: G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(5,10000000)
  2. Content Light Level Metadata: This contains the MaxCLL and MaxFALL values.
    • Example output: max_content=1000, max_average=400

Step 2: Format the Metadata for FFmpeg

You must pass these values to the x265 encoder using the -x265-params flag. Format the values as follows:

Step 3: Run the Transcoding Command

To preserve the HDR10 color space and metadata, you must also specify the correct color primaries, transfer characteristics, and matrix coefficients (BT.2020 and PQ).

Use the following complete FFmpeg command, substituting the metadata values you extracted in Step 1:

ffmpeg -i input.mp4 -c:v libx265 -pix_fmt yuv420p10le -color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc -x265-params "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(5,10000000):max-cll=1000,400:hdr10=1" -c:a copy output.mp4

Command Parameter Breakdown