背景
项目中使用QT开发监控软件,集成海康、宇视、大华、华迈、以及网络流设备。品牌设备使用SDK控制,网络流设备自己使用FFmpeg库来解决。网络流设备如果同时解码多路播放,会出现CPU占用较高、操作卡顿的情况。如果视频流路数更多如16路,或解码更为复杂的如H265,那么CPU将无力支持,甚至异常崩溃也是很可能的。
问题分析
视频的播放是需要一定的计算能力支撑的。主要是体现在解码以及渲染两方面,默认FFmpeg是软件解码(软解),然后将解码出来的数据进行下格式转换,再通过QPainter渲染显示出来,都是使用CPU来计算。所以此种方式当路数增大,CPU资源占用不断提高,就会出现资源不足卡顿现象。
但此种现象是正常的,干的活多,CPU消耗的资源自然就会越多,所以要做的就是把CPU的任务分担出去给GPU,即硬件解码及渲染。
硬件解码
1.思路
GPU,图形处理器,可以先简单认为是各种核显,独立显卡。CPU能者多劳,但总有极限,GPU一般是专门进行图像相关的处理。那么就可以把音视频的解码以及渲染交给GPU来做,将极大解放CPU,当然不同的GPU也是能力大小不同的,所以GPU不能保证解码效果一定比CPU好(也不会太差),它主要是代替CPU分担解码的工作。
2.方式
如何使用硬解呢?百度一下,就会看到经常出现出现的几个词:DXVA2、 D3D11VA、QSV、libmfx、CUDA、VAAPI等。有必要先了解下DirectX(Windows系统提供的多媒体库接口),PC平台视频的硬件编解码、渲染等与此有关。总体看硬解方式还是比较多的,这里细节不展开介绍,我们来从使用角度来认识,具体可以参考FFmpeg硬解的示例程序,这些方式可以分为两类:一类是显卡本身提供的API;一类是系统封装的API,。
- 显卡本身提供的,可以理解为一块电路板的说明手册,你直接用对应的接口就能操作GPU的资源来做想要的处理,如VAAPI、libmfx等
- 系统封装的,系统层面的API接口,忽略硬件差异,如只要你用Windows系统,你就可以用DXVA2等系统提供的接口,不用管系统怎么具体操作GPU的
硬件渲染
通过硬件解码,已经可以较大减轻CPU的负担。原理就是CPU将原始的音视频数据提供给GPU,GPU来做处理然后得到解码后的数据,CPU不参与解码过程。到这出现一个问题,解码后的数据怎么处理?图像的渲染也是比较占用性能的,因此这里也是性能提升点,一般两种方式:
- 解码后的数据从GPU再传输给CPU,已经拿到解码数据可以调用QPainter或三方库来渲染图像
- 自产自销,GPU中的解码数据,直接通过GPU方式渲染图像
两种方式根据实际都可以选择,但明显,第二种方式更能解放CPU。因为整个播放流程的主要的解码、渲染工作都交给CPU做了,此时CPU即使还会有些处理占用,也是很低的了。这里个人的做法是采用SDL库,十分成熟稳定性能也较高,可以灵活的切换CPU、GPU渲染方式。已经封装好了代码类,放于这篇博文音、视频输出类封装
测试
通过以上两步,经过实际测试,同时处理16路视频流(H265、H264编码),CPU有显著下降,运行正常无卡顿,在另外一台性能更好的主机上同时播放25路也能较为流畅地播放。相较于软解方式,性能提升巨大,可在任务管理器查看CPU、GPU的占用情况。
至此,问题得以解决。程序复杂度略有增大,如果只是播放单路流或者不会占用过多CPU资源,默认软解即可。
说明
这篇是讲解FFmpeg软、硬解码主干思路的文章,搞清原因及解决思路,细节可以自行搜索相关文章,有很多大佬的文章。只要抓住主干理清思路,剩下按部就班,自然水到渠成。