微云日上传视频数达到140万个,每日播放视频次数达到1000w次,在线播放视频成为强烈的需求。但是在PC WEB、H5的播放体验并不好,原因有两个:
(1)播放组件支持的视频格式少,仅支持MP4、MOV等H.264编码的视频;
(2)部分视频(特别是UGC视频)码率过大,导致播放卡顿。
所以我们决定对微云的视频转码,提供流畅的视频在线播放体验。
原视频存放在架平仓库,转码视频时需要先下载视频到本地,再对下载好的视频转码得到新视频,最后再把新视频上传到云端。简单的转码流程如下:
为了能在各个客户端上流畅地播放视频,我们需要把原视频转码成H.264/AAC编码、低码率的MP4视频。视频文件主要由视频流和音频流等信息组成,其中视频流和音频流有着不同的编码格式。转码的过程如下图,先解封视频,分别提取视频流和音频流,把视频流转为H.264格式,把音频流转为AAC格式,然后再封装起来得到新视频。
我们这里选择FFmpeg作为视频转码组件。因为FFmpeg是一个成熟的开源、跨平台组件,支持多种格式的音视频转码,并提供了一套录制、转换以及流化音视频的完整解决方案。
3.1 哪些视频需要转码?
微云的存量视频达到40P,如果都转码这些视频,显然不太现实,也没有必要,因为存量视频的点击播放率较低,投入产出比太低。所以我们经过分析,发现用户一般是分享视频的场景下,更多的点击播放视频。好钢用在刀刃上,花钱花在跟节眼上,在机器资源有限的情况下,所以我们决定对分享的视频再进行转码。
3.2 转码后的新视频存在哪里?
原视频转码后会产生新视频,新视频的存放应该满足这几个条件:
(1)用户不感知。由于是后台自动转码,所以用户不应该感知到有新视频的存在,否则会引起用户误会,导致用户投诉或新视频被删。
(2)并发上传视频不冲突。由于多个视频在同时转码,所以上传新视频时相当于并发写操作,这里需要做到并发写无冲突。
(3)下载速度稳定。
经过讨论,我们最后选择了腾讯云COS存储系统来存放新视频。因为新视频不能存放在原视频的用户的目录下,否则会用户会感知到;也不能存在公共的FTN账号上,因为FTN底层做了对写排队保护,如果并发上传过多,容易导致队列满而失败。而COS系统满足上面三个条件,支持单目录并发写,不容易冲突。
3.3 下载、转码、上传操作流水线化
前面提到,转码视频时需要先下载视频到本地,再对下载好的视频转码得到新视频,最后再把新视频上传到云端。
举个例子,假如有A、B两个视频需要转码。在同步转码模式下,下载模块下载完原视频A的数据后,转码模块拿到视频A的数据开始转码,这时候下载模块就空闲,直到上传模块把视频上传到COS、结束视频A的完整转码过程,下载模块才会开始下一个转码任务:下载视频B的数据。在整个转码过程中,每个模块都在等待其他两个模块的操作完成而空闲着,这样的转码效率低下,白白浪费了很多时间。
显而易见,这三个模块都是后者依赖前者的输出结果,也就是说,一旦前者输出结果后,后续的模块的操作和前者就再无关系。根据这个特点,我们在每个模块之前加入队列,把下载、转码、上传操作异步化,各个模块之间不再同步等待转码结束,而是在完成本模块的任务后,继续从队列里面取下一个任务。这样就实现了转码的流水线化,极大地提高转码效率。简单流程如下:
这里我们使用Gearman组件来实现队列功能,Gearman是一个强大的分布式任务管理组件。详细介绍可以参见Gearman官网,这里先不展开详细介绍了。
3.4 总体架构
经过前面的推论,我们设计出了视频云播转码的总体架构。如下:
(1)由分享场景触发视频转码,云播逻辑server把待转码视频放到下载队列中,等待转码。
(2)用户播放已转码视频时,从公网直连COS边下边播,实现云播功能。
目前云播转码模块已经部署到外网环境,其中使用了40台V8机器来转码视频,目前已hold住业务分享场景的日常转码、云播需求。
由于资源有限,我们的转码方案只满足了分享场景的转码需求,并没有完成覆盖业务的所有场景。上述转码方案其实也是属于预转码,并不能保证所有转码过的视频都会被播放。后续我们计划实现实时转码功能,通过用户播放操作触发转码,这样能最大化利用机器资源,做到百分百覆盖云播场景。