GPUの力で爆速エンコード
2023-12-05
azblob://2023/12/01/eyecatch/2023-12-05-ffmpeg-harware-encode-000.jpg

今回は待望?のGPU有効活用シリーズの第2弾です。

当初予定していたネタが思ったより動かなくて、ふと思い出した用途で書いてます。

ということで、今回やっていくのはハードウェアエンコードです。

AIが流行る前はGPUの用途といえばゲームかエンコードだった(個人の感想です)のになぜかすっかり忘れていました。

実行環境

以下の環境でffmpegを実行しました。

  1. Windows11 22H2
  2. AMD Ryzen 5 3600
  3. Geforce RTX 4070
  4. メモリ32GB
  5. ffmpeg 6.1-full_build-www.gyan.dev

コーデックは一般的なH.264/MPEG-4 AVCと、その後継であるH.265/HEVC、負荷の高い代わりにさらに圧縮率の高いAV1の3つを、ソフトウェアエンコードとハードウェアエンコードのそれぞれでエンコードしてその所要時間と品質について比較していきます。

また、エンコードする動画は Creative Commons Attribution 3.0 で公開されている Big Buck Bunny のこの動画を使用します。 
動画ライセンスについてはこちら https://peach.blender.org/about/

エンコード

各コマンドの実行時間はmeasure-Command で計測しました。その結果がこちらです。

H.264/MPEG-4 AVC

  • ソフトウェアエンコード
    • 実行コマンド:ffmpeg -i input.mp4 -c:v libx264 -c:a copy out.mp4
    • エンコード後のファイルサイズ:257MB
    • 実行時間:3分47秒
  • ハードウェアエンコード
    • 実行コマンド:ffmpeg -i input.mp4 -c:v h264_nvenc -c:a copy out.mp4
    • エンコード後のファイルサイズ:179MB
    • 実行時間:36秒

H.265/HEVC

  • ソフトウェアエンコード
    • 実行コマンド:ffmpeg -i input.mp4 -c:v libx265 -c:a copy out.mp4
    • エンコード後のファイルサイズ:121MB
    • 実行時間:8分
  • ハードウェアエンコード
    • 実行コマンド:ffmpeg -i input.mp4 -c:v hevc_nvenc -c:a copy out.mp4
    • エンコード後のファイルサイズ:182MB
    • 実行時間:38秒

AV1

  • ソフトウェアエンコード
    • 実行コマンド:ffmpeg -i input.mp4 -c:v libsvtav1 -c:a copy out.mp4
    • エンコード後のファイルサイズ:157MB
    • 実行時間:4分40秒

リファレンス実装であるlibaomは現実的な時間でエンコードが終わらないので、速度重視のlibsvtav1を使用しました。

  • ハードウェアエンコード
    • 実行コマンド:ffmpeg -i input.mp4 -c:v av1_nvenc -c:a copy out.mp4
    • エンコード後のファイルサイズ:182MB
    • 実行時間:36秒

ソフトウェアエンコードでは数分はかかっていたものが、ハードウェアエンコードにするといずれも40秒かかりませんでした。

比較方法

品質の比較にはVMAFというものを使います。

これは2つの動画で差少なければ少ないほどスコアが上がり、まったく同じならスコアが100になります。

これでエンコード前の動画と比較したスコアを出しました。

また10分すべてを比較するとかなり時間がかかるので、最初の30秒を比較しています。

H.264/MPEG-4 AVC

  • ソフトウェアエンコード
    • 比較コマンド:ffmpeg -i .\out_libx264.mp4 -i .\input.mp4 -filter_complex "libvmaf=vmaf_v0.6.1.json:log_path=libx264.xml:n_threads=16:shortest=1:repeatlast=0" -an -f null -t 30 -
    • スコア:95.763985
  • ハードウェアエンコード
    • 比較コマンド:ffmpeg -i .\out_h264_nvenc.mp4 -i .\input.mp4 -filter_complex "libvmaf=vmaf_v0.6.1.json:log_path=h264_nvenc.xml:n_threads=16:shortest=1:repeatlast=0" -an -f null -t 30 -
    • スコア:92.178428

H.265/HEVC

  • ソフトウェアエンコード
    • 比較コマンド:ffmpeg -i .\out_libx265.mp4 -i .\input.mp4 -filter_complex "libvmaf=vmaf_v0.6.1.json:log_path=libx265.xml:n_threads=16:shortest=1:repeatlast=0" -an -f null -t 30 -
    • スコア:92.658707
  • ハードウェアエンコード
    • 比較コマンド:ffmpeg -i .\out_hevc_nvenc.mp4 -i .\input.mp4 -filter_complex "libvmaf=vmaf_v0.6.1.json:log_path=hevc_nvenc.xml:n_threads=16:shortest=1:repeatlast=0" -an -f null -t 30 -
    • スコア:93.200827

AV1

  • ソフトウェアエンコード
    • 比較コマンド:ffmpeg -i .\out_libsvtav1.mp4 -i .\input.mp4 -filter_complex "libvmaf=vmaf_v0.6.1.json:log_path=libsvtav1.xml:n_threads=16:shortest=1:repeatlast=0" -an -f null -t 30 -
    • スコア:94.910897
  • ハードウェアエンコード
    • 比較コマンド:ffmpeg -i .\out_av1_nvenc.mp4 -i .\input.mp4 -filter_complex "libvmaf=vmaf_v0.6.1.json:log_path=av1_nvenc.xml:n_threads=16:shortest=1:repeatlast=0" -an -f null -t 30 -
    • スコア:94.067473

まとめ

一般的にはハードウェアエンコードを行うとソフトウェアエンコードよりも品質は下がるはずなのですが、H.265/HEVCでは圧縮しすぎたのかなぜか逆転するという不思議な現象が起こりました。

また、ソフトウェアエンコードではlibx264が品質は優秀なのですが、動画時間が延びればファイルサイズもエンコード時間も必然的に伸びることも考えれば、AV1でハードウェアエンコードするのがいいのかなと個人的に思いました。