ffmpegでNVENCを使ってエンコードしてみる

ffmpeg encoding
NVENCをffmpegで動かしてみます。
お手軽で高速、安定したエンコードができます。

NVIDIAのGPUのビデオエンコーダNVENCを使ってエンコードをしてみます。CPUを使ったエンコーダに比べ大変高速です。
Windowsを前提に記事を書きますが、ffmpegのオプションの説明になるのでMacやLinuxでも使えます。

NVENCは直に動かすことができません。ビデオ編集ソフトやビデオエンコードソフトにNVENCが組み込まれているものを使います。
ここではffmpegを使って動かします。

ffmpegはコマンドプロンプトで動かします。Window画面はありませんので取っつき難いと思っている方がほとんどでしょう。エンコードには設定するパラメータがたくさんありWindows画面にすべて表示していられません。また、エンコードでは一度設定を決めてしまうと設定を毎回変える必要は無いのでWindow画面とか必要なくなってしまうのです。コマンドプロンプトで動かすのが一番スッキリした方法なのです。

FFmpegの入手

FFmpegは自分でビルドするか実行ファイルを配布しているサイトから入手します。
FFmpeg Builds
https://ffmpeg.zeranoe.com/builds/
なにか選択肢がありますが、何も触らずダウンロードを始めましょう。

自分でビルドする場合は
関連記事:Windows 10のUbuntuアプリ18.04でFFmpegをビルドする

古いffmpegではNVENCが入っていない場合があります。ffmpegは頻繁に更新されるので常に最新版を使うようにしましょう。
本記事ではStatic版を前提に書いています。

FFmpegの動かし方

ffmpeg.exeを入手したらどこか適当なフォルダへおいて作業を始めます。
ここでは"c:\ffmpeg"ディレクトリにffmpeg.exeファイルがあるとして話を進めます。

Windows PowerShellを開きます。スタートメニューのスタートボタンを右クリックするとメニューの中にあるでしょう。
窓が開いたら"c:\ffmpeg"へ移動します。
cd /ffmpeg
PS C:\ffmpeg> ls


    ディレクトリ: C:\ffmpeg


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/06/16     16:40       88660992 ffmpeg.exe
ディレクトリ内にffmpeg.exeがあればすぐに動かせます。
まずはffmpeg.exeのバージョンを表示してみます。
PS C:\ffmpeg> .\ffmpeg.exe -version
ffmpeg version N-94054-gdd357d76e5-ffmpeg-windows-build-helpers Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 8.2.0 (GCC)
configuration: --pkg-config=pkg-config --pkg-config-flags=--static --extra-version=ffmpeg-windows-build-helpers --enable-version3 --disable-debug --disable-w32threads --arch=x86_64 --target-os=mingw32 --cross-prefix=/home/user1/Downloads/ffmpeg-windows-build-helpers/sandbox/cross_compilers/mingw-w64-x86_64/bin/x86_64-w64-mingw32- --enable-libcaca --enable-gray --enable-libtesseract --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libbs2b --enable-libflite --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libzimg --enable-libzvbi --enable-libmysofa --enable-libaom --enable-libopenjpeg --enable-libopenh264 --enable-liblensfun --enable-libvmaf --enable-libsrt --enable-demuxer=dash --enable-libxml2 --enable-nvenc --enable-nvdec --extra-libs=-lharfbuzz --extra-libs=-lm --extra-libs=-lpthread --extra-cflags=-DLIBTWOLAME_STATIC --extra-cflags=-DMODPLUG_STATIC --extra-cflags=-DCACA_STATIC --enable-amf --enable-libmfx --enable-gpl --enable-avisynth --enable-frei0r --enable-filter=frei0r --enable-librubberband --enable-libvidstab --enable-libx264 --enable-libx265 --enable-libxvid --enable-libxavs --enable-avresample --extra-cflags='-mtune=generic' --extra-cflags=-O3 --enable-static --disable-shared --prefix=/home/user1/Downloads/ffmpeg-windows-build-helpers/sandbox/cross_compilers/mingw-w64-x86_64/x86_64-w64-mingw32 --enable-nonfree --enable-decklink --enable-libfdk-aac
libavutil      56. 28.100 / 56. 28.100
libavcodec     58. 53.100 / 58. 53.100
libavformat    58. 27.103 / 58. 27.103
libavdevice    58.  7.100 / 58.  7.100
libavfilter     7. 55.100 /  7. 55.100
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  4.101 /  5.  4.101
libswresample   3.  4.100 /  3.  4.100
libpostproc    55.  4.100 / 55.  4.100
例えばこんな風に表示されます。

