乐趣区

腾讯云FFmpeg打造一条完备高效的视频产品链

伴随着飞速增长的视频普及与观看需求,腾讯云技术专家、FFmpeg 决策委员会委员赵军认为,视频行业目前存在一个“技术、需求与现实”的三角博弈,其场景犹如带着镣铐的舞蹈,即需要在超高清晰度、计算能力与网络带宽约束之下寻求平衡。正是基于这样一个三角博弈,腾讯云以“开源、协同”为利器,逐步打磨出一个完备且高效的视频产品链。本文来自于赵军在 LiveVideoStackCon2019 北京站上的精彩分享。

文 / 赵军
整理 / LiveVideoStack

大家好,我是腾讯云的赵军,同时我也是 FFmpeg 决策委员会委员、开源爱好者。在 2018 年成为 FFmpeg maintainer,2019 年入选 FFmpeg 决策委员会(voting committee),具备丰富的基于 Linux 的 Router/Gateway 开发经验,并持续关注 Linux 在网络方面发展。曾开发基于 Linux 的高清 / 标清 H.264/MPEG2 视频解码器及图像处理平台。曾在 Intel DCG/NPG 负责基于 FFmpeg 以及 Intel 平台上的视频编码 / 解码 / 转码、视频后处理、视频分析的硬件加速的工作。目前在腾讯云负责视频云的系统优化相关工作,除去支持公司内部的项目开发以外,也在持续向 FFmpeg 社区提交 patch,同时也倡导引领同事以开放的心态拥抱开源。

今天的演讲将分为明眸、智眸、云剪和开源四个部分来讲解,其中明眸主要针对音视频编解码与画质增强方案,智眸主要涉及智能媒体检索、分析和审核方案,云剪主要提供在线媒体内容生产方案,而开源则是本次演讲中将重点介绍的内容。

音视频发展现状


.png](/img/bVbx2iS)
晰、流畅和品质这三者的博弈,对于视频来说,体育赛事、游戏等领域对直播清晰度要求不断提升,国家政策也在鼓励 4K 和 8K 的增长,这些因素使得超高清晰度视频内容成为音视频技术发展的重要方向,与此同时,人们开始追求更多的趣味性和附加能力,但硬件计算能力或者软件性能并没完全跟上,这使得成像品质以及其他附属能力所需要的计算能力也位于了问题之列;一如既往的,无论是 4G 还是即将到来的 5G 时代,网络的制约在能预计的时间内,依然也还是一个不可忽视的影响因素之一。

  1. 音视频技术 +AI,打造从内容生产、极速高清到视频识别分析全链路产品

1.1 明眸:极速高

提到极速高清就不得不聊聊视频编码,上图从 Codec 和系统工具的角度,以 MPEG 组织为基准描述了发展历史,图片下方是容器格式,做过工程的人都了解,很多时候相比 Codec,容器格式有时会暴露很多的工程问题。图中色块分别代表不同阶段的技术发展,红色部分已经是历史,橙色部分表示过渡,蓝色部分更像是现在和不远的将来的交界。


处理和编码算法动态优化三部分组成,场景识别主要是对场景进行切分,根据场景预设编码模板。其次前置处理主要解决的问题是多次转码带来的副作用,最后在基于以上两部分的前提下做编码算法的动态优化。

当场景识别、前置处理和编码算法动态优化三部分做完之后,我们可以得到一些基本的结论,由于直播客户更在意主观质量,明眸以 VMAF 为目标做开发。简单提及一下,腾讯云在对 VMAF 和 PSNR 做比较时发现,如果 VMAF 的分数在 70 分左右甚至更高,VMAF 的分数会与 PSNR 正相关,倍数关系大概在 2.5- 3 倍之间,反之,我们也发现,PSNR 分数比较高时,VMAF 的分数不一定高,所以我们认为,以 VMAF 为目标的优化也大概率的涵盖了 PSNR 的目标值。明眸可以在相同码率下将 VMAF 评分提升 10+,同 VMAF 分下码率节省可以达到 30% 左右。当然 VMAF 也存在一些问题,比如对小分辨率的适配并不是很好,这可能与 Netflix 自身由点播内容居多,并且片源的质量都非常高有关。

1.2 智眸:智能媒体生产平台

从上图可以看到目前视频 AI 比较通用的流程,视频源从左向右边,解码之后如果要做对象探测会有一个 Scale 和 CSC,如果做 Tracking 会向下走,如果做 ROI coordinates 会向上进行正常的解码。这个流程图看似简单,但在工程中需要各种各样的考量,其中的每一个点都可能会成为潜在的性能瓶颈。

