intel Arc GPUでHWEncode環境

さくらのアドベントカレンダー2022 20日目の記事です。

https://qiita.com/advent-calendar/2022/sakura

どうも、さくらインターネット　やまけんです。

2日目で　さくらのクラウドでUniFi Network Applicationを動かす

https://qiita.com/yamakenjp/items/24c9ad1f98fb1fa89e4a

こちらの紹介をしましたが、今度はGPUでのハードウェアエンコードのお話です。
GPUでのハードウェアエンコードの話は、2018年にnvidiaのNVENCを使うお話を。

https://qiita.com/yamakenjp/items/7474f210efd82bb28490

2021年にはハードウェアエンコードでの品質比較の話をさせていただきました。

https://qiita.com/yamakenjp/items/6a37afef25b1e4254669

今回は、今年発売されたIntelのGPU Intel Arcを使ったハードウェアエンコード環境作成のお話をさせていただきます。

# はじめに

intelは今年に入り20数年ぶりに単体GPUカード市場に再参入しました。
とはいえ、再参入と言っても、過去に出したGPUカードはIntel740という製品で、このカードは当時スペック詐欺と言われ全く売れず、その後のi810チップセットの内蔵グラフィックや、CPU内蔵グラフィックという形で単体GPUではなく、お世辞にも性能が高いわけでもなく、表示ができる程度のものがずっと続いていました。
ちなみに黒歴史化してるらしく、アスキーの記事にされています。

https://ascii.jp/elem/000/000/666/666972/

一応当時を知る身から一言だけ言わせてもらうと、intelはDirect Memory Executionという、当時としては画期的かつ今のグラボにも応用されている先進機能を搭載したあたりは評価されるべきだし、本当はRDRAMが廉価で提供できれば、この機能を最大限活用できただろうが、そうはならなかったと言うところ。

そんなintelは細々とCPUにiGPUというのを長く続けており、ハードウェアデコーダやエンコーダを搭載し、ゲームをするには心細いが、最低限の機能は兼ね備えています。

昨年の記事でも変換速度はNVEncには敵わないものの、品質についてはNVEncよりも高いものとなっており、バランスのとれたものでありました。

ここに来て、新たに発売されたIntel Arcシリーズは新たにAV1のハードウェアエンコーダをGPUとして初搭載したり（現在はNVIDIA Ada Lovelace世代でも搭載しました)と少し先進的な取り組みをしています。

そんな新しいGPUのハードウェアエンコーダ性能を検証しようと言う内容です。

# 必須環境
Intel Arcが載っている Ubuntu 24.04 x86_64 マシン

SPARKLE Intel Arc A310 ECOがおすすめです。
1Uサイズ、low profile PCIe、50W補助電源不要でサーバマシンにも組み込めます。
実売15k円ぐらい

https://kakaku.com/item/K0001598620/


## 準備
### ドライバ用リポジトリーの追加
下記を参考にリポジトリの追加を行います。

https://dgpu-docs.intel.com/driver/client/overview.html#installing-client-gpus-on-ubuntu-desktop-24-04-lts

```
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \
  sudo gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg

echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu noble unified" | \
  sudo tee /etc/apt/sources.list.d/intel-gpu-noble.list

sudo apt-get update && sudo apt-get install -y intel-media-va-driver-non-free
```



### GPUの認識確認

```
#　GPU認識の確認
sudo lspci -v |grep -A8 VGA
```
下記の結果のようになります。
```
ubuntu@intel-arc:~$ lspci -v |grep -A8 VGA
03:00.0 VGA compatible controller: Intel Corporation DG2 [Arc A310] (rev 05) (prog-if 00 [VGA controller])
	Subsystem: Device 172f:4019
	Flags: bus master, fast devsel, latency 0, IRQ 130, IOMMU group 1
	Memory at de000000 (64-bit, non-prefetchable) [size=16M]
	Memory at c0000000 (64-bit, prefetchable) [size=256M]
	Expansion ROM at df000000 [disabled] [size=2M]
	Capabilities: [40] Vendor Specific Information: Len=0c <?>
	Capabilities: [70] Express Endpoint, MSI 00
	Capabilities: [ac] MSI: Enable+ Count=1/1 Maskable+ 64bit+
ubuntu@intel-arc:~$ 
```
きちんと認識しているのが確認できました。

