How to Use tonemap_vaapi in FFmpeg
This article provides a practical guide on using FFmpeg's
tonemap_vaapi filter to convert High Dynamic Range (HDR)
video to Standard Dynamic Range (SDR) using VA-API hardware
acceleration. You will learn the required hardware setup, essential
filter options, and complete command-line examples for both
full-hardware pipelines and hybrid workflows.
Prerequisites
To use tonemap_vaapi, you must meet the following
requirements:
- A compatible Intel or AMD GPU that supports VA-API tone-mapping (typically Intel Gen9 Skylake or newer, or modern AMD GPUs).
- FFmpeg compiled with
--enable-vaapiand relevant driver support (intel-media-driver/iHDorradeonsi). - Access to the direct rendering device node, typically
/dev/dri/renderD128.
Understanding the Filter Parameters
The tonemap_vaapi filter maps wide color gamuts and high
dynamic ranges down to standard color profiles directly inside GPU
memory. Key parameters include:
format: The output pixel format. For standard SDR H.264/H.265 encoding, usenv12.p/primaries: Target color primaries. Common setting:bt709.t/transfer: Target transfer characteristics. Common setting:bt709.m/matrix: Target color space matrix. Common setting:bt709.
Complete Hardware Pipeline (Decode, Tonemap, Encode)
The most efficient way to use tonemap_vaapi is to keep
all frame data in GPU memory from decoding through encoding. This
eliminates the overhead of copying frames between system RAM and video
RAM.
ffmpeg -init_hw_device vaapi=va:/dev/dri/renderD128 \
-hwaccel vaapi -hwaccel_output_format vaapi \
-i input_hdr.mkv \
-vf "tonemap_vaapi=format=nv12:p=bt709:t=bt709:m=bt709" \
-c:v h264_vaapi -b:v 8M -c:a copy \
output_sdr.mp4Breakdown of the command:
-init_hw_device vaapi=va:/dev/dri/renderD128: Initializes the VA-API device context.-hwaccel vaapi -hwaccel_output_format vaapi: Decodes the HDR stream directly into hardware surfaces.-vf "tonemap_vaapi=format=nv12:p=bt709:t=bt709:m=bt709": Maps the color space from HDR10 (BT.2020 / SMPTE 2084) to SDR (BT.709) and sets the pixel format to NV12.-c:v h264_vaapi: Encodes the tonemapped video using the VA-API H.264 encoder.
Hybrid Workflow (Software Decode, VA-API Tonemap)
If your GPU does not support hardware decoding of the specific HDR profile (such as 10-bit HEVC), you can decode on the CPU and upload frames to the GPU for tone-mapping and encoding.
ffmpeg -init_hw_device vaapi=va:/dev/dri/renderD128 \
-i input_hdr.mkv \
-vf "format=p010,hwupload,tonemap_vaapi=format=nv12:p=bt709:t=bt709:m=bt709" \
-c:v h264_vaapi -b:v 8M -c:a copy \
output_sdr.mp4Breakdown of additions:
format=p010: Ensures software-decoded frames are in a 10-bit format compatible with VA-API upload.hwupload: Moves frames from host memory to the VA-API hardware surfaces before processing withtonemap_vaapi.
Exporting to Software Encoders (e.g., libx264)
If you require software encoding (such as libx264 for
higher compression efficiency), download the tonemapped frames back to
system memory using hwdownload:
ffmpeg -init_hw_device vaapi=va:/dev/dri/renderD128 \
-hwaccel vaapi -hwaccel_output_format vaapi \
-i input_hdr.mkv \
-vf "tonemap_vaapi=format=nv12:p=bt709:t=bt709:m=bt709,hwdownload,format=nv12" \
-c:v libx264 -crf 20 -preset medium -c:a copy \
output_sdr.mp4Note: The trailing format=nv12 filter after
hwdownload removes the hardware surface wrapper so the
software encoder can process the raw frames.