ffmpeg h265 nvidia显卡硬件加速 参数测试

This article is categorized as "Garbage" . It should NEVER be appeared in your search engine's results.

前半部分(使用windows ffmpeg)写于2023年6月;后半部分(使用ubuntu ffmpeg)写于2023年12月

2023年6月(windows ffmpeg)


当前命令(似乎是从某个supseruser.com问答里拿出来的,等后续找个时间补充下链接)

https://superuser.com/questions/1236275/how-can-i-use-crf-encoding-with-nvenc-in-ffmpeg

* windows

$ ffmpeg -i <input.mp4>  -c:v hevc_nvenc -preset:v p7 -tune:v hq -rc:v vbr -cq:v 19 -b:v 0 -preset slow <output.mp4>

现在的问题在于:如何调整参数?(不使用bitrate控制质量)

似乎和 p7 有关。

又找到一个新的命令,看起来更详细一些:

https://gist.github.com/jungin500/d412986ad633889e5968531a138d82ca

先用上面链接的原始命令(去掉了几行不必要的,保留了关键的 p1  cq, vbr = 24 

更新:后面又去掉了-hwaccel cuda和-hwaccel_output_format cuda,因为我的ffmpeg识别不出这个命令:

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p1 \
 -rc vbr -cq 24 -qmin 24 -qmax 24 -b:v 0K \ 
"output1.mp4"

评价(原视频大小为990M的游戏录屏,Nvidia replay制作的,码率固定,时长固定,所以本身可能就存在较大优化空间<等待后续补充>):

990M->583M

转码后的视频质量很高


然后把-preset p1改成p7

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p7 \
 -rc vbr -cq 24 -qmin 24 -qmax 24 -b:v 0K \ 
"output2.mp4"

990M->572M

但编码时间从原来的10秒不到变成了现在的1分钟左右。似乎不太值。


所以接下来默认使用p4,这样编码时间是25秒左右,可以接受。(speed在4.5x~4.7x浮动)


试试-preset p4,然后cq省略不写

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p4 \
"output3.mp4"

990M->36.3M

很糊,但依然能辨别游戏视频里的小字(比如队友ID,敌人ID,煎药配方等等)


试试-preset p4,然后cq=40

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p4 \
 -rc vbr -cq 40 -qmin 40 -qmax 40 -b:v 0K \ 
"output4.mp4"

990M->56.7M

看来cq还是太大了


试试-preset p4,然后cq=30

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p4 \
 -rc vbr -cq 30-qmin 30-qmax 30 -b:v 0K \ 
"output5.mp4"

990M->241M

如果截图快速对比,还是能发现cq=30的质量要下降一些的。有些很小的字,在cq=30的质量下还是会模糊。


听说crf和cq只是叫法不一样(一个是H264一个是HEVC),数字大小的用法是一样的。现在来试试cq的默认值是不是23:

试试-preset p4,然后cq=23

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p4 \
 -rc vbr -cq 23-qmin 23-qmax 23 -b:v 0K \ 
"output6.mp4"

990M->660M

对比这个:

可以看出数字大小还是不能直接照搬的。cq的默认值应该比40还要大,大概是45?


再试试-preset p5和cq=26:

ffmpeg \
 -i "input.mp4" \ 
-vcodec hevc_nvenc \
-preset p5 \
 -rc vbr -cq 26-qmin 26-qmax 26 -b:v 0K \ 
"output7.mp4"

990M->425M

效果不错。虽然仔细放大也能看出小字体的区别,但已经无伤大雅了,非常适合拿来压缩那些不怎么重要的游戏视频。


再试试OBS gpu-h265的录屏

待补充


2023年12月(ubuntu ffmpeg)

现在换成了ubuntu 22,部分运行参数发生了改变


环境:ubuntu 22.04


首先,在ffmpeg.org下载的linux static build是不支持nvidia硬件加速的,要想开启hevc_nvenc,只能:

  1. 使用apt-get获取,但ubuntu 22.04系统上只支持到ffmpeg 4.4.x
  2. 自己编译ffmpeg 5.x甚至6.x甚至7.x

先试试自己编译,这里参考了:🔗 [Using FFmpeg with NVIDIA GPU Hardware Acceleration - NVIDIA Docs] https://docs.nvidia.com/video-technologies/video-codec-sdk/11.1/ffmpeg-with-nvidia-gpu/index.html

按照教程来确实可以编译,但ffmpeg执行的时候出了问题:

ffmpeg: error while loading shared libraries: libavdevice.so.60: cannot open shared object file

这个 libavdevice.so.60 来得非常诡异,网上查了一圈,参考🔗 [Ffmpeg error in linux - Stack Overflow] https://stackoverflow.com/questions/12901706/ffmpeg-error-in-linux,发现我的ubuntu系统里面只有 libavdevice.so.58 .

所以估计是ffmpeg的源代码太新了(一开始用的是ffmpeg 6.1),所以试一试ffmpeg 5.x,结果5.x也不支持我手里的 libavdevice.so.58 

ffmpeg: error while loading shared libraries: libavdevice.so.59: cannot open shared object file

所以说ffmpeg 5.x也还是太新了,要再降级到4.x才行,但4.x版本不就是apt-get获取的版本吗...所以说似乎走到死胡同里去了

猜测:想要手动编译ffmpeg 6.x成功,得上一个自带 libavdevice.so.60 文件的系统才行,估计要ubuntu 23,但手里的ubuntu 22.04暂时不打算升级...

本来已经打算将就着用apt提供的ffmpeg 4.4.x了,但突然用教程🔗 [CompilationGuide/Ubuntu – FFmpeg] https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu 成功编译了ffmpeg 6.1(去掉了 --enable-libsvtav1 的支持,因为懒得搞av1的依赖了,而且暂时也用不上,此外nvidia对av1_nvenc的支持仅限于新显卡:🔗 [Nvidia NVENC - Wikipedia] https://en.m.wikipedia.org/wiki/Nvidia_NVENC


再次更新:

首先目前的显卡不支持av1_nvenc

其次hevc_nvenc编码出来的文件体积甚至比原始文件(h264)还大

以一个9.6M的h265视频为例:

使用libx265能做出5.6M的高清h265视频,质量和原本的h264相当

使用hevc_nvenc要么只能做出15M的视频(质量和原本h264相当),要么只能做出3.2M的垃圾质量视频(糊成一团)

🔗 [ffmpeg - Different outputs when encode to h265 using CPU only and GPU together - Super User] https://superuser.com/questions/1754003/different-outputs-when-encode-to-h265-using-cpu-only-and-gpu-together


再补充一些对hevc_nvenc的测试:

ffmpeg -i input.mp4 -vcodec hevc_nvenc -preset [xxxxxx] output.mp4

接下来的测试中仅改变-preset xxxxx的参数

(和cpu不同)hevc_nvenc环境下,-preset几乎完全决定了输出视频的质量

源文件9.6M的h264

没有slower和veryslow
-preset slow 输出15.2M的h265,质量和原h264文件相当,speed=0.966x
-preset medium 输出15.3M的h265,质量和原h264文件相当,speed=3.11x
-preset fast 输出3.3M的h265,糊成一团,speed=7.58x
不写-preset 输出15.3M的h265,质量和原h264文件相当,speed=3.11x,推测此时就是使用了-preset medium

看来slow, medium, fast这种preset参数不太行,试试-preset p5这样的写法
-preset p5 输出15.3M的h265,质量和原h264文件相当,speed=2.52x
-preset p4 输出15.3M的h265,质量和原h264文件相当,speed= 3.1x
-preset p3 输出15.3M的h265,质量和原h264文件相当,speed=4.49x
-preset p2 输出15.1M的h265,质量和原h264文件差不多相当,speed=5.04x
-preset p1 输出3.3M的h265,糊成一团,speed=7.61x

作为对比的cpu软解libx265:

ffmpeg -i input.mp4 -c:v libx265 -vtag hvc1 -preset [xxxxxxx] output.mp4

接下来的测试中仅改变-preset xxxxx的参数

-preset对视频质量的改变不大:

-preset slow 输出5.6M的h265,质量和原h264文件相当,speed=0.807x
-preset medium 输出5.4M的h265,质量和原h264文件相当,speed=1x
-preset fast 输出5.6M的h265,质量和原h264文件相当,speed=1.45x
(跳过了faster, veryfast, superfast)
-preset ultrafast 输出3.9M的h265,质量看得出下降了一点,但肯定要比hevc_nvenc的那个3.3M的糊成一团h265好得多,speed=2.68x

而且还有一个很重要的一点,就是使用hevc_nvenc的时候,gpu使用率并不高(普遍只有5%以下;只有-preset fast的时候才会占用15%的样子),要想彻底利用显卡,可能还是要写脚本同时处理多个视频能占满gpu. 写脚本也未必有用,因为我发现同时运行多个hevc_nvenc实例时,每个ffmpeg进程的gpu利用率更低了(比如开3个进程,就是3% + 1% + 4%)。看来hevc_nvenc这个东西可能天生就很难占满某些nvidia显卡,或者说是我的ffmpeg指令有问题。


目前的结论

整篇笔记的服务对象只有一个:对h264视频进行高效且高质量的h265编码。所以下面的结论仅仅适合我的使用需求。

原本的设想是:使用hevc_nvenc以后,gpu占用率可以达到100%(单文件),处理速度很快,而且h265的产出质量(指文件大小和视频质量)和cpu软解libx265差不太多。

但事实上是:使用hevc_nvenc以后,单文件ffmpeg命令的gpu占用率很低,处理速度虽然比cpu快,但h265的产出质量极难控制:想要视频质量好,视频文件体积往往大于cpu软解,而且编码速度也不快;如果仅通过-preset把视频文件体积降下来,视频体积大概率会一下子降得特别厉害(从-preset medium到fast),视频画质也随即变成了一团糊糊。

目前看来使用显卡进行高效且高质量的h265编码还是不太现实。

Leave a Comment Anonymous comment is allowed / 允许匿名评论