しかし、このままでは、エンコードに使う /dev/dri/renderD128 のパーミッションの問題で、一般ユーザーでffmpegを使う場合、HWエンコードができなくなります。

```
ubuntu@intel-arc:~$ ls -l /dev/dri/render*
crw-rw---- 1 root render 226, 128 Feb 23 19:06 /dev/dri/renderD128
ubuntu@intel-arc:~$
```

そこで、一般ユーザーでもアクセス可能にするための設定ファイルを作成します。

```
sudo vi /etc/udev/rules.d/99-render.rules
```

```99-render.rules
KERNEL=="render*" GROUP="render", MODE="0666"
```

設定反映のためにOS再起動後、デバイスのパーミッションを確認します。

```
ubuntu@intel-arc:~$ ls -l /dev/dri/render*
crw-rw-rw- 1 root render 226, 128 Feb 24 12:36 /dev/dri/renderD128
ubuntu@intel-arc:~$ 
```

### ドライバインストールの確認

hwinfoをインストールし、ドライバインストールができているか確認します。

```
sudo apt-get -y install hwinfo
```

```
sudo hwinfo --display
```

下記のように `Driver Status: xe is active` なっていればOKです

```
ubuntu@intel-arc:~$ sudo hwinfo --display
07: PCI 300.0: 0300 VGA compatible controller (VGA)             
  [Created at pci.386]
  Unique ID: svHJ.LFWyWCHJn5D
  Parent ID: GA8e.mr2N3fBJq5F
  SysFS ID: /devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0
  SysFS BusID: 0000:03:00.0
  Hardware Class: graphics card
  Model: "Intel VGA compatible controller"
  Vendor: pci 0x8086 "Intel Corporation"
  Device: pci 0x56a6 
  SubVendor: pci 0x172f 
  SubDevice: pci 0x4019 
  Revision: 0x05
  Driver: "i915"
  Driver Modules: "i915"
  Memory Range: 0xde000000-0xdeffffff (rw,non-prefetchable)
  Memory Range: 0xc0000000-0xcfffffff (ro,non-prefetchable)
  Memory Range: 0xdf000000-0xdf1fffff (ro,non-prefetchable,disabled)
  IRQ: 130 (373 events)
  Module Alias: "pci:v00008086d000056A6sv0000172Fsd00004019bc03sc00i00"
  Driver Info #0:
    Driver Status: i915 is active
    Driver Activation Cmd: "modprobe i915"
  Driver Info #1:
    Driver Status: xe is active
    Driver Activation Cmd: "modprobe xe"
  Config Status: cfg=new, avail=yes, need=no, active=unknown
  Attached to: #20 (PCI bridge)

Primary display adapter: #7
ubuntu@intel-arc:~$ 
```

メディアドライバの確認

```
sudo apt-get -y install vainfo
vainfo
```

下記のように `vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 24.4.4 ()` と表示されており
`vainfo: VA-API version: 1.22 (libva 2.22.0)` とlibvaのバージョンが2.19.0 以上であれば大丈夫です。