以上是智眸的一些基本能力,包括人像、声音 / 文字、图像以及基本物体的识别、智能分析和审核,它可以根据需求灵活组合,图中也列出了很多的应用场景。

在客户使用和对接时,基本上是以 Rest API 做对接,图中清晰展示了整个流程运行起来的全貌。

以上是腾讯云在视频识别和视频分析中要解决的问题,其中智能拆条需要根据内容或关键人物出现进行拆分,智能集锦应用在体育场景中较多,比如制作进球或得分集锦。

1.3 云剪:助力提升视频生产效能

如果将视频当作一条链路来考虑,可以看到视频从最初上传到制作处理,再到内容管理、传输分发,最后在终端播放,其中制作与处理部分腾讯云存在一些技术缺失,因此腾讯云做了云剪来弥补这部分的功能,主要目的是让用户实现在云端不需要 SDK 就可以对视频数据做处理,这种场景中比较具有代表性的是电竞行业,它的素材可能在 PC 端已经做好,不用在移动端进行处理。

云剪目前也是一个把腾讯云已有的能力打包,用以解决行业痛点的一个综合性质的产品。

  1. 拥抱开源,以开放的心态加速技术升级

2.1 FFmpeg 简介

从事多媒体行业,基本没有人可以完全忽视 FFmpeg 这个开源界中最流行的多媒体库,FFmpeg 库有着多平台的支持,无论是服务器 Linux、移动端 Android、PC 端的 MAC 以及 Windows 都可以使用,使用方式分为 tools 和 C libraries 两种,tools 包括 ffmpeg、ffplay、ffprobe 等,另一种方式则是 C libraries,但 C libraries 场景时候,我们也发现它在某些场景下缺乏一定的灵活性。

2.2 开源与协同

在刚进腾讯云时,大的部门中有 38 个 repo 都叫 FFmpeg,这可能也是业务快速发展过程中所经历的一些痛处。我们开始尝试做一个统一版本,尝试将部门将不同 repo 中,比较有价值的部分提炼出来,构造一个内部完整而统一的 Repo;另一方面,我们认为,既然使用的 FFmpeg 来自开源,我们在它上面的工作成果,也应该让它最终返回到开源社区去。这样,一方面可以使得原来内部的 FFmpeg 库统一,减少内部的重复性工作,另一方面对于社区来说腾讯云及时将 Feature、Bug Fix、性能优化、文档更新和 samples 反馈给它,在这个过程中,也顺势打造了一个非常完整流畅的工作流程,用于支持内部的开发,也用于反馈给开源社区。

2.3 接口与框架

提及接口和框架的问题,首先想到的是上面这段话,简单说来,犹如为院子造墙,什么放在墙外,什么放在墙内,门开在什么地方,还要提防想着把墙推倒的人;在实际的项目中,也有类似的问题,如果项目要和别人合作,首先需要明确两人的职责,这是最容易出问题的部分;具体到 FFmpeg,一方面,它需要解决怎么屏蔽不同的 Os、硬件平台和 Codec 细节,并保持使用过程中能灵活构建 media pipeline 的能力,与此同时,在 AI 大潮中,它也面临着是否需要集成 Deep Learning 框架到 AVFilter 模块的这种现实问题。

2.4 性能之痛

性能在多媒体技术中一直是一个永恒的话题,例如压缩技术在十年间可以提升 50% 的压缩率,但复杂度却会提升 10 倍以上,这对计算能力提出了一个非常大的挑战。我们知道,所有优化的前提是理解算法与数据流向,并且有 Profiling 的数据作为支撑,除了算法上面的提升以外,也需要更好更充分的利用已有的硬件资源。大部分情况下,硬件性能优化是在 CPU 和 GPU 上完成。以 FFmpeg 为例,它的 CPU 优化在上体现在多线程和 SIMD 优化两个方面,在解码过程中使用了基于 Frame 和 Slice 的线程以及更为底层的 SIMD 优化,在 Filter 中只用了基于 Slice 的线程与 SIMD。GPU 一般来说有二个优化方向,一个是专有硬件,比如 Intel GPU 中的 QSV 部分,一块是通用计算加速和 3D 渲染,分别是 CUDA,以及尝试和 CUDA 对抗的 OpenCL,还有历史悠久的 OpenGL 以及它的继任者 Vulkan。

