ffmpegでハードウェアエンコード (Intel, AMD, NVIDIA)

## この記事は？

あるとき ffmpeg でのハードウェアエンコードが気になって、調べて見つけた記事 & LinuxMint 上では動作確認できたコマンドのメモついでに手順を軽く記載 (というかほぼコピー)。

ffmpeg では、Intel の QSV、AMD の AMF、NVIDIA の NVENC を用いてハードウェアエンコードをすることができます。

デフォルトの ffmpeg では、ソフトウェアエンコードだけです。(多分)(でも Linux Mint では、apt からパッケージで ffmpeg をインストールした所、NVENC が利用可能な状態でした。)

ハードウェアエンコードをするには、モジュールを準備し、自力で ffmpeg をビルドする必要があります。この記事では、QSV、AMF、NVENC の ffmpeg への導入 & ビルド方法をまとめました。

ここに示した手順を全て行えば、Intel GPGPU でも AMD GPU でも NVIDIA GPU でも、好きなものでハードウェアエンコードできる ffmpeg  を構築できます。(全部使うことは普通無いですが。3社のハード PC を使っている~~変態~~変わった環境の人であれば話は別です。)

## 環境

ここに表示する手順及びコマンドは、以下の環境で実行を確認したものです。

| 項目 | 型番等 |
| --- | --- |
| OS | Linux Mint 20.2 Uma 64bit |
| CPU | Intel Core i3-7020U |
| グラフィック | Mesa Intel HD Graphics 620 (KBL GT2) |

NVIDIA, AMD の GPU エンコードについては、マシンを持っていないため、ヘルプ表示しか確認していないです。
(確認できてないものを公開って良く無いですが･･･。)

## ビルドツールの準備

モジュールの準備から ffmpeg のビルドまで、ビルドをするにあたって必須のツールをまずはインストールします。

```sh
sudo apt install build-essential git cmake pkg-config wget
```

## QSV の準備

### 0. 概要 & 手順目次

QSV (Intel Quick Sync Video) は、Intel CPU の内蔵 GPU (GPGPU) を用いてハードウェアエンコードができるものです。

1. libva のインストール
2. VA-API ドライバのインストール
3. Media SDK のインストール

(インストールと一言で言っていますが、ソースのダウンロード、及びビルドも手動で行います。)
Intel CPU の GPGPU を使ったハードウェアエンコードが必要でない場合は、この項をスキップしてください。

参照元:

<https://qiita.com/Daigorian/items/3b5bf97f58b071e0945d>

### 1. libva のインストール

環境によっては、libva2 というパッケージが入っている場合もありますが、これでは Media SDK のインストールで進めなくなるので、(恐らく) どのみちこの手順は必須です。

```sh
# 依存パッケージ & 必要なツールインストール
sudo apt install meson libdrm-dev automake libtool

# ソースダウンロード & ビルド & インストール
git clone https://github.com/intel/libva.git
cd libva
mkdir b && cd b
../autogen.sh
make -j5
sudo make install
```

b というディレクトリを作って、その中でビルド作業を行っていますが、この手順は無くても問題はありません。
(build というディレクトリが初めから存在するので、変わりに b で。)

`make`のオプション`-j5`ですが、これは並列で実行するジョブ数の最大数指定です。
(CPU のスレッド数+1 を指定るすと良いっぽいです。私の環境は 4スレッドなので 5です。)
指定無しだと最大 1つ、つまり並列実行無しとなります。
他の作業を並列で行っている等なければ、オプションをつけることを推奨します。
(大規模なビルドだと、けっこうな時間がかかります。)

ビルドしてインストールされた libva は、`/usr/local/lib`に配置されます。
ここは`LD-PATH`に含まれておらず、MediaSDK のビルドで認識されません。
以下のコマンドで`LD-PATH`に追加します。

```sh
sudo sh -c "echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf"
sudo ldconfig
```

### 2. VA-API ドライバのインストール

```sh
# 依存パッケージインストール
sudo apt install libpciaccess-dev

# 依存ライブラリ Intel(R) Graphics Memory Management Library のビルド & インストール
git clone https://github.com/intel/gmmlib.git
cd gmmlib/
mkdir build && cd build
cmake ..
make -j5
sudo make install

# VA-API ドライバ iHD_drv_video.so のビルド & インストール
# 'cd ~' 等で適当な位置にカレントを移しておく
git clone https://github.com/intel/media-driver.git
cd media-driver
mkdir build && cd build
cmake ..
make -j5
sudo make install
```

libva と VA-API ドライバのインストールができれば、VA-API が利用可能になっているハズです。
vainfo で VA-API の状況を確認します。

```sh
# vainfo をパッケージからインストール
sudo apt install vainfo

# vainfo を実行
vainfo
```

`va_openDriver() returns -1`というエラーが無ければ OK です。

### 3. Media SDK のインストール

```sh
# ソースダウンロード & ビルド & インストール
git clone https://github.com/Intel-Media-SDK/MediaSDK.git
cd MediaSDK
mkdir build && cd build
cmake ..
make -j5
sudo make install
```

ビルドしてインストールされた MediaSDK は、`/opt/intel/mediasdk/lib`に配置されます。
ここは`LD-PATH`に含まれておらず、ffmpeg のビルドで認識されません。
以下のコマンドで`LD-PATH`に追加します。

```sh
sudo sh -c "echo /opt/intel/mediasdk/lib/ >> /etc/ld.so.conf.d/mediasdk.conf"
sudo ldconfig
```

