ハードウェア支援がまだ未実装の新し目のコーデックを使った動画のエンコードはとにかく時間が掛かりますが、その解決策の一つに分割エンコードというものがあります。エンコード前の動画を一定のルールで分割して、分割した動画を同時に並行してエンコードするというものです。今回は、分割エンコーディングツールである『AV1an』を使用して、分割エンコーディングの実力を試したいと思います。
『AV1an』とは
各種AV1エンコーダーの分割エンコーディングをサポートした便利なオープンソースのツールです。以下、GitHubリンクから入手することが可能です。
『AV1an』(https://github.com/master-of-zen/Av1an)
Windowsバイナリが配布されていますが、環境設定起因のエラーの解消が難しかったため、ビルドから実行しようとしましたが、どうやってもビルドが通らなかったため、WSL2上のUbuntuでビルドをします(cargo install av1anでもインストール出来るようですが、最新のバージョンを取得してこないため、ビルドをします)。
Windowsで試してみたい方は、以下リンク先を参考にしてビルドにチャレンジしてみて下さい。
Windows上での『AV1an』のビルド方法(https://www.reddit.com/r/AV1/comments/s8151l/how_to_compile_av1an_on_windows_without_breaking/)
『AV1an』をUbuntu上でビルドする
前述のようにWindowsでのビルドはうまく行かなかったため、WSL2上のUbuntuでビルドしていきます。まずはビルドにあたっての準備です。
1.Rustのインストール
Av1anのビルドにはRustが必要なため、Rustをインストールします。以下は、RustをインストールするためのCargoコマンドとなります。
sudo curl https://sh.rustup.rs -sSf | sh
2.各種パッケージのインストール
ビルドに必要なパッケージをaptコマンドでインストールします。
sudo apt install build-essential make pkg-config python3 cython3 autoconf automake libtool clang libavdevice-dev libavformat-dev libavfilter-dev libavutil-dev ffmpeg curl nasm python3-pip
3.VapourSynthをインストールします
エンコード用の元動画を分割するために必要なVapourSynthをインストールします。Pythonのライブラリのため、pipコマンドでインストールします。
pip install vapoursynth
これで準備は整いました。では、いよいよAV1anをビルドしていきます。
4.『AV1an』のビルド
Githubからソースを取得した後、cargoコマンドでビルドします。
cargo build --release
以上で『AV1an』のビルドは完了です。
エンコードの準備
次にエンコードの準備をしていきます。
1.AOMのAV1エンコーダーを取得
エンコードに必要なエンコーダーを取得します。今回はAv1anがデフォルトで使用するAO MediaのAV1エンコーダーを使用します。
AO MediaのAV1エンコーダー(https://aomedia.googlesource.com/aom/)
説明にある通りビルドし、取得してください。
2.FFmpeg Staticビルドの取得
エンコードの際に必要となるFFmpeg staticをダウンロードします。
FFmpeg Staticビルド(https://johnvansickle.com/ffmpeg/)
3.各種バイナリの配置
AV1エンコーダーとFFmpeg StaticビルドはAv1anと同じディレクトリに配置してください。aomencとffmpeg、ffprobeをAV1anと同じディレクトリに置いて下さい。
これで分割エンコーディングの準備はすべて整いました。
分割エンコーディングを実施
それでは実際に動画のエンコードを行ってみようと思います。エンコード元動画は下記となります。
- 画角:1920×1080
- フレームレート:60FPS
- 画質:214kbps
- 尺:2時間47分
エンコードを行うPCのスペックは以下となります。
- CPU:Core i9 9900k
- メモリ:DDR4 64GB
- ストレージ:NVMe M.2 SSD
今回はエンコード時間比較のために、FFmpegとaomencでもエンコードを行います。ffmpegとaomencのエンコードでは極力av1anのデフォルトパラメータを使うようにします。
エンコードのコマンド
実行するコマンドは以下となります。
AV1an
time av1an -i ./input.mp4 -o ./output.mp4
※av1anのオプション(https://github.com/master-of-zen/Av1an/blob/master/docs/CLI.md)
FFmpeg
av1anがデフォルトで2passエンコードを行うので、ffmpegでも2passエンコードを行います。
time ffmpeg -y -i ./src/test.mp4 -c:v libaom-av1 -threads 8 -cpu-used 6 -tile-columns 1 -tile-rows 0 -aom-params cq-level=30 -pass 1 -f null /dev/null && time ffmpeg -y -i ./input.mp4 -c:v libaom-av1 -threads 8 -cpu-used 6 -tile-columns 1 -tile-rows 0 -aom-params cq-level=30 -pass 2 ./outputffmpeg.mp4
aomenc
aomencはmp4を直接処理できないので、ffmpegでy4mの形式に変換しておきます。
ffmpeg -i input.mp4 -f yuv4mpegpipe input.y4m
time aomenc --threads=8 --cpu-used=6 --end-usage=q --cq-level=30 --tile-columns=1 --tile-rows=0 --width=1920 --height=1080 -o ./outputaomenc.bin ./input.y4m
※aomencのオプション(https://github.com/master-of-zen/Av1an/blob/master/docs/Encoders/aomenc.md)
エンコードの実施結果
エンコード時間の結果は下記となります。それぞれ、実施日と時間を変えて3回エンコード時間を計測しました。時間は、分(m)と秒(s)で表記しています。
No. | AV1an | FFmpeg (1passと2pass合計) | aomenc |
(1) | 20m01s | 28m22s (1m31s+26m51s) | 31m40s |
(2) | 20m38s | 28m04s (1m35s+26m29s) | 30m37s |
(3) | 20m46s | 29m41s (1m37s+28m04s) | 32m24s |
いかがでしょうか。分割エンコードを行ったAV1anはFFmpegとaomencと比べて3割程度、エンコード時間が短縮される結果になりました。Av1anはデフォルトでワーカープロセスを5つ起動してエンコードを行うため、さすがに通常のエンコードよりも速いですね。動画の分割と再結合というオーバーヘッドがあった上で速いのですから、分割エンコードはハードウェア支援が無い環境では、割りと有効なのではないかと思います。
尚、ワーカープロセスは「-w」オプションで変えられるので、幾つかのパターンで試してみたところ、以下のような結果となりました。
ワーカープロセス数 | エンコード時間 分(m)と秒(s)で表記 |
1 | 37m21s |
2 | 24m26s |
3 | 22m21s |
4 | 21m42s |
5 | (20m) |
6 | 21m40s |
8 | 21m46s |
16 | 22m43s |
9900kは8コア16スレッドのCPUであるため、いたずらにワーカープロセスを増やしても、リソースの限界が来てエンコード速度の向上には繋がらないようです。また、6ワーカープロセスで全論理プロセッサが使用率100%になって、エンコードが終わるまで何も出来なくなりました。
さいごに
さて、今回は動画の分割エンコードを体験してみよう、という内容でしたが、いかがでしたでしょうか?AV1anはAV1なら、他にSVT-AV1やrav1e、H.264/265、VP8/9にも対応していますし、最新のCPUで動かしてみると面白いかもしれません。64コア/128スレッドのRyzen Threadripper PRO 5995WXなんかでエンコードしてみると、凄いことになりそうですね。