ffmpeg NVENCの画質と最適設定
NVENCとfdk-aacが使えるffmpegをビルドし、h264_nvenc の cq (constant quality mode) の動作を解析し最適なエンコード設定を求めた。
x264 の crf とは設定が根本的に違う。crf は動きの少ない時の目標、cq は動きの多い時の目標(q の平均の上限)
動きの少ない時の q (Quantization Parameter) は cq の方が 5 低いので cq 28 が crf 23 相当。
nvdec を使わない場合の cq 28 の画質は x264 デフォルト crf 23 と同程度。(動きが激しい時は除く)
ただしビットレートは3割程度大きい。(cq 30 なら x264 並)※Turing 以降ではビットレート約2割減、画質改善とBフレームの効果
評価環境は ffmpeg-4.3.1 nvenc 9.0.18.3(デフォルト Bフレームなし)GT 710 2020/11
問題点
・Bフレームを使うと画質が悪い ※
・nvdec を使うと画質が少し悪い(画質と速度、どちらを取るか)
・cq のビットレートは x264 と比較して動きが少ないと増加、動きが多いと減少する(q の変動が大きい)
※Bフレームの画質は -rc-lookahead が使えれば問題ない
追加情報
ffmpeg-5.1.2 の評価を追加 nvenc 10.0.26.2 RTX 4060 で確認 2023/12
Bフレームのデフォルトが 3 に変わったのでBフレームなしにするには -bf 0 が必要。h264 のBフレーム使用時の画質は -b_ref_mode 1 でかなり改善している。(q値の評価)hevc の場合は -b_ref_mode 1 ならBフレームを使っても問題ない。(Turing 世代でhevc のBフレーム対応) ※次の評価で問題が見つかったので h264 の -b_ref_mode 1 は使えない。
-bf は nvenc の help には記載されていないオプション、libx264 でも使える(helpの表示 ffmpeg -h encoder=h264_nvenc)
ffmpeg-6.1.2 の評価を追加 nvenc 12.0.16.1 RTX 4060 で確認 2024/12
h264 の画質はデフォルトの -rc-lookahead 無効だとかなり悪いので -rc-lookahead を有効にする必要がある。(目視の評価※)原因は -b_adapt 無効、-rc-lookahead と -b_adapt は連動している。-rc-lookahead の有効な設定範囲は 5~40。これでBフレームの問題は解決し画質は x264 と同程度。 -rc-lookahead が使えない場合はBフレームなしにする。※q値の評価では差が出ない現象だったので目視の評価が重要でした。
-b_ref_mode のデフォルトが 0 (無効)から -1 (実際は2)に変わったので-b_ref_mode 1 と 2 の画質を確認。
h264 ではデフォルトの -b_ref_mode 2 が最適。 -b_ref_mode 1 には cq モードのビットレートが増える問題があるので使えない。cq 30 のビットレートは x264 crf 23 より少し低くなった。hevc では -b_ref_mode 1 と 2 の差がほとんどないのでデフォルトの 2 でよい。hevc では -rc-lookahead 0 でも画質は悪くないがキーフレーム間隔が固定から可変に変わる効果もあるので -rc-lookahead は有効にする。hevc は h264 より低ビットレートに強いが画質はいまいち。
新機能の av1 は nvenc API 12.0 以降で対応、av1 の画質はビットレート指定では hevc より良い。 cq モードでは設定や挙動が変だが、画質はよいので hevc の代わりに使ってもよいだろう。(av1 cq 35 が hevc cq 30 相当のビットレート)
h264 と hevc の画質については Turing の GTX 1660 super でも同じでした。
これ以降の記事は古い世代のGPU(GT 710など)を元にしているので新しい世代のGPUに関しては後述の追加データの方も見てください。h264_nvenc の挙動は新しい世代のGPUでも変わっていない。
デコーダ(nvdec)の画質確認
Full HD から 720p の mp4 を作成する場合
-c:v mpeg2_cuvid -deint 1 -drop_second_field 1 -resize 1280x720
・インターレース解除は-deint 1 (bob) と-deint 2 (adaptive) があるがbobは高速だが画質が悪い
adaptiveの画質はffmpegのbwdifより悪い(ffmpegのyadifの画質はいまいち、線の上に斑点が散るのでアニメには不向き)※現在の環境では再現しないので yadif でよい、bwdif より線が少し汚い程度
60fps化はしないので2番目のフィールドは捨てる
・リサイズの画質はffmpegのデフォルトbicubicより悪い
デコーダは速度重視ならnvdec、画質重視ならffmpeg
エンコード オプションの検討
デフォルトでは 2000kbps の vbr になるが、品質を指定する場合は -b:v 0 -cq を使う
-b:v 0 なしだと使う ffmpeg によって挙動が変わるので -b:v 0 は必要(ビルドしたものと q の上限が違った)
h264_nvenc の cq (constant quality mode) は x264 と違い、動きが少ない時に q の値が大幅に低下する
q は quantization parameter (QP)
・h264_nvenc の -b:v 0 -cq
q は設定値 +5 ~ -7 (エンコード時の q 表示、-qp 換算だと +6 ~ -6、q 表示は整数で設定より 1 低い、切り捨て?)
動きが少ない時は -7
・libx264 の -crf
q は設定値 +6 ~ -4 (エンコード後のPフレームの q 表示、Bフレームは +6 を越えない範囲で P + 2 程度)
-4 は静止の場合、動きが少ない時は -1~-2 程度 (実質的な q の範囲は +6 ~ -2 )
x264 とは q の下がり方に 5 の差があるので
-b:v 0 -cq 28 で動きの少ない時の q は x264 のデフォルト -crf 23 とほぼ同じになる( q の最大値は 4 大きい)
これでも x264 よりファイルサイズはかなり大きいので -cq 30 でも良いと思う(ファイルサイズ優先)
Constant QP mode で画質を確認(nvdec未使用)
-qp 21 ◎ 細部の描画も良好
-qp 23 ◎ 静止画でも気にならない
-qp 25 ◎ 静止画だと少し気になる
-qp 28 ○ 動いているなら気にならない
-qp 32 △ 動きが大きい時なら許容できる
-qp 36 × 動きが大きくてもかなり気になる
これを目安に設定を決める、動きの多い時でも32程度に抑えたい
-rc constqp (Constant QP mode) のデフォルトは -qp 28(エンコード時の q 表示は 設定値 -1 )
x264 のデフォルト crf 23 の q の範囲 19~29 は非常に優秀であることがわかる
Bフレームなしの x264 と h264_nvenc で同じ -qp なら画質はほぼ同じ、ビットレートは nvenc が1割程度大きい。※ RTX 4060 ではビットレートは同じ
ビットレート指定の vbr では qmin qmax を指定することができる
-b:v 2000k -qmin 23 -qmax 36
-qp 23 より下げても画質はあまり改善しないので -qmin 23
-qp 36 を越えると急激に画質が悪化するので -qmax 36
720p のビットレートは 2000k 以上が必要
その他のオプション
-g 150 GOPサイズ(キーフレーム間隔) 30fps で 5 秒、デフォルトの 250 は長すぎる
250 だとシークが遅くなる、ファイルサイズ的にもほとんどメリットない
x264 は可変で max 250 なので、150 程度がちょうどよい
※ -rc-lookahead を使う場合はキーフレーム間隔が可変になるので -g 150 は不要(x264 と同じ max 250 になる)
-profile:v high high profile(デフォルトはmain) high の方が薄い背景の潰れが少ない
main だと q が大きい時に階調が潰れやすい(アニメだとわかりやすい)
-rc vbr_hq high quality mode 速度低下に見合った効果があるかは疑問、ビットレートは僅かに小さくなる
-bf 3 Bフレーム(max 4) 画質が非常に悪くなる ※ -rc-lookahead が使えれば改善
Constant QP mode で確認すると q の値が時々 +8 跳ね上がる
画質で注目したポイントは
薄い背景などの潰れ、文字やロゴの潰れ、線の綺麗さとノイズ、青色部分の潰れ
最適なエンコード設定
品質指定の場合 -profile:v high -g 150 -b:v 0 -cq 30 -bf 0 ※デフォルトが -bf 3 に変わったので -bf 0 追加、 -rc-lookahead が使える場合は -profile:v high -b:v 0 -cq 30 -bf 3 -rc-lookahead 20
ffmpeg -y -c:v mpeg2_cuvid -deint 1 -drop_second_field 1 -resize 1280x720 -i "input file" -vf fps=30000/1001 -async 1 -aspect 16:9 -c:v h264_nvenc -profile:v high -g 150 -b:v 0 -cq 30 -bf 0 -c:a libfdk_aac -ac 2 -b:a 128k -brand mp42 "output.mp4"
-cq 30 で q の範囲は -qmin 24 -qmax 36 相当
ビットレートは実写で 2000kbps 程度、-cq 28 だと3割増加するが高画質(x264 デフォルト並)
nvdec を使わない場合
ffmpeg -y -i "input file" -vf yadif,fps=30000/1001 -async 1 -s 1280x720 -aspect 16:9 -c:v h264_nvenc -profile:v high -g 150 -b:v 0 -cq 30 -bf 0 -c:a libfdk_aac -ac 2 -b:a 128k -brand mp42 "output.mp4"
ビットレート指定の場合
ffmpeg -y -c:v mpeg2_cuvid -deint 1 -drop_second_field 1 -resize 1280x720 -i "input file" -vf fps=30000/1001 -async 1 -aspect 16:9 -c:v h264_nvenc -profile:v high -g 150 -b:v 2000k -qmin 23 -qmax 36 -bf 0 -c:a libfdk_aac -ac 2 -b:a 128k -brand mp42 "output.mp4"
nvdec nvenc 以外のオプションの説明はこちら