2.4.1 CPU 加速

CPU 的加速中,首先想到的是线程,本质上说,使用线程能力优化是想充分释放多核的能力,目前对于大部分的 PC 来说以 4 线程或 8 线程居多,但对于 Sever 来说核数可能会更多,目前的环境多以 48 或 96 线程为主,因此在不互相影响的前提下调动多核的积极性是 CPU 加速所要解决的首要问题。在 FFmpeg 中,以 AVFilter 为例,他有一个 AVFILTER_FLAG_SLICE_THREADS 的标识,很多实现上,是把一个 Frame 中不相关的数据以行或者列的方式做加速,以我的经验来看,如果程序出现性能问题,首先应该考虑的问题是是否使用了 CPU 的多线程能力。第二种 CPU 加速方式是 SIMD 加速,SIMD 汇编优化形式一般有 intrinsics、inline assembly、hand-written assembly 三种,FFmpeg 汇编优化以第三种为主,这是由于 intrinsics 在封装是有些潜在的性能损失,相同的功能用 intrinsics 和 hand-written assembly 去解决,前者可能会引入一些性能损失;而 inline assembly 的问题在于比较难以跨平台,比如 Linux 和 Windows,而 FFmpeg 的跨平台是它的目标之一。所以,现在 FFmpeg 社区更偏向于 hand-written assembly 方式,另外,大部分的 hand-written assembly 汇编优化其实是以 x264 的汇编优化库为基础做的,并且选择 nasm 为汇编器(不选择 yasm 是由于它没有支持最新的一些 CPU 指令)。

提及了多线程优化,我们也以使用者的角度看着,使用 FFmpeg API 的时候,如何设置线程。对于 FFmpeg 来说,大部分的情况下可能并未考虑在高负载 / 重耦合场景下运行的情况,FFmpeg 在解码时的默认策略是根据 CPU 的核数创建线程,目前大部分的 PC 设备都是四核八线程的配置,但一个典型的数据中心的 Server 有 48 核 96 线程,但解码器实际上并没法同时使用这么多的核,这种情况下,需要自己控制解码线程,而非使用 FFmpeg 的默认策略,我们也遇到过使用 FFmpeg API 时候,默认创建超过 1200 个线程的问题。第三个是 BUG 的问题,FFmpeg 集成时很多时候只在 PC 端测试过,并未在拥有这么多核的服务器上测试,使得 FFmpeg 的 VP9encoder 当时甚至会在多核服器上 crash,种种事情表明,在多核服务器下使用 FFmpeg,需要在多线程上做更细致的控制,而仅仅只使用其默认线程策略。另外,还有一点要提及,线程并不只是影响性能,它也会影响图像质量,我们也发现,在编码时候,随着编码器使用的线程数目的增加,其 VMAF 分数可能会降低。在服务器端,使用 FFmpeg 这类框架时候,如何在保证性能以及图像质量的前提下,怎么更好的控制线程(使用 CPU 的计算能力),是个非常有趣的问题。

在性能优化过程中,SIMD 优化也面临着一些挑战,一是在使用 SIMD 优化时需要将算法改造成适合 SIMD 的算法,这并不总是一件容易的事情,其次需要考虑不同硬件之间的移植性。另外,对于 SIMD 一般都有内容对齐的需求,且算法上要尽量避免分支使得数据可以流化,同时,算法上的一些操作并不都被 SIMD 指令支持(相较而言 x86 的 SIMD 指令要比 arm 更为丰富一些);另外,还有考虑不同硬件之间浮点算法的精确性,种种挑战,使得 SIMD 的优化的使用上并不特别的便利。

2.4.2 GPU 优化

当时我基于英特尔的 GPU 做整个转码链路的优化,Codec 解码主要有两套 plugins,一套是基于 MSDK,类似 FFmpeg 集成 x264 后依赖第三方去做解码。第二套思路是基于 VAAPI 的 interface 去做,使得整个硬件加速 Codec 是 FFmpeg 自身的一部分。除了做 Codec 的加速以外,团队同时还用 OpenCL 做了一些 AVFiltrer 的优化,这两种优化之间各有优势。顺带提及一句,即使 GPU 已经加速,在 API 的角度依然无法判断是否使用了 GPU 资源,这个问题目前只能归结到 FFmpeg API 的设计缺陷。另外,关于更多 GPU 的优化问题,可以参考我之前的一些文章(FFmpeg 在 Intel GPU 上的硬件加速与优化)。

退出移动版