NVENCが使えるか?

入手したffmpegでNVENCが使えるか確認してみます。
使えるエンコーダの一覧を"encorders.txt"に書き出します。
> ./ffmpeg -encoders > encoders.txt
"encorders.txt"をテキストエディタで開いてみてください。ffmpegで使えるものが一覧で見れます。この中にnvencと書いてあるものがあればNVENCを使えます。または次のコマンドで確認します。
> cat .\encoders.txt | Select-String "nvenc"

 V..... h264_nvenc           NVIDIA NVENC H.264 encoder (codec h264)
 V..... nvenc                NVIDIA NVENC H.264 encoder (codec h264)
 V..... nvenc_h264           NVIDIA NVENC H.264 encoder (codec h264)
 V..... nvenc_hevc           NVIDIA NVENC hevc encoder (codec hevc)
 V..... hevc_nvenc           NVIDIA NVENC hevc encoder (codec hevc)

エンコードだけでは無くデコードもGPUで行えます。デコーダ一覧を"decoders.txt"に書き出します。
> ./ffmpeg -decoders > decoders.txt
エンコーダと同様にテキストエディタで開いて見てください。あるいは次のコマンドで表示します。
> cat .\decoders.txt | Select-String "nvidia"

 V..... h264_cuvid           Nvidia CUVID H264 decoder (codec h264)
 V..... hevc_cuvid           Nvidia CUVID HEVC decoder (codec hevc)
 V..... mjpeg_cuvid          Nvidia CUVID MJPEG decoder (codec mjpeg)
 V..... mpeg1_cuvid          Nvidia CUVID MPEG1VIDEO decoder (codec mpeg1video)
 V..... mpeg2_cuvid          Nvidia CUVID MPEG2VIDEO decoder (codec mpeg2video)
 V..... mpeg4_cuvid          Nvidia CUVID MPEG4 decoder (codec mpeg4)
 V..... vc1_cuvid            Nvidia CUVID VC1 decoder (codec vc1)
 V..... vp8_cuvid            Nvidia CUVID VP8 decoder (codec vp8)
 V..... vp9_cuvid            Nvidia CUVID VP9 decoder (codec vp9)

このようにffmpegの使い方や使えるものはffmpegのオプションで表示できます。helpオプションが基本です。基本的オプションが表示されるので一度は目を通しましょう。
> ./ffmpeg -help

もしここでnvencが出てこなければffmpegを入手し直しましょう。

NVENCのオプション

次にNVENC専用のオプションを表示してみます。
h.264エンコード時のオプションを書き出します。
> ./ffmpeg -h encoder=h264_nvenc > h264_nvenc.txt
hevcエンコード時のオプションを書き出します。
> ./ffmpeg -h encoder=hevc_nvenc > hevc_nvenc.txt

ffmpegコマンドオプションの例

エンコード品質の設定方法には昔ながらのビットレート指定、固定品質モードと固定量子化量モードの3種類があります。
ビットレート指定には、固定ビットレートモード(cbr)と可変ビットレートモード(vbr)の2種類があります。ライブ配信かDVDに焼く以外でビットレート指定を使うメリットはありません。
エンコードした映像を一時停止し拡大して見る趣味がある人は固定量子化量モード(qp)を選びましょう。

h.264あるいはh.265を使うなら固定品質モード(cq)を選びましょう。
NVENCの場合、明示的なモードの指定は実質的にありません。オプションのパラメータの組み合わせで自動的にモードが変わります。これがとても判りにくいです。

下準備が整ったので実際のコマンド例を紹介します。

少し古いデジタルビデオカメラを持っているとインターレースでts形式のファイルがたくさんあるでしょう。h.264かHEVCで容量を小さくしましょう。tsファイルの映像はmpeg2でデコードします。