SDK の準備ができたら、あとは ffmpeg のビルドです。
`configure`実行時に`--enable-libmfx`オプションをつけることで、QSV が有効化されます。(後述)

## AMF の準備

### 概要 & 手順目次

AMF (Advanced Media Framework) は、AMD の GPU を用いてハードウェアエンコ (ry

1. AMF のダウンロード
2. ソース (SDK) を所定のパスへ配置

ソースを配置するだけです。
AMD の GPU を使ったハードウェアエンコードをしない場合は、この項はスキップしてください。

参照元:

<https://nico-lab.net/installing_amd-vce_with_ffmpeg/>

### SDK のダウンロードと配置

```sh
# SDK のダウンロード
git clone https://github.com/GPUOpen-LibrariesAndSDKs/AMF.git

# SDK の配置
cd AMF/amf/public/include
sudo mkdir /usr/local/include/AMF
sudo cp -r ./* /usr/local/include/AMF/
```

あとは ffmpeg のビルドだけです。
追加のオプション等も必要無く、ビルドすれば自動で検出され、有効化されます。

## NVENC の準備

### 概要 & 手順目次

NVENC は、NVIDIA の GPU を用いて (ry

1. NVIDIA headers をダウンロード
2. make コマンドでソース (ヘッダファイル) を所定の位置へ配置

make コマンドで配置できるので、AMF よりも簡単に終わります。
NVIDIA の GPU を使ったハードウェアエンコードをしない場合は、この項はスキップしてください。

参照元:

<https://nico-lab.net/installing_cuda_with_ffmpeg/>

### SDK のダウンロードと配置

```sh
# SDK のダウンロード
git clone https://github.com/FFmpeg/nv-codec-headers.git

# SDK の配置
cd nv-codec-headers
sudo make install PREFIX=/usr
```

あとは ffmpeg のビルドだけです。
追加のオプション等も必要無く、ビルドすれば自動で検出され、有効化されます。

## ffmpeg のビルド

パッケージからのインストールではなく、手動ビルドとインストールなので、依存パッケージも自前で用意してやる必要があります。

```sh
# non-free リポジトリの追加
sudo apt install software-properties-common
sudo apt-add-repository non-free

# 依存パッケージのインストール
sudo apt update
sudo apt install \
   autoconf \
   automake \
   build-essential \
   cmake \
   git-core \
   libass-dev \
   libfreetype6-dev \
   libgnutls28-dev \
   libsdl2-dev \
   libtool \
   libva-dev \
   libvdpau-dev \
   libvorbis-dev \
   libxcb1-dev \
   libxcb-shm0-dev \
   libxcb-xfixes0-dev \
   pkg-config \
   texinfo \
   yasm \
   zlib1g-dev \
   nasm \
   libx264-dev \
   libx265-dev \
   libnuma-dev \
   libvpx-dev \
   libfdk-aac-dev \
   libmp3lame-dev \
   libopus-dev \
   libaom-dev

# QSV の MediaSDK の pkgconfig が非標準の場所にあるので、環境変数 PKG_CONFIG_PATH で参照を追加
# (QSV 未使用時はこの手順はスキップで OK)
export "PKG_CONFIG_PATH=/opt/intel/mediasdk/lib/pkgconfig:$PKG_CONFIG_PATH"
# fish 上では「"」が無いとうまく動きませんでした

# ソースダウンロード
## tar でダウンロードする場合
wget https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2
tar xjvf ffmpeg-snapshot.tar.bz2
## git でダウンロードする場合 (こちらの方が容量が多いので注意)
git clone https://git.ffmpeg.org/ffmpeg.git

# ビルド & インストール
# ソースのルートディレクトリでビルドしないと make でエラーになります
# mkdir build && cd build 等は行わずにビルドしましょう
cd ffmpeg
./configure \
  --extra-libs="-lpthread -lm" \
  --enable-libmfx \
  --enable-gpl \
  --enable-gnutls \
  --enable-libaom \
  --enable-libass \
  --enable-libfdk-aac \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 \
  --enable-nonfree
make -j5
sudo make install
```

QSV を使う場合、`./configure`で`--enable-libmfx`が必要になります。
Intel の MediaSDK を準備していない場合、このオプションは外してください。
AMF、NVENC は、使用の有無に関わらず、特に追加のオプションはありません。

## 確認 & 実行例

ハードウェアエンコードが利用可能になっているか確認します。
次のコマンドで、ffmpeg で利用可能なエンコーダを確認できます。

```sh
ffmpeg -encoders
```

```txt
(略)
 V....D h264_amf             AMD AMF H.264 Encoder (codec h264)
 V....D h264_nvenc           NVIDIA NVENC H.264 encoder (codec h264)
 V..... h264_qsv             H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration) (codec h264)
(略)
```

以下のようにすることで、ハードウェアエンコードが実行できます。

```sh
ffmpeg -i Input.mp4 -c:v h264_qsv -q:v 25 Output.mp4
```

ビデオコーデック指定`-c:v`で、使用するエンコーダを指定できます。

H.264 コーデックの場合、QSV なら`h264_qsv`、AMF なら`h264_amf`、NVENC なら`h264_nvenc`です。(ソフトウェアエンコードだと`libx264`)

H.265 (HEVC) の場合、同様にして`hevc_XXX`です。

`-q:v`は品質指定です。0に近いほど高品質大容量、100に近いほど低品質小容量です。(QSV では、オプション無しだとだいぶ低めの品質設定？)