対象 OS: Linux(Intel iGPU / AMD GPU対応)

VAAPIとは

VAAPI(Video Acceleration API)は、LinuxでGPUに動画の処理をさせるための標準的な仕組みです。Intelの内蔵GPUとAMDのGPUで使えます(NVIDIAのGPUは、VAAPIではデコードにしか使えません)。GPUのエンコーダーを直接使うので、CPUでエンコードするより大幅に速くなります。

GPU VAAPI サポート
Intel iGPU H.264(Sandy Bridge以降。Haswell以前は旧ドライバーの i965 を使う)/H.265は新しい世代で対応。AV1エンコードはIntel Arc・一部の新しいXeに限定
AMD GPU H.264 / H.265 — VCE/VCNの世代・ドライバ依存。AV1はRDNA3以降
NVIDIA(nouveau など) デコードのみ(エンコードはNVENCを使う)

前提条件

必要なパッケージのインストール

Ubuntu / Debian:

※ このコマンドはVAAPI環境が必要です
sudo apt install vainfo libva-dev intel-media-va-driver-non-free  # Intel(Broadwell以降)
sudo apt install vainfo libva-dev i965-va-driver-shaders          # Intel(Haswell以前)
sudo apt install vainfo libva-dev mesa-va-drivers                 # AMD

-non-free が付かない intel-media-va-driver では、Broadwell で H.264 のエンコードができません。Intel 用の2つのパッケージは、Debian では non-free、Ubuntu では multiverse のリポジトリにあります。

Arch Linux:

※ このコマンドはVAAPI環境が必要です
sudo pacman -S intel-media-driver libva   # Intel
sudo pacman -S mesa libva                 # AMD

VAAPIデバイスの確認

※ このコマンドはVAAPI環境が必要です
vainfo

出力に VAEntrypointEncSlice などのエントリポイント(GPUができる処理の一覧)が並べば、準備はできています。

h264_vaapi の基本コマンド

※ このコマンドはVAAPI(Linux)環境が必要です
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 \
  -vf 'format=nv12,hwupload' \
  -c:v h264_vaapi -qp 23 \
  -c:a aac -b:a 128k output_vaapi.mp4

各オプションの意味:

  • -vaapi_device /dev/dri/renderD128:使うVAAPIデバイスを指定します。/dev/dri/renderD129 など、複数ある環境もあります。
  • -vf 'format=nv12,hwupload':フレームをGPUのメモリに送ります。これがないとエンコードできません。
  • -qp 23:画質の値です(1〜51で、小さいほど高画質。0は指定なしの扱い)。

hevc_vaapi(H.265)

※ このコマンドはVAAPI(Linux)環境が必要です
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 \
  -vf 'format=nv12,hwupload' \
  -c:v hevc_vaapi -qp 28 \
  -c:a aac -b:a 128k output_hevc_vaapi.mp4

av1_vaapi(AV1)— Intel Arc / Core Ultra以降

※ このコマンドはVAAPI(Linux / Intel Arc)環境が必要です
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 \
  -vf 'format=nv12,hwupload' \
  -c:v av1_vaapi -rc_mode CQP -global_quality 30 \
  -c:a aac -b:a 128k output_av1_vaapi.mp4

av1_vaapi には、h264_vaapi/hevc_vaapi で使う -qp がありません。付けても「Codec AVOption qp … has not been used for any stream」という警告が出るだけで、エンコードは既定の画質のまま進みます。画質を固定するなら -rc_mode CQP -global_quality 30、ビットレートを指定するなら -b:v 4M を使います。av1_vaapi の -global_quality はAV1の量子化の値(0〜255、指定しないときは25)で、-qp の1〜51とは目盛りが違い、小さいほど高画質です。AV1のエンコードに対応しているのは、Intel Arc(Alchemist)とCore Ultra(Meteor Lake)以降、AMD RDNA3以降のGPUです。

VAAPIデコード + エンコードのフルGPUパイプライン

デコードもGPU(VAAPI)で行うと、CPU使用率をほぼゼロにできます。

※ このコマンドはVAAPI(Linux)環境が必要です
ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 \
  -hwaccel_output_format vaapi \
  -i input.mp4 \
  -c:v h264_vaapi -qp 23 \
  -c:a copy output_fullgpu.mp4

デコードしたフレームを、GPUからCPUに移す必要がなくなります。

ビットレート指定エンコード

-rc_mode CBR はビットレートを一定に保つモードで、-b:v 4M でその値を決めます。

※ このコマンドはVAAPI(Linux)環境が必要です
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 \
  -vf 'format=nv12,hwupload' \
  -c:v h264_vaapi -rc_mode CBR -b:v 4M \
  -c:a aac -b:a 128k output_cbr.mp4

よくあるエラーと対処法

error while loading shared libraries: libva.so.2

libva が入っていません。Ubuntu では sudo apt install libva2 で入れます。

Device creation failed(/dev/dri/renderD128 が見つからない)

ls /dev/dri/ で、デバイスがあるか確認します。あわせて、GPUのカーネルモジュール(Intel は i915、AMD は amdgpu)が読み込まれているかも確認します。

format=nv12,hwupload なしでエラー

VAAPIのエンコーダーは、GPUのメモリにあるフレームしか受け取れません。そのため hwupload が必要です。