```
ubuntu@intel-arc:~$ sudo vainfo
Trying display: wayland
Trying display: x11
error: can't connect to X server!
Trying display: drm
libva info: VA-API version 1.22.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_22
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 24.4.4 ()
vainfo: Supported profile and entrypoints
      VAProfileNone                   :	VAEntrypointVideoProc
      VAProfileNone                   :	VAEntrypointStats
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSliceLP
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSliceLP
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileJPEGBaseline           :	VAEntrypointEncPicture
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSliceLP
      VAProfileHEVCMain               :	VAEntrypointVLD
      VAProfileHEVCMain               :	VAEntrypointEncSliceLP
      VAProfileHEVCMain10             :	VAEntrypointVLD
      VAProfileHEVCMain10             :	VAEntrypointEncSliceLP
      VAProfileVP9Profile0            :	VAEntrypointVLD
      VAProfileVP9Profile0            :	VAEntrypointEncSliceLP
      VAProfileVP9Profile1            :	VAEntrypointVLD
      VAProfileVP9Profile1            :	VAEntrypointEncSliceLP
      VAProfileVP9Profile2            :	VAEntrypointVLD
      VAProfileVP9Profile2            :	VAEntrypointEncSliceLP
      VAProfileVP9Profile3            :	VAEntrypointVLD
      VAProfileVP9Profile3            :	VAEntrypointEncSliceLP
      VAProfileHEVCMain12             :	VAEntrypointVLD
      VAProfileHEVCMain422_10         :	VAEntrypointVLD
      VAProfileHEVCMain422_10         :	VAEntrypointEncSliceLP
      VAProfileHEVCMain422_12         :	VAEntrypointVLD
      VAProfileHEVCMain444            :	VAEntrypointVLD
      VAProfileHEVCMain444            :	VAEntrypointEncSliceLP
      VAProfileHEVCMain444_10         :	VAEntrypointVLD
      VAProfileHEVCMain444_10         :	VAEntrypointEncSliceLP
      VAProfileHEVCMain444_12         :	VAEntrypointVLD
      VAProfileHEVCSccMain            :	VAEntrypointVLD
      VAProfileHEVCSccMain            :	VAEntrypointEncSliceLP
      VAProfileHEVCSccMain10          :	VAEntrypointVLD
      VAProfileHEVCSccMain10          :	VAEntrypointEncSliceLP
      VAProfileHEVCSccMain444         :	VAEntrypointVLD
      VAProfileHEVCSccMain444         :	VAEntrypointEncSliceLP
      VAProfileAV1Profile0            :	VAEntrypointVLD
      VAProfileAV1Profile0            :	VAEntrypointEncSliceLP
      VAProfileHEVCSccMain444_10      :	VAEntrypointVLD
      VAProfileHEVCSccMain444_10      :	VAEntrypointEncSliceLP
ubuntu@intel-arc:~$ 
```

## oneAPI Toolkitsのインストール

IntelGPUではIntel Media SDKを使っていましたが、新しいGPUからoneAPIを使うようになりました。
oneAPIの中のintelVPLというのが該当のものですが、MediaSDKを置き換える存在になっています。

https://www.intel.com/content/www/us/en/developer/tools/vpl/overview.html

今回は下記のAPTにてインストールします。

https://www.intel.com/content/www/us/en/docs/oneapi/installation-guide-linux/2025-0/apt-005.html

```
wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \
| gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null

echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list

sudo apt-get update && sudo apt-get -y install intel-basekit libvpl-dev
```

### intelVPL GPUのインストール
oneVPL自体はパッケージでのインストールが完了していますが、GPU Runtimeは別途インストールが必要です。

https://github.com/intel/vpl-gpu-rt

インストール
```
sudo apt-get -y install git build-essential pkg-config cmake automake autoconf libva-dev libdrm-dev

git clone https://github.com/intel/vpl-gpu-rt vpl-gpu-rt
cd vpl-gpu-rt

mkdir build && cd build
cmake ..
make
sudo make install
```

上記にてoneVPL GPUランタイムがインストールされます。


## FFmpegのインストール
Compile FFmpeg for Ubuntu, Debian, or Mint

https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu

こちらをベースにパッケージベースで入れていきます。

intel GPUでのHWエンコードについては

https://trac.ffmpeg.org/wiki/Hardware/QuickSync

に記載があるとおり

```
Build FFmpeg with oneVPL
 ./configure --enable-libvpl && make -j8 && make install
```

とのことなので、--enable-libvpl をつければ良いということです。

個人的にhapエンコードを使いたいので libsnappy-dev をインストールの上
`--enable-libsnappy` を追記しています。

またTLS対応のために libssl-dev をインストールの上
`--enable-openssl` を追記しています。

