用ffmpeg gpu进行转码失败,求解答

Note: 此文章首发于我的个人博客zhi-hua.wang ,开放转载但需附上出处。

FFMPEG 是一款开源的视频处理软件,再利用FFMPEG转码的过程中踩了很多坑,在这里列举一些常用的 FFMPEG 命令防止忘记。

以下所有的命令的输入都是《The.Mandalorian.S01E01.INTERNAL.HDR.2160p.WEB.H265-DEFLATE.mkv》这部影片,这部影片有很多特殊的地方,所以给我带来了不少困扰。它也驱使我学习了关于视频的很多知识,以下是它的一些基本参数:

bt2020nc 。为了节省篇幅,以下均以input.mkv代表这个视频源文件。而且由于配备了gtx1070显卡以及安装了最新的驱动,所有的操作都是尽量利用GPU进行硬件加速。

告诉ffmpeg使用cuvid加速,并且把视频的数据保留在显存而不是内存上。由于版权问题ffmpeg不自带scale_npp滤镜,需要自己编译。为了方便我选择manjaro系统,直接安装AUR上的ffmpeg-full包。这个过程也很心酸,可以专门写一篇文章了,这里就不展开了。关于ffmpeg转码的文章在互联网上有很多,尤其是英伟达官网的《ffmpeg

运行以上命令却报错了。原来scale_npp滤镜很娇气,无法处理10bit的视频,因此尝试失败。

输入以上命令,发现咋只有48fps呢?那岂不是要十几分钟?太慢了!

突然发现了scale_cuda这个宝藏,它能接受10bit输入。而且scale_cuda在ffmpeg的编译版中自带!这就好办了,赶紧敲下以下命令:

所有任务都转到GPU上运行了,性能得到巨大提升。通过观察发现此时的瓶颈变为了GPU解码。GPU解码器的占用率高局100%,而编码器只占用了不到20%。

经过长时间的试错,发现之前的错误通过在scale_cuda滤镜后添加hwdownload,format=p010le就可以解决了,至于为啥我也不知道 。-hwaccel_output_format cuda目前可以不加,只不过会警告你以后不加就会报错了。

这一条与上一条没多大的区别,只是把scale_cuda改为了resize。resize这个参数是我从英伟达官网上的一篇pdf上了解到的,它说用resize性能好一些。至于好不好我不知道,我只知道resize更易读与打出来。

之前的转码都是恒定码率模式,很不科学。hevc_nvenc没有crf参数,这可咋办呢?好在找到了替代方案。通过将-rc:v 设置为vbr或者vbr_hq,从而启用VBR模式,然后设置-cq:v-qmin-qmax。这里最好把它们设置成一个数值,否则没有多大意义。这个数值接类似于crf参数。

经过前面这么多的折腾,视频已经压制好了。可是越看越不对劲。为啥我压的视频看起来灰蒙蒙的呢?经过深入调查发现是由于HDR导致的。这个视频本身是HDR的,而转换过程中ffmpeg并没有保留HDR有关的元数据(这应该是个BUG),又没进行颜色的转换。所以播放器把这个HDR视频当作SDR来处理,就会导致画面发灰。解决办法有两种,一是将其转为SDR,这需要tonemap滤镜(似乎scale滤镜也可以)。另一种是保留元数据,让播放器能够正常处理。这里选择第一种。由于tonemap是运行在cpu上的,效率低,所以我改用它的硬件加速版:tonemap_opencl

注意下面的命令我只在linux上测试成功过,win10会报错,我也不知道为什么。