10ビットの素材が8ビットで出力される

nv12 は8ビットの形式です。format=nv12,hwupload を使うと、10ビットの素材も8ビットに変換されてから GPU に送られます。10ビットのまま出力するには、-vf 'format=p010le,hwupload' に変え、-profile:v main10 などの10ビット対応プロファイルを指定します。GPU とドライバーが10ビットに対応している必要があります。

VAAPIとNVENCの比較

項目 VAAPI(Intel/AMD) NVENC(NVIDIA)
対象GPU Intel iGPU / AMD GPU NVIDIA GPU
OS Linux主体 Windows / Linux
設定の複雑さ やや複雑(デバイス指定) 比較的シンプル
速度 高速 高速

速度と品質の目安

速さと画質は、GPUの世代やドライバー(Intelなら旧 i965 か、新しい iHD/media-driver か)で大きく変わります。

  • エンコード速度:内蔵GPU(iGPU)でも、CPUの libx264 -preset medium より速く処理できることが多く、Intel ArcやAMD RDNA系のような単体のGPU(ディスクリートGPU)では、さらに速いこともあります。
  • 画質:同じVMAF(画質を数値で表す指標)にそろえると、VAAPIは libx264 よりビットレートが多めに必要になりがちです。差の大きさは世代と素材で変わります。Intelの新しいmedia-driver(iHD)はQSVと同じような調整が効き、旧 i965 より画質が安定します。
  • AV1:Intel Arc / AMD RDNA3のAV1エンコードは、H.264と同じ画質をはっきり小さいサイズで出せることがあります。配信では特に効果があります。

つまずきやすいポイント

/dev/dri/renderD128 で権限エラー

  • 症状: No VA display found for device /dev/dri/renderD128. と出て、デバイスを作れない。-v verbose を付けると、Failed to open /dev/dri/renderD128 as DRM device node. も表示される。
  • 原因: 実行しているユーザーが render(または video)グループに入っていない。コンテナの中で特に起きやすい。
  • 対処: sudo usermod -aG render $USER でグループに追加し、ログインし直します。Dockerでは --device /dev/dri でデバイスを渡し、--group-add にホストのrenderグループのGIDを指定します。

format=nv12,hwupload を忘れて Impossible to convert between the formats が出る

  • 症状: フィルターを付けずに -c:v h264_vaapi を指定すると、形式を変換できないというエラーで止まる。
  • 原因: VAAPIのエンコーダーはGPUのメモリ上のフレーム(サーフェス)しか受け取れず、CPU側のフレームはそのまま渡せない。
  • 対処: -vf 'format=nv12,hwupload' を必ず付けます。デコードもGPUで行う場合(-hwaccel vaapi -hwaccel_output_format vaapi)は、フレームがすでにGPUにあるので hwupload はいりません。

複数GPU環境でデバイスを取り違える

  • 症状: 内蔵GPU(iGPU)を使いたいのに単体GPUが選ばれる。または、その逆。
  • 原因: /dev/dri/renderD128 と renderD129 のどちらがどのGPUかは、環境によって違う。
  • 対処: ls -l /dev/dri/by-path/ でPCIアドレスとデバイスの対応を確かめ、使いたいGPUの renderDxxx を -vaapi_device に書きます。

10ビット入力が8ビットになる

  • 症状: HDRや10ビットの素材を format=nv12,hwupload でエンコードすると、エラーは出ないまま8ビットで出力される。
  • 原因: nv12 は8ビットの形式なので、ここで8ビットに変換される。
  • 対処: -vf 'format=p010le,hwupload' に変えます。出力側でも、10ビット対応のプロファイル(-profile:v main10 など)を指定します。

よくある質問

VAAPIとQSV(Quick Sync)はどう違う?

どちらもIntelのGPUでハードウェアエンコードができます。VAAPIはLinuxの標準のAPIで、QSV(h264_qsv)はIntel独自のSDKを通して使います。Linuxで広く使うならVAAPIです。Intelの機能をすべて使いたいときや、Windowsでも使いたいときはQSVが候補になります。

-qp と -rc_mode のどちらで品質を決めるべき?

画質を一定にしたいなら -qp を使います(小さいほど高画質で、23前後が目安)。配信や容量の管理のためにビットレートをそろえたいなら、-rc_mode CBR -b:v 4M のようにビットレートで制御します。両方を狙うなら、-rc_mode VBR -b:v に -maxrate を組み合わせます。

AMD GPUでもVAAPIで使える?

使えます。mesa-va-drivers(Mesa Gallium)を入れ、カーネルの amdgpu モジュールが有効なら、h264_vaapi/hevc_vaapi が動きます。AV1のエンコードはRDNA3以降で使えます。

CPUエンコードと比べて画質が落ちた気がする

品質の値が同じでも、VAAPIは libx264 より効率がやや劣ります。そのため同じサイズだと、画質が下がって見えることがあります。-qp を1〜2下げるか、ビットレートを1〜2割上げると、差は目立たなくなります。

Dockerコンテナ内でVAAPIを使うには?

docker run --device /dev/dri ... でデバイスを渡し、コンテナ内のユーザーをホストの render グループのGIDに追加します。コンテナの中で vainfo が正しく動けば、準備はできています。

関連記事