本演讲主要讲解如何通过FFmpeg作为一个主要的接口,将OpenGL、OpenCV以及诸如Tensorflow等AI框架以第三方库的形式,作为FFmpeg的一个模块进行快速的业务开发,从而简化音视频图像处理的开发流程,为听众打开一个新思路。
文 / 刘歧
整理 / LiveVideoStack
审校/ 赵军
感谢大家关注FFmpeg在OnVideo以及AI方面的一些工作,我是刘歧,是OnVideo联合创始人的同时也担任技术负责人,同时也是FFmpeg的官方顾问,FFmpeg GSoC 2019 Mentor,FFmpeg决策委员会的委员,以及腾讯云TVP。我主要的兴趣在嵌入式开发、图形图像及音视频流媒体处理、分布式系统设计等领域。FFmpeg官方有我的联系方式,大家有问题可以和我随时交流。关于FFmpeg深度学习场景下的应用,目前看来,颇具价值且实用。
1. 契机
![875d964b996c90e1fa1c12c30dfb1262.png](https://i-blog.csdnimg.cn/blog_migrate/0b475d96b57582729ce226d2835ef0e0.jpeg)
首先介绍一下我们的公司,OnVideo是一个音视频在线编辑云平台,上图是制作人员的处理过程中效果预览这个功能的一个展示。OnVideo云平台可以支持很多的图像处理相关功能,但实际上它并不限于视频和图片相关,它大量的使用了FFmpeg的一些内置功能以及AI相关的框架与算法,其具体功能大约如下图所示:
![98a79170afa90fa7fed8ac3625fac76a.png](https://i-blog.csdnimg.cn/blog_migrate/ca3ccde09ed8df81370b10565400f7e8.jpeg)
![91cde0f896c33a2d06fa1fed85aadb52.png](https://i-blog.csdnimg.cn/blog_migrate/413078f2143ef8300cd1f0dc149ddcaf.jpeg)
另外一个需要附带提及的事情是我在2019年Google Summer of Code期间指导学生做的一个深度学习相关FFmpeg Mentor Project,这是一个基于神经网络实现对图像进行去雨点、去雾的功能(本质上这两个是类似的功能),最终实现并放入了FFmpeg。
![e01de883c89a3c8d110b6e44de2656be.png](https://i-blog.csdnimg.cn/blog_migrate/1b7073bff4486c255d5289d79be38933.jpeg)
在做FFmpeg GSOC项目期间,首先和有意愿的学生事先沟通,然后在FFmpeg社区以及GSOC上申请立项,之后是与学生沟通要达到去雨点去雾的功能要点,做出实际的开发计划任务,紧接着,我安排并引导学生去了解了FFmpeg的一些基本功能以及相关原理,随后实现了去雨点去雾的功能,需要注明的是,FFmpeg目前的去雨点,去雾使用了基于AI的方式,目前FFmpeg同时支持两类后端,其中一个是FFmpeg native的DNN后端,但性能较差,主要用作验证,另一个是可以在实际场合中部署的TensorFlow后端。上图展示了最终的一个结果,图中上半部分为原图,下面是对应去雨点去雾的图像,需要注意,虽然目前的实现基本上能解决大部分的问题了,例如天气恶劣的环境采集的图像后期处理,通过这种技术可以节省很多时间,但更广泛的现实场景是有可能会存在一些瑕疵,这可能是目前AI算法普适性的一个通用问题。接下来重点分享一下onVideo中更细节的一些技术内容。
2. 初级处理
![d84e527d370eb256f9a141ea35ec2773.png](https://i-blog.csdnimg.cn/blog_migrate/da4d04e6ca1b5863ab6139ad30a745ce.jpeg)
做音视频的云端处理,尤其是Web-base的场景,最忌讳的是前端Web部分预览看到的内容与后端实际生成的结果不一致,会导致非常尴尬的用户体验,我们的第一步就需要将Codec格式统一化,此步会在云端进行处理,对于输出,在客户要求的情况下,我们会给到高清版本,否则就给到低清版本,原因是高清版本流量消耗较大,会耗费很多带宽;另外,实际使用中,常规的预览并不真正需要高清,除非用户有特别需求。另外,为了后期在后端处理更快,会将所有内容变成I帧,这样的好处是可以精确处理到帧;其次,我们也使用了FFmpeg提供的一些基础的滤镜,概述如下:
画字体(FFmpeg的字体功能使用了FreeType等),为了解决其中一些瑕疵(例如某些系统下的文字大小粗细不一致)尝试过更改drawtext,但效果不理想;另外,如果字体找不到的话,那会变成一小方块,此时只需要换一个字体库即可。再就是subtitle,唱词的时候用subtitle,例如电影中的字幕,可以切为一段一段。
在平时我们做视频切片处理的时候,会有一个问题,在生成一个视频之后,所有视频的start time全都会归零,在切片时,需要将多轨道的时间都对上,所以setpts和asetpts、adelay、atempo这些功能强大的Filter,在处理音视频的编辑中,例如多轨道叠加或者边缘对齐等需求下,起了非常大的作用。我写过一篇关于setpts的文章,大家有兴趣可以去阅览一下。
overlay多图层:有时候我们并不只是要求单纯的设x,y,也需要同时需要调整宽高,但overlay不直接支持宽高的调整,这可以通过一些简单的开发,例如增加前景宽高处理用来做缩放效果,或者还有一些其他效果例如使用expr的办法。另外,FFmpeg有内置方法,可以直接做一些想要的效果,例如跑马灯效果,游动效果等;甚至于导播台中,在直播的过程当中,推出去一个视频流,可以通过利用zmq的方式动态的改一个logo,或者是加字幕。
chromakey:与colorkey类似,chromakey主要是以 YUV处理为主,colorkey主要以RGB处理为主,二者均只支持抠单色。例如扣绿幕背景时,将其中的代码稍作修改(增加diff值的计算)即可改善抠图的小瑕疵问题。如果是杂色背景,就需要多次抠图或者利用AI的方式,再或者边缘检测等方式。
crop:剪切处理,国内经常看到的视频是16:9/9:16/3:4/4:3的分辨率,但如果把视频发到Twitter上,则看到大多数是以1:1的分辨率显示的,就需要进行crop裁剪处理;除去上述这些Filter以外,我们还使用了boxblur、avgblur等。
3. 进一步图像处理
一些基本的处理功能介绍完毕之后就需要考虑关于性能的问题。
3.1 如何解决FFmpeg某些滤镜处理性能差的问题
![eb1d72ab83094873199eb1e6451b87a0.png](https://i-blog.csdnimg.cn/blog_migrate/587fdf78c3336c3dc1486bcc18b044ca.jpeg)
以overlay为例,早期用overlay等Filter是顺序处理的,是一个简单的单线程处理,我们知道,多数图像都是decode之后的图像,多数都是yuv格式,是一个点一个点打上去的图像,在像素之间没有关联的情况下,可以考虑充分利用多核,进行多线程处理。这是FFmpeg Filter内部的一个优化点。
分布式处理:通过引入timeline的概念,不同的轨道对应各自的timeline,在进行多个轨道切片的时候,通过timeline进行对应匹配。此方法的性能使得可以在数秒至一分钟之内快速处理完成一个1小时长度的视频任务。
OpenGL优化:在用FFmpeg做图像移动,放大效果动画,缩小效果动画,旋转效果动画等图像动态效果时,图像会有抖动感;可以在遇到图像抖动情况通过此方式处理。
使用分布式+FFmpeg+OpenGL,是我本人处理这些问题的基本做法。
3.2 单独使用FFmpeg的一些问题
单独使用FFmpeg tools某些场景下可能会出现性能差、运动不平滑、计算量大、扩展不方便和升级开销大的问题,因此团队开始考虑如下的一些优化,尝试把FFmpeg和OpenGL结合起来,解决性能问题。
3.3 利用FFmpeg+OpenGL方式处理
![30f4a471b8ef8514da909ab1b52eeb74.png](https://i-blog.csdnimg.cn/blog_migrate/dcc62f409d344f59f85efe6f91c35992.jpeg)
上图所示,是利用FFmpeg API +OpenGL API方式处理的流程图。但利用FFmpeg API+OpenGL API方式处理的特点是开发成本高、技能融合模糊,因为开发人员全部都要精通(指同时知晓FFmpeg API的使用,OpenGL API的使用),很难短时间找到这样的合适的开发人员,不太适合创业型小公司,所以团队采用了下面的方式避过这个问题.
3.4 FFmpeg内置OpenGL
![601528ddbd5649fd21437f4dbdf9a1cf.png](https://i-blog.csdnimg.cn/blog_migrate/7d2d99a13c0658bd5be24da4f8edd2f2.jpeg)
采用FFmpeg融合了OpenGL,但并不直接touch OpenGL的优化部分,这部分又精通OpenGL的开发人员之间使用GLSL优化,而FFmpeg开发者只关心怎么把FFmpeg作为一个通用的Filter放入进来,最终是将图像算法处理和音视频编解码处理分开,开发层次会更加清晰,如上图所示为升级优化之后的处理流程。FFmpeg内置OpenGL的方法处理的优势是可以一劳永逸、不同专业的人员做不同专业的事情。
![c4845bb2b14bba6d451ea761f4288ebf.png](https://i-blog.csdnimg.cn/blog_migrate/a93e83f2f5820d00c2362f0494aaf412.jpeg)
专业的人员处理专业的事情之后,我们需要的就是将执行步骤抽象为接口,再利用插件(Plugin)将内容按照接口进行处理。
3.5 FFmpeg与OpenCV的配合
![d9a31fabf28748eb427c80e18e890994.png](https://i-blog.csdnimg.cn/blog_migrate/f8a4a520c467160619a063221ac4d6b4.jpeg)
由于OpenCV的特点,它在3.0版本之后全面拥抱C++,因此FFmpeg只能使用旧版本,但是我们还是需要用一些新版本的OpenCV的功能。面对这种情况,我们只能自己抽象需要的接口,再做成so,先完成导入后再进行处理。
4. AI融合
![41843041f36e8671b86c1e1bb0a8ce65.png](https://i-blog.csdnimg.cn/blog_migrate/7f0ef723ce83c1181e76e6436b0aa801.jpeg)
自2018年起,FFmpeg GSOC项目开始集成CUDNN以及TensorFlow框架,使得它调第三方程序即可实现超分辨率或者直接使用FFmpeg内置的CUDNN模块。需要提及一下,如果直接用FFmpeg内置的DNN,性能很差,甚至会慢到0.001的倍速,它指使用了CPU资源,且没做任何优化,基本上用作算法的验证,不能作为线上实际使用的后端。在FFmpeg的AI框架下,目前还支持了SDR转HDR、去雨点去雾处理以及智能插帧(还在开发中)。
![2decc60fcc6c81f0a7e92773ced438cd.png](https://i-blog.csdnimg.cn/blog_migrate/f51ffbaa2cad371b8ff85ae1d0aa9e07.jpeg)
关于Native DNN的支持,主要处理以上几个接口即可。
![8566da3b77806ab2835fc0238c69c12e.png](https://i-blog.csdnimg.cn/blog_migrate/fce27b1a826553d33d57f2aae9ee370e.jpeg)
目前AI部分需要自己单独进行模型(Model)训练,在以前,FFmpeg使用这些Model的时候需要自己转换Model为PB文件,目前通过处理后直接提供Model文件即可。
5. 总结
![6274a91be7a7314e0e6f055fd4d99683.png](https://i-blog.csdnimg.cn/blog_migrate/e599cae009b68ff66c3292f088038ca6.jpeg)
一个创业团队的初期会按照最简单迅速的方式演进,因此我们团队初期全部使用FFmpeg,在应用过程中,功能快速跑起来时发现了一系列问题,根据经验和团队成员各自擅长的部分进行针对处理,最后在考虑性能时加入了分布式的方法。