tonemap_opencl的这些参数中,tonemap指定了使用的算法,可选值为nonecliplineargammareinhardhablemobius。param是用来微调这些算法的。具体的内容看ffmpeg的文档。这里最重要的是将p、t以及m都设置为了bt709。所以这个滤镜会完成以下转换:色彩原色: bt2020->bt709、传输特性:smpte2084->bt709、矩阵系数:bt2020nc->bt709 (HDR有多种不同标准,smpte2084对应的是HDR10。 经过HDR->SDR的转换,颜色终于变得正常了,不过仔细看肯定和原片有差距。可以根据画面的特色选用不同的算法和参数来进行调整,以保证画面的准确度。

9. 颜色偏差--添加HDR元数据(失败)

上一节我们将HDR转为了SDR,画面的准确度有些许丢失。那该怎么办呢?之前说到还有一种方法,那就是保留元数据。我尝试过用MKVToolNix将色彩原色、传输特性以及矩阵系数分别设置为9、16和9。然后这个视频在linux上播放正常了,但是在windows上还是灰的。我真的是很无语!!!

我在github上还找到了另外一个项目,叫做nv_hevc_hdr_patcher。但是这个项目看起来挺不好用的,我懒得折腾,所以HDR元数据添加宣告失败(怎么可能这么轻易放弃,下一节会用其它工具搞定这个问题(如果我还会继续写的话(会吗?)))

使用FFMPEG,在尽量利用硬件加速的情况下完成了视频的压制。直接转码时会丧失HDR元数据,导致发灰(见下图中间一栏)。通过tonemap可以将HDR转为SDR视频,画面的颜色得到较为准确的还原,但还是有轻微的差别。最终也没能够完成HDR元数据的添加。

直接压片,元数据丢失导致发灰

根据谷歌统计的数据,由于去年疫情带来的增长加速,再加上视频会议、AR/VR与云游戏等应用的兴起,视频服务已经占据整个互联网60%以上的流量。而这也使得服务器端视频处理能力的要求在不断拔高,处理的对象已经不再是1080p 30帧的短视频了,而是对4K以上的HDR视频进行实时转码。
除了开发更高效的视频编码(VP9、AV1等)和媒体框架之外,硬件平台也是不可或缺的一环,市面上也涌现了不少大相径庭的硬件方案。传统的CPU在新编码上早已显得吃力,而GPU虽然性能优越,但计算流量过大,服务器的成本要高出一截,因此不少云服务厂商也开始推出专用硬件来进行视频处理。
GPU作为最常用的视频处理硬件,也理所当然地成为了数据中心视频转码的选择之一。目前常用于视频转码的最新英伟达GPU为T4。该卡包含320个图灵Tensor核心和2560个CUDA核心,单精度算力达到8.1 TFLOPS。英伟达称在独立的硬件转码引擎下,与前代GPU Tesla M60相比,其转码性能提升至2倍,同时支持38个1080p的视频流。

除了英伟达之外,AMD也有可用于视频编码的Radeon Pro V520 GPU,根据全球最大的云服务厂商亚马逊AWS公布的数据,其通用图形渲染性能要高出英伟达T4 40%,单卡最多支持6个1080p60的视频流同时编码。
除了传统的通用GPU方案外,另一个常见的方案就是采用专门的视频处理加速卡,比如赛灵思于去年发布的数据中心媒体加速卡Alveo U30,专用于高密度的视频转码应用。该卡的APU采用了4核Arm Cortex-A53,RPU采用了双核Arm Cortex-R5F,而GPU采用了Arm Mali-400 7002)的C5实例相比,成本更是低上60%。
除此之外,赛灵思还会提供其视频转码SDK,不仅整合了FFMpeg,更有媒体加速API与U30上的编解码器直连,今年年末还会推出对于另一框架GStreamer的支持。
亚马逊不仅推出了基于这类加速卡的云服务,旗下的直播平台Twitch也在使用这类实例。Twitch称计划将VT1实例用于数百万计的直播转码,以此实现在更密集的串流和低延迟下,不牺牲视频的压缩或画质。
作为仅次于亚马逊AWS和微软Azure的云服务厂商,谷歌在其公共云服务上依然在使用传统的GPU方案。但坐拥全球最大的视频平台Youtube和成立不久的云游戏平台Stadia,谷歌决定在这些服务上采用自己的硬件来加速视频处理。
作为视频编码标准VP9的开发者,谷歌想要同时实现H.264和VP9支持,以及多输出的转码,并在直播与离线转码中达到理想的速度与质量,还能全面控制软件算法进行调整,因此谷歌决定开发自己的硬件VCU芯片。
谷歌基于该硬件打造的系统具有两张VCU加速器,每个加速器内置了10个VCU编码器核心,每个核心都能够实时编码2160p的视频流,使用三个参考帧时可达60FPS。经过在H.264二次编码上的输出对比,8块VCU芯片的性能是4块英伟达T4性能的两倍以上,是英特尔Skylake CPU的8倍以上,在VP9编码上的性能差距更是可以拉到20倍。
在视频处理方面,尤其是视频编码转码上,CPU+GPU的通用传统方案已经在失去其优势,专用的加速器方案明显在成本和性能突破上走的更快一些。这种趋势在数据中心的其他应用领域上也在慢慢显现,比如深度学习、AI等,专用加速器的方案更适合针对性更强的场景。随着云服务厂商不断推出更多的专用实例,GPU在视频处理上的地位很可能会被专用加速器给替代。

ffmpeg 转码mp4视频时,由于视频录制有问题(可能是丢帧过多),转码无法完成,处理卡住无法退出,CPU一直飙在100%。

1. ffmpeg能否在转码前判断文件是否可以正常转码?
目的:不能正常转码时不进行转码处理
2. 批处理转码过程中遇到这种问题时,怎样判断/中断操作?
目的:避免由于任务卡死、CPU飙高等原因影响其他服务。

我要回帖

更多关于 plex可以用gpu转码嘛 的文章

 

随机推荐