./ffmpeg -hwaccel cuvid  -c:v mpeg2_cuvid  -i input.ts  -c:v h264_nvenc -b:v 0 -cq 26 -rc-lookahead 32 -temporal-aq 1 -weighted_pred 0 -flags:v +ildct -top 1 -b_ref_mode middle -c:a copy -g 60 out_cq_ts.mkv
h264でエンコードしています。
"-cq"オプションで品質指定します。今回は"26"にしています。
"-b:v 0"というのがポイントです。これと"-cq"があると固定品質モードになります。
"-weighted_pred"を1にすると途中でエラーが生じるファイルがありました。様子を見ながら使ったほうが良いのかも。
出力はインターレースであると指定しています。

.\ffmpeg -hwaccel cuvid  -c:v mpeg2_cuvid  -i input.ts  -c:v hevc_nvenc -b:v 0 -cq 26 -rc-lookahead 32 -temporal-aq 1 -weighted_pred 0  -b_ref_mode disabled -c:a copy -g 60 out_cq_ts_hevc.mkv
hevcでエンコードしています。
品質指定はh264と同じです。
GPUの世代により”-b_ref_mode”を有効にできません。私のはGTX1070なので有効にできません。
Video Encode and Decode GPU Support Matrix | NVidia

インタレース維持ができません。出来上がったファイルにインタレースのフラグが無いようです。再生時にインターレースと認識されない扱いに困るファイルが出来上がります。
デコーダ側でインタレース解除の指定ができます。デコーダのヘルプを表示して見てください。私が試した限りですが再生時にカクつくので紹介するのをやめました。

.\ffmpeg -hwaccel cuvid  -c:v h264_cuvid  -i input.mkv  -c:v hevc_nvenc -qp 26 -rc-lookahead 32 -temporal-aq 1 -weighted_pred 1 -b_ref_mode disabled -profile main10  -c:a copy -g 60 out_qp_264_hevc.mkv
h264のファイルをhevcでエンコードし直してみます。固定量子化量でエンコードしています。
main10プロファイルを指定していますが、pixel formatの対応が不十分で今の所何の意味もありません。yuv444p10leが使えるようになれば10bitのカラー深度のエンコードもできるようになると思われます。

まとめ

Zen2を買う準備をしています。QSVがなくなるのでNVENCの使い方を久しぶりに確認しています。

ffmpegを使う理由は特に気にせずとも多くの入力フォーマットが使える事とmuxerの安定感です。映像と音がズレることはほぼないです。ズレても修正する方法がいくつもあります。豊富なフィルタを気楽に試せます。

Turing世代でhevcの画質が上がったようですね。あいにくPascal世代しか持っていません。
もっと前の世代で実験して、画質が悪いし容量節約にも使えないと判断して放っておきました。今ではmpeg2の容量をざっくり1/3にする程度ならスピードを考えるととても魅力的になっているようです。h264でもよさそうです。

h.264やHEVCの品質パラメータの値を決めるのはとても大変です。固定品質や固定量子化量では目安となるものがありません。自分で納得いくまでエンコードした絵を見る必要があります。暗いシーンを探してひたすら見比べたり、派手な動きをするシーンのノイズを何度も見たり、ここのノイズがきになる~とパラメータ調整を何度もしてたらソースのノイズだったり、だんだん何をしているか判らなくなります。
気になるシーンをまとめた動画を最初に作り、それをx265で満足行くまでエンコードし、そのファイルサイズを基準にハードウエアエンコードのファイルサイズ、画質とエンコード速度を天秤にかけます。
はい、苦行です。
この苦行を乗り越えれば、その後パラメータを見直す必要はほぼ無いのですけどね。乗り越えられない・・・

こんな時はビットレートやssim値を頼りたくなる気持ちも判ります。ですが、h.264やHEVCの利点が何も反映されなくなるので避けたほうが良いです。
h.264やHEVCはパッと見たとき粗に気づかないという所で圧縮率を上げています。じっくり見てはいけません・・・なおさら何を見ればいいか判らなくなりましたか?

ハードウエアエンコードはざっくり容量を減らす目的かリアルタイム配信に使うのが良いですね。とにかくエンコード速度は魅力的です。
GTX1070を使っていますが、フィルタ処理など余計なことをしなければ700fpsくらいで変換してくれるビデオファイルもあります。
保存用はじっくりとx265かx264でやるしかないでしょうね。


コメント

最近のコメント

Threaded Recent Comments will be here.