```
#FFmpegコンパイルに必要なものを導入
sudo apt-get update -qq && sudo apt-get -y install \
  autoconf \
  automake \
  build-essential \
  cmake \
  git-core \
  libass-dev \
  libfreetype6-dev \
  libgnutls28-dev \
  libmp3lame-dev \
  libssl-dev \
  libtool \
  libva-dev \
  libvorbis-dev \
  libsnappy-dev \
  meson \
  ninja-build \
  pkg-config \
  texinfo \
  wget \
  yasm \
  zlib1g-dev

#作業ディレクトリ作成
mkdir -p ~/ffmpeg_sources ~/bin

#NASM インストール
sudo apt-get -y install nasm

# libx264 インストール
sudo apt-get -y install libx264-dev

# libx265 インストール
sudo apt-get -y install libx265-dev libnuma-dev

# libvpx インストール
sudo apt-get -y install libvpx-dev

# libfdk-aac インストール
sudo apt-get -y install libfdk-aac-dev

# libopus インストール
sudo apt-get -y install libopus-dev

# libaom インストール
sudo apt-get -y install libaom-dev

# libvmaf インストール
cd ~/ffmpeg_sources && \
wget https://github.com/Netflix/vmaf/archive/v3.0.0.tar.gz && \
tar xvf v3.0.0.tar.gz && \
mkdir -p vmaf-3.0.0/libvmaf/build &&\
cd vmaf-3.0.0/libvmaf/build && \
meson setup -Denable_tests=false -Denable_docs=false --buildtype=release --default-library=static .. --prefix "$HOME/ffmpeg_build" --bindir="$HOME/bin" --libdir="$HOME/ffmpeg_build/lib" && \
ninja && \
ninja install

# FFmpeg インストール
cd ~/ffmpeg_sources && \
git -C ffmpeg pull 2> /dev/null || git clone --depth 1 https://git.ffmpeg.org/ffmpeg.git && \
cd ffmpeg && \
PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" ./configure \
  --prefix="$HOME/ffmpeg_build" \
  --pkg-config-flags="--static" \
  --extra-cflags="-I$HOME/ffmpeg_build/include" \
  --extra-ldflags="-L$HOME/ffmpeg_build/lib" \
  --extra-libs="-lpthread -lm" \
  --ld="g++" \
  --bindir="$HOME/bin" \
  --enable-libvpl \
  --enable-openssl \
  --enable-gpl \
  --enable-libaom \
  --enable-libass \
  --enable-libfdk-aac \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libsnappy \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 \
  --enable-libvmaf \
  --enable-static \
  --enable-nonfree && \
PATH="$HOME/bin:$PATH" make && \
make install && \
hash -r

パスを通したり
source ~/.profile
echo "MANPATH_MAP $HOME/bin $HOME/ffmpeg_build/share/man" >> ~/.manpath
```

## 動作確認
実際にインストールが成功したか、下記のコマンドでQSVエンコード関連オプションが使えるか確認します。

```
for i in buildconf hwaccels decoders filters encoders; do echo $i:; ffmpeg -hide_banner -${i} | egrep -i "qsv|vaapi|libvpl"; done
```

結果はこのようになると思います。

