最近做图像预处理的工作有点多。这里记录一下最近做OpenVINO推理的端到端优化时对FFMPEG做图像预处理的一点心得。
这几天碰到的问题是在准备给mobilenet-ssd神经网络推理前需要对视频文件做解码,然后缩放到需要的分辨率再转成RGB格式的数据,这样才能丢进网络里做推理。这个解码,缩放,色彩转换的流程通常是通过FFMPEG来实现的,通常的代码实现流程是
流程示意图
对应的FFMPEG命令行大致等同于
ffmpeg -hwaccel qsv -c:v hevc_qsv -i 1.mp4 -vf hwdownload,format=nv12,scale=w=1920:h=1080 -pix_fmt rgb32 -f sdl -
这样的处理会有一些性能上的损失
更为高效的办法是将缩放和颜色空间的转换都放在GPU侧去做,由GPU把所有的数据预处理都做好,CPU只需要读回数据,就可以直接丢进推理网络里。
流程示意如下
如果要用GPU做图像缩放和色彩空间转换,网上有很多教程,例如用OpenCL代码来实现。但是对于我这个混子程序员来说,能不写代码就不写代码。经过一番搜索,终于让我得到了答案
在这里https://trac.ffmpeg.org/wiki/Hardware/QuickSync有这么命令
这个命令是利用FFMPEG的filter插件vpp_qsv, 将hevc_qsv解码出来的数据缩放成1920x1080分辨率,rgb32格式, 然后用hwdownload将数据读到系统内存,再送到sdl中显示。
照着这个命令运行一下,发现出错了。换了几个FFMPEG版本,结果都一样
什么叫不支持bgra的像素格式?百思不得其解。万般无奈,只能祭出VS2017的debug大法,经过一些跟踪和调试,发现问题出在创建vqq_qsv滤镜的时候, 在滤镜初始化创建directx的surface buffer的时候,会调用到libavutil\hwcontext_dxva2.c里dxva2_init_pool()函数,在line 172行左右会检查传进来的ctx->sw_format是否是dxva2 surface支持的像素格式。
而支持的像素格式在第79行
只支持NV12和P010? 实在不明白为啥,随手加个一行,看看能不能跳过去继续往下走?
编译FFMPEG, 再运行刚才的命令
图像竟然出来,还正常播放结束了!!!
下面来比较一下2个命令的CPU/GPU占用率和解码播放的速度有什么不同
#命令1, CPU做缩放和颜色转换
ffmpeg -hwaccel qsv -c:v hevc_qsv -i 1.mp4 -vf hwdownload,format=nv12,scale=w=1920:h=1080 -pix_fmt rgb32 -f sdl -
#命令2, GPU做缩放和颜色转换
ffmpeg -hwaccel qsv -c:v hevc_qsv -i 1.mp4 -vf vpp_qsv=w=1920:h=1080:format=rgb32,hwdownload,format=rgb32 -f sdl -
播放速度2.03x
CPU占用率16%,可以看到有一个核基本是100%占用率。 GPU占用率39%
播放速度3.4x
CPU占用率16%,可以看到有一个核基本是70%占用率。 GPU占用率56%
可以看出,
有sdl显示 - 播放速度0.661x, CPU占用率18%, GPU占用率30%,
无显示 - 播放速度 0.852x
有sdl显示 - 播放速度1.51x, CPU占用率18%, GPU占用率58%
无显示 - 播放速度4.25x
可以看出
问题解决了,FFMPEG的基于Intel QSV的一些滤镜用起来还是很方便的,比如vpp_qsv可以做图像分辨率缩放,色彩空间转换,帧率转换以及图像的截取crop以及各种图像效果增强等功能
具体的功能和参数可以用命令来查询
ffmpeg -h filter=vpp_qsv
但是有2个疑点还没有找到答案
这几个问题只能留着慢慢以后再解决了...