対象 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 が正しく動けば、準備はできています。