```
ubuntu@intel-arc:~$ for i in buildconf hwaccels decoders filters encoders; do echo $i:; ffmpeg -hide_banner -${i} | egrep -i "qsv|vaapi|libvpl"; done
buildconf:
    --enable-libvpl
hwaccels:
vaapi
qsv
decoders:
 V....D av1_qsv              AV1 video (Intel Quick Sync Video acceleration) (codec av1)
 V....D h264_qsv             H264 video (Intel Quick Sync Video acceleration) (codec h264)
 V....D hevc_qsv             HEVC video (Intel Quick Sync Video acceleration) (codec hevc)
 V....D mjpeg_qsv            MJPEG video (Intel Quick Sync Video acceleration) (codec mjpeg)
 V....D mpeg2_qsv            MPEG2VIDEO video (Intel Quick Sync Video acceleration) (codec mpeg2video)
 V....D vc1_qsv              VC1 video (Intel Quick Sync Video acceleration) (codec vc1)
 V....D vp8_qsv              VP8 video (Intel Quick Sync Video acceleration) (codec vp8)
 V....D vp9_qsv              VP9 video (Intel Quick Sync Video acceleration) (codec vp9)
filters:
 ... deinterlace_qsv   V->V       Quick Sync Video "deinterlacing"
 ... deinterlace_vaapi V->V       Deinterlacing of VAAPI surfaces
 ... denoise_vaapi     V->V       VAAPI VPP for de-noise
 ... overlay_qsv       VV->V      Quick Sync Video overlay.
 ... overlay_vaapi     VV->V      Overlay one video on top of another
 ... procamp_vaapi     V->V       ProcAmp (color balance) adjustments for hue, saturation, brightness, contrast
 ... scale_qsv         V->V       Quick Sync Video "scaling and format conversion"
 ... scale_vaapi       V->V       Scale to/from VAAPI surfaces.
 ... sharpness_vaapi   V->V       VAAPI VPP for sharpness
 ... tonemap_vaapi     V->V       VAAPI VPP for tone-mapping
 ... transpose_vaapi   V->V       VAAPI VPP for transpose
 ... vpp_qsv           V->V       Quick Sync Video "VPP"
 ... hstack_vaapi      N->V       "VA-API" hstack
 ... vstack_vaapi      N->V       "VA-API" vstack
 ... xstack_vaapi      N->V       "VA-API" xstack
 ... hstack_qsv        N->V       "Quick Sync Video" hstack
 ... vstack_qsv        N->V       "Quick Sync Video" vstack
 ... xstack_qsv        N->V       "Quick Sync Video" xstack
 ... pad_vaapi         V->V       Pad the input video.
 ... drawbox_vaapi     V->V       Draw a colored box on the input video.
encoders:
 V..... av1_qsv              AV1 (Intel Quick Sync Video acceleration) (codec av1)
 V....D av1_vaapi            AV1 (VAAPI) (codec av1)
 V..... h264_qsv             H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration) (codec h264)
 V....D h264_vaapi           H.264/AVC (VAAPI) (codec h264)
 V..... hevc_qsv             HEVC (Intel Quick Sync Video acceleration) (codec hevc)
 V....D hevc_vaapi           H.265/HEVC (VAAPI) (codec hevc)
 V..... mjpeg_qsv            MJPEG (Intel Quick Sync Video acceleration) (codec mjpeg)
 V....D mjpeg_vaapi          MJPEG (VAAPI) (codec mjpeg)
 V..... mpeg2_qsv            MPEG-2 video (Intel Quick Sync Video acceleration) (codec mpeg2video)
 V....D mpeg2_vaapi          MPEG-2 (VAAPI) (codec mpeg2video)
 V....D vp8_vaapi            VP8 (VAAPI) (codec vp8)
 V....D vp9_vaapi            VP9 (VAAPI) (codec vp9)
 V..... vp9_qsv              VP9 video (Intel Quick Sync Video acceleration) (codec vp9)
ubuntu@intel-arc:~$ 
```

きちんとビルド時のオプションが有効なこと、デコーダ、フィルター、エンコーダにqsv関連が入っているのがわかります。

表示が出ない場合、今回コンパイルしたffmpegではないパッケージでインストールしたffmpegなどの結果になっている可能性があります。 which ffmpeg にてffmpegのパスを確認し、今回コンパイルしたffmpegで間違い無いかを確認してください。

# 実際に使ってみる
では実際に使ってみましょう。

MPEG2からH.265へ720pでエンコード
```
ffmpeg -hwaccel qsv -hwaccel_output_format qsv -c:v mpeg2_qsv -i input.mp2ts -vf deinterlace_qsv,scale_qsv=-1:720 -c:v hevc_qsv preset slow -look_ahead_depth 30 -c:a aac -b:a 192k -ar 48000 -tag:v hvc1 -f mp4 out.mp4
```
解説です。

> -hwaccel qsv

HWエンコードでqsvを明示

> -hwaccel_output_format qsv

GPUメモリ上にデコードしたデータを展開することによってメインメモリとの間のやりとりを減らして処理を高速化させます。

> -c:v mpeg2_qsv

MPEG2のハードウェアデコードを明示

> -i input.mp2ts

変換元ファイルを指定します。

> -vf deinterlace_qsv,scale_qsv=-1:720

まず deinterlace_qsv でHWにてインターレス解除。その後720Pになるよう縮小。
通常はscale=と使うかと思いますが、scale_qsvでHWスケーリングを使うので高速になります。

> -c:v hevc_qsv

H.265でNVEncを使います

> -tag:v hvc1

Apple製品で扱えるH.265は hev1ではなくhvc1の方なので、タグで明示します

> -f mp4

出力ファイルフォーマットがをmp4であると明示します

> -aspect 16:9 

16:9を指定

> out.mp4

出力先ファイル名を指定