文 / 郭叶军
整理 / LiveVideoStack
点击拓展链接查看回放视频

很高兴能有机会在LiveVideoStock做有关于FFmpeg深度学习模块干系内容的技能分享。
1 为什么须要在FFmpeg中实现深度学习模块
首先,为什么须要FFmpeg深度学习模块,FFmpeg对输入的码流,首先进行解码,解码后得到一个个的视频帧,以及相应的音频数据等。经由一系列的Filter之后,末了可以进行重新编码或者直接播放出来。这些filter的功能包括传统的图像处理,也包括一些统计功能,比如直方图等。在深度学习的算法出来之后,由于他太有效了,包括很多的算法功能,例如超分辨率、目标识别、人脸检测、目标检测、人脸识别等等,都须要深度学习的算法来实现。以是,我们须要拓展filter的功能,使它可以支持深度学习算法。
当我们将深度学习的算法加入到FFmpeg的Filter之后,Filter就拥有了很多打算机视觉干系的算法。那么它与比如说OpenCV的打算机视觉软件包有什么关系?这个问题我们可以从两个角度来看:在支持深度学习算法之前,FFmpeg与OpenCV是相互合营、相互支持的一种关系。例如在OpenCV中,可能须要先调用FFmpeg进行视频解码,解码完成后回到OpenCV中进行相应的打算机视觉算法运用。此外,在FFmpeg中有一些Filter,这些Filter背后调用的便是OpenCV,通过这种办法来利用OpenCV中的一些算法功能。但是在比较新版本的OpenCV中,接口语言切换成了C++,而在FFmpeg中哀求的是C代码和并且调用的是C库的接口, 因此FFmpeg基于OpenCV的Filter就很难用上OpenCV的最新算法功能,以是在这种情形下就很有必要在FFmpeg增加深度学习模块来支持多个Filter运用深度学习算法。
从其余一个角度来看,在之前,对付打算机视觉的算法开拓者来说,会在OpenCV中进行算法实现,代码完成后基本不太可能再次在其它运用中重新实现一次,那么这也就造成了很多的打算机视觉算法都只在类似于OpenCV的软件包中完成。而在深度学习模块,算法实现的载体已经从以前的代码变成了模型文件,模型文件可以很随意马虎的分发出去,被各个软件包通过恰当的办法进行加载、实行,从而实现一些深度学习算法的功能。综上所述,无论从什么角度来看,我们都有必要在FFmpeg中增加深度学习相应的模块。在增加深度学习模块之后,对付FFmpeg的开拓者来说开拓事情会更灵巧,速率更快。想象一下,在这之前对付FFmpeg的开拓者来说,须要首先调用FFmpeg的API进行解码,解码完成后,再编写代码或者调用第三方库等实现深度学习算法的运用,末了再回到FFmpeg中进行编码。而深度学习模块就相称于将之前用户须要自行开拓的深度学习实现干系的部分转移到FFmpeg内部,以Filter的形式对外暴露,因此对付FFmpeg的开拓者来说开拓变得更加便捷。
2 FFmpeg深度学习模块的发展历史
其实在2018年FFmpeg才开始支持深度学习模块,是经由一个GsoC项目,即谷歌关于鼓励在校学生做演习生的活动,鼓励大家进入各个开源社区做一些代码事情。由于详细的代码实现一样平常都在7、8月份,以是称为Summer of Code,项目的效果还不错。2018我紧张通过邮件参与谈论深度学习模块如何运用,但在GsoC2018完成之后,创造没人进行接下来的掩护。于是在2019年,我基于这一部分做了很多事情,包括贡献了绝大部分的代码。除此之外,大师兄刘歧还带了一个GsoC2019的项目,带领一名北大的学生基于深度学习的模块做了些有关Filter的事情。2019年年底,我成为了深度学习模块的Maintainer。
到了2020年,发生了一个比较大的变革是我们将OpenVINO(英特尔的一个深度学习的推理引擎)加入到了FFmpeg的深度学习模块中,同时也开展了一个GsoC项目,希望将深度学习模块中的一些功能进行优化,能够利用汇编措辞做一些速率的提升。希望在2021年看到GsoC2021在FFmpeg深度学习模块中的一些项目进展。
3 FFmpeg深度学习模块总体架构
深入到FFmpeg中看一下深度学习模块的总体架构:FFmpeg是由多个库组成的,上图左边列出了部分:libavcodec是音视频解码干系的、libavdevice是音视频输入输出干系的、libavformat是如何将音视频码流组合到一个文件中、libswscale是对视频帧的一些处理、libswresample是对音频数据的重采样,以及所有util干系的Tool放在libavutil中。与深度学习模块密切干系的是libavfilter模块,由于我们的深度学习模块目前紧张是为Filter做事的,以是放在libavfilter模块中。对外,我们的深度学习模块可能会调用TensorFlow的 C动态库,也可以调用OpenVINO的C动态库,也便是说须要提前在系统中安装TensorFlow或者OpenVINO的C库的.so文件、.h文件等等。
对付libavFilter内部,前面提到,我们可以有很多基于深度学习算法的Filter,也可以调用多个深度学习模块,以是中间涌现DNN接口层,对Filter以及下面的backend进行解耦。目前系统中有三个Filter与深度学习算法干系。第一个是Super-Resolution的Filter,是在GsoC2018的项目中加入的,支持了两个算法模型:一个是ESPCN,即输入的是一张低分辨率的图片,输出的是高分辨率图片,模型直接进行超分运用;其余一个模型叫做SRCNN,首先将一张低分辨率的图片经由快速放大,变成一张高分辨率但质量较为一样平常的图片,这张图片经由SRCNN算法之后,分辨率保持不变、图片质量会变得更好,在后面我们会用到SRCNN算法举例进行解释。
第二个Filter叫derain:输入一个RGB格式的图片,调用的模型的算法可以将图片中的雨滴去除掉,这是在GsoC2019完成的。我们剖析前面两个Filter就会创造,实在这两个Filter实现的算法功能是在模型文件中表示的,在Filter里面的代码更多的是将FFmpeg的数据构造与模型文件的输入输出进行连接。因此从这个角度来看,我们就没有必要为每一个算法功能实现一个Filter,我们可以做一个比较general的Filter —— dnn_processing。只要调用这个Filter,无论模型文件供应的算法功能是什么,只要将FFmpeg与模型文件实行前后的数据流串通起来,就可以实现任何与图像处理干系算法的支持。
下面一层便是三个backend:TensorFlow backend对外调用TensorFlow的C动态库,OpenVINO backend就会对外调用OpenVINO的C动态库。如果考虑到系统中既没有TensorFlow也没有OpenVINO,我们可以选择转换到Native backend,即相应的代码实现都在FFmpeg代码树中,可以直接拿来用。后面将会以Super-Resolution里面的算法模型为例,通过dnn_processing这个Filter举例解释如何利用这三个不同的后端。
4 FFmpeg深度学习模块接口
目前接口紧张分为三块:第一,有一个最基本的函数,输入的是backend type,可选值是Native backend、TensorFlow backend或者OpenVINO backend,根据这个backend会返回一个DNNModule。在DNNModule数据构造中首先要做的便是给出模型文件所在的路径,奉告Module加载模型文件,加载完成后会在Filter中进行判断,查询加载的模型输入的信息(包括输入NHWC中的每个维度的数字是什么,formate是float32、RGB还是int8等等)。查到干系信息后再与FFmpeg的数据流进行比较是否能够匹配,如果channel的数据匹配不上,则返回error,如果是其它的一些数据构造的大小有变革的话,可以提前做一些scale的转换,或者做color spaceconvertion的一些变换。当统统都变换好之后,我们就会在为模型设置好输入、输出之后完成实行。当然,用set_input_output来设置模型的输入/输出紧张是将输入/输出的变量名字奉告Model,方便后续实行时清楚的知道要将FFmpeg的数据添补到模型的哪个地方,以及模型的哪个地方是输出,获取到输出的数据重新放到FFmpeg的pipeline里。然后对每个Filter进行这样的操作,做模型的推理,当所有的码流或者图片实行完毕之后,实行Model即可。以上便是深度学习模块紧张接口的利用方法。
5 三种后端运用实例
5.1 重现编译FFmpeg
前面提到深度学习模块有三种后端,分别是OpenVINO、TensorFlow和Native。下面举例解释该当如何运用:首先第一步,TensorFlow backend在默认编译FFmpeg时是非enable的,以是我们须要加入一个选项,奉告FFmpeg的build system,须要enable TensorFlow。在此之前我们要在Tensorflow的官方网站下载1.14(建议)版本,解压、安装到系统目录下,包括.h文件和.so文件,然后再在configure进行以上配置,就可以天生支持TensorFlow backend的FFmpeg的可实行程序了。
如果须要用的是Native backend,任何选项都不须要加,由于相应的代码已经直接写在代码树中。
如果是利用OpenVINO backend,则与Tensorflow backend类似,也要加入选项,奉告FFmpeg接下来我们要启用OpenVINO backend。一样平常来说,OpenVINO的默认安装目录不是系统目录,以是须要增加一些额外的cflags,指出OpenVINO的头文件在哪里,用ldflags指出OpenVINO的.so库在哪里。在configure的同时,其内部会写一个最大略的OpenVINO运用程序进行编译并且实行,只有统统都通过,才会启用OpenVINO的后端,因此前面须要加LD_LIBRARY_PATH指出OpenVINO的.so所在的位置。
通过这样的办法,我们就可以得到三种后端,即Tensorflow+backend的后端、Native+backend的后端或者OpenVINO+backend的后端,得出的结果都是一个可实行的程序,叫ffmpeg或者ffplay等等。
5.2 准备SR模型文件
准备好可实行的程序之后,我们就可以准备Super-Resolution的模型文件了。首先我们要来准备TensorFlow格式的模型文件。一开始这个是在vf_sr.c的Filter中写的,也便是说我们须要下载一个第三方的库,运行python脚本,就会天生srcnn.pb。这便是基于Tensorflow格式的模型文件,包括了已经演习好的数据。
在这个根本上,如果我们须要利用Native backend,就须要在我们的FFmpeg/tools/python目录下调用convert.ty这个python脚本,它的输入便是Tensorflow的pb文件srcnn.pb。然后会天生在FFmpeg中自定义的一种新的格式——srcnn.model文件,这个.model文件就可以被Native backend加载和实行,这是我们在FFmpeg中自定义出来的,比较简洁。
如果须要利用OpenVINO后端,实在OpenVINO可以支持多个不同格式,例如Tensorflow格式、通过中间转换的办法支持pyTorch格式,支持ONNX格式等等。OpenVINO的源代码中有一个model-optimizer目录,在这个目录中有多少python脚本。例如mo_tf.py脚本文件就可以将Tensorflow格式的模型文件转换为OpenVINO支持的格式,OpenVINO的模型文件有两个,分别是.xml和.bin文件,我们只须要将这两个模型文件放在同一个目录下即可。
如果大家想重现上述内容,而转换又比较麻烦的话,大家可以在图中最下方的网址中下载相应文件。
5.3 运用SR算法
准备好相应的程序和模型文件后,接下来要实行的FFmpeg的命令行如图所示。
TensorFlow backend命令行:
-i:输入文件是什么。一样平常来说FFmpeg处理的是视频。在这里为了方便展示,我们输入一个.jpg文件,解码之后就经由多少的Filter。由于我们的模型须要的是YUV格式,我们首先运用了format的Filter进行格式的转换,以确保输出的是YUV格式。然后我们调用scale的Filter,其目的是为了将输入图片的长和宽大略的放大一倍,得到高分辨率低质量的一张图片。这张图片再经由dnn_processing的Filter,就可以变成相同分辨率高质量的图片。在该Filter中的参数部分,我们须要指出后端是Tensorflow,其模型文件是什么,以及模型的输入输出的变量名是什么,才能将FFmpeg的数据构造与模型串联。
如我们须要的是Native backend,只须要改变backend的flag,并改变模型文件的文件名即可。同样的,对付OpenVINO来讲,其它参数都保持不变,只要将OpenVINO的flag传进去,并调度模型文件为srcnn.xml。Filter会根据flag经由dnn interface再调用希望运用的backend,终极完成相应的算法功能。
6 下一步操持
那么接下来我们会有哪些新的实现操持?
第一,我们现在实行的是同步的处理,即给到一个frame,实行完毕后才会返回,这样在有些时候会影响整体效率。因此接下来我们会实现一个异步的实行,即在吸收到一个视频帧后,直接将视频帧输入到深度学习模块中,在推理完成之前返回调用,希望能够加快处理的速率。并且在这个根本上,我们就可以支持batch support,也便是每次推理并非一帧一帧进行,而是支持一次多帧的处理,尽可能用高下面硬件的并行处理功能。
除此之外,刚才一贯强调的模型的输入输出与FFmpeg的数据构造之间须要做一些恰当的转换。由于模型的输入千变万化,存在很大可能性,而目前只是支持一些比较固定模式的转化,因此希望后续可以加入一些比较灵巧的转化。再接下来,由于不同的backend会有自己的特性,须要单独设置flag,那么我们就须要在接口中为每个backend实现其私有的操作选项,从Filter向下通报到相应的backend中。其余,从Filter的角度来讲,实在还有很多事情是可以做的。例现在朝增加的Filter只是可以用来对图片进行处理,而没有实现剖析的功能,例如检测和识别等这些都是下一步须要做的。乃至包括音频干系的Filter,例如将识别音频转化为笔墨内容等等。
末了以FFmpeg深度学习模块Maintainer的角色,非常欢迎大家对FFmpeg深度学习模块提出建议或见地,包括增加更多的基于深度学习模块的Filter,欢迎大家一起谈论。
末了为大家推举一本书本《OpenCV深度学习运用与性能优化实践》。书中紧张讲解了OpenCV深度学习模块中加速干系的内容,很多加速的代码都是由作者实现并贡献出来的,并且将实现时的一些想法都写入了书中,算是比较少见的一手信息。在书本的末了,我们还先容了一个完全的人脸活体检测的过程。包括先将人脸检测出来,再确保该检测出来的人脸是一个真实的人,不是视频、图片或者面具等,即所谓的“活体”。确保为活体之后,再进行识别这个人是谁。即从检测到防敲诈再到识别的全过程,全体过程包括源代码都在书中有详细先容,有须要或者有兴趣的朋友可以理解一下。
https://www.livevideostack.cn/video/online-gyj/