FFmpeg VAAPI Device Initialization and Deinterlacing

This guide provides a direct walkthrough on initializing a VAAPI (Video Acceleration API) device in FFmpeg and applying the hardware-accelerated deinterlace_vaapi filter. Utilizing VAAPI offloads deinterlacing directly to compatible Intel or AMD GPUs, significantly lowering CPU consumption while maintaining high-speed video processing on Linux systems.

Initializing the VAAPI Device

To use VAAPI filters, FFmpeg must first initialize the hardware context pointing to your GPU's DRM render node (typically /dev/dri/renderD128).

Device initialization is defined before the input using either the legacy shortcut flag or the generic hardware device flag:

  • Shortcut flag: -vaapi_device /dev/dri/renderD128
  • Generic flag: -init_hw_device vaapi=va:/dev/dri/renderD128

Understanding Hardware Surface Requirements

The deinterlace_vaapi filter operates strictly on VAAPI hardware surfaces, not software pixel formats like YUV420P. Your pipeline must provide frames in vaapi pixel format. This is accomplished in one of two ways:

  1. Hardware Decoding: Decode directly into VAAPI memory using -hwaccel vaapi -hwaccel_output_format vaapi.
  2. Software Upload: Decode on the CPU and upload the frames to GPU memory inside the filter chain using format=nv12,hwupload.

The deinterlace_vaapi Filter Syntax

The basic filter call is simply deinterlace_vaapi. It accepts parameters to tune the output:

  • mode: Specifies the deinterlacing algorithm.
    • default: Driver default (typically motion-adaptive).
    • bob: Bob deinterlacing.
    • weave: Weave deinterlacing (no interpolation).
    • motion_adaptive: Motion-adaptive algorithm.
    • motion_compensated: Motion-compensated algorithm.
  • rate: Specifies frame rate output.
    • frame: Output one frame for each frame (preserves input frame rate).
    • field: Output one frame for each field (doubles the frame rate, e.g., 29.97i to 59.94p).

Complete Command Examples

1. Full Hardware Pipeline (Decode, Deinterlace, Encode)

This is the most efficient method because the video stays in GPU memory throughout the entire transcode process.

ffmpeg -vaapi_device /dev/dri/renderD128 \
  -hwaccel vaapi -hwaccel_output_format vaapi \
  -i input_interlaced.mp4 \
  -vf "deinterlace_vaapi=mode=motion_adaptive:rate=field" \
  -c:v h264_vaapi -b:v 5M \
  -c:a copy output_progressive.mp4

2. Software Decode with Hardware Deinterlacing

If your input codec cannot be hardware-decoded by VAAPI, decode using the CPU, upload the frames to the GPU for deinterlacing, and encode using the GPU:

ffmpeg -init_hw_device vaapi=hw:/dev/dri/renderD128 \
  -filter_hw_device hw \
  -i input_interlaced.mkv \
  -vf "format=nv12,hwupload,deinterlace_vaapi=rate=frame" \
  -c:v h264_vaapi -qp 24 \
  -c:a copy output_progressive.mp4

3. Hardware Deinterlace with Software Encoding

If you need to encode using a CPU-based encoder (such as libx264), you must download the frames back to system memory using hwdownload after deinterlacing:

ffmpeg -vaapi_device /dev/dri/renderD128 \
  -hwaccel vaapi -hwaccel_output_format vaapi \
  -i input_interlaced.ts \
  -vf "deinterlace_vaapi=rate=field,hwdownload,format=nv12" \
  -c:v libx264 -crf 20 -preset fast \
  -c:a copy output_progressive.mp4