随着云剪辑、云导播、音视频生产在线协作的兴起, 生产环境下的音视频处理越发为人所关注。音视频处理在生产环境下,对控制精准性有着更高的要求。从服务端到客户端,精准的时间控制、画面控制都是生产环境音视频和分发环境下音视频处理的重要区别。服务端与客户端的协同上,容易产生微小的差异。
文 / 姜雨晴
整理 / LiveVideoStack
大家好,我叫姜雨晴,是Media Track音视频研发负责人,之前就职于熊猫直播,一直从事前端的播放器,后来有幸去了字节跳动,最近在参与和熊猫直播的创业项目。这个项目主要是关于生产环境下的解决方案,我们不再做传统2C的视频分发解决方案,而是针对于视频的创作者的协同和合作进行一个解决方案,这和传统2C的观看端有很多不一样的地方。
本次内容主要分为四个部分:一是架构;二是工作流;三是一致性;四是扩展性。
首先,了解一下我们的产品,在网页端和小程序端会有修改和批注的功能,也就是我们最早上线这版的功能。如果要做一个生产环境下的解决方案,我个人比较倾向于先了解生产环境下,用户如何去使用这款产品。
因为我个人比较喜欢使用一些剪辑软件去剪辑一些片子。这张图是我个人剪辑时的状态,首先需要精确到帧的控制,而且每一段的时间戳都非常准确,要清楚哪一段插进的内容,如要清楚知道图中字幕的位置等要精确到哪一个像素。尤其在网络的视频分发过程中,并不能保证这样的一致性。平时在观看时是不需要保证到帧的,这就给我们的服务带来了很大的挑战。
我们现在最核心的两个业务是:媒体转码和视频标注和截图。首先,媒体转码是网络分发,我们所看到的东西不可能用源流,因为源流可能特别大,有可能在网页或小程序端解码不了,这就涉及到转码,所以转码流和源流是否保持一致就成了很大的问题。其次,视频标注和截图也会在一致性上产生差异。
这张图是我们现在的Media Track整个的架构,整个命名方式延续了熊猫的命名方式,所有的项目都采用英雄联盟的英雄为项目名称。现在最主要的两个项目是:一是对用户可见的Web端的Sona和小程序的Neeko,它们的背后是第二层长连接Riven和API的Kayn这两个部分,也就是和前端进行交互的这层,它们的灵活性会比较高,并根据产品的需求加接口。
最后这部分是微服务集群,重点是音视频服务Ahri,对于系统内的其他服务而言,Ahri只是音视频服务,与其他的微服务没有任何区别。
Ahri是所有媒体相关操作的微服务集合,包括媒体转码、文件格式矫正、媒体信息的获取、截图、音频waveform抽样、标注点绘制、图片处理等一系列工作。Ahri对外仅是个普通的微服务。对内是微服务组,这也是它命名的原因。Ahri是一个九尾妖狐,它可以将能量存储在火球中并释放出去,它的九条尾巴就像对内的微服务一样,都是它不可或缺的部分。
这张图展示了Ahri的架构,Ahri对外的服务就是Ahri网关,并没有自己实际的操作,它所有的操作都是向内部的微服务创建任务并汇总这些任务,但转码还是采用云厂商的转码。
我们两个比较重要的工作流:一是调用工作流,Ahri先要知道需要做什么再进行工作,利用Magic number判断文件类型。因为我们的系统允许用户传任何文件,这样会把文件的扩展名改掉,或者前端无法判断它是否是一个音视频文件。这时Ahri会再进行判断,如果是一个视频文件会通知其他服务矫正它,并进入真正的媒体处理的流程。
媒体处理流程也会做一个矫正,实际并不想同一个文件处理多次。当多个用户上传同一个文件时,需要做hash。当事件任务完成或者状态更新时,就进行广播消息。
如果没有媒体信息、获取媒体信息矫正。截图标记会遇到一些坑点:一是时间戳找齐;二是画图标记找齐。
时间一致性,传统上,现在可以看到的视频片断如图所示,首先是格式上的时间零点,然后是音频首帧时间点、视频首帧时间点,最后是标注点。
图中上部分是服务器的原片,因为用户比较专业,大部分上传的片子都是如图所示,也就是音频时间原点和视频时间原点几乎是一致的,甚至有些在上面打了时间码。
但我们现在所用的转码服务经常会把转码流变成图中下部分,也就是它们起始时间并不一致。所以在找一帧画面时是需要基准点的,一般基准点是视频图像的首帧,也就是start time,然后标记时间戳是以视频时间的start time基准点去找。
我以前是做网页播放器出身,网页播放器会对start time进行处理。因为依据图中的转码流处理,如果starttime是4秒钟,首屏时间就要等4秒之久,所以一般会计算一个Base-Time,也就是把音频和视频的starttime小的值作为基准时间点,作为时间零点,之后的每一帧都会减去这个时间点。像这种时间点的控制就会造成真正的start time其实并不是首帧的PTS,这时MSE Buffer就需要再一次找齐时间点。
这其中会有一个坑点,现在的时间点在浏览器上有可能会被清除掉,因为浏览器有一个机制是播放一定时间时会把前面的缓存清除,以节省内存空间,但这时候的start time点就不准了。所以在取视频的时间点时要保证是第一个片段塞进MSR Buffer。
根据图中所展示的处理,目的是加速起播时间,其次是尽量保留展现数据。
因为小程序播放器是小程序的底层,它的起始时间点是视频的首帧,这是利用用户打好时间戳的视频,根据视频的转码流和源流PTS对出来的,小程序的基准时间点为0。
小程序以视频为基准播放,无需特殊处理。小程序另外一个坑是小程序为了保证它的消化不会过大,会保持timeupdate为250ms,需要精确到帧,必须自制定时器。但需要注意,定时器过多,会导致程序崩溃,建议做全局定时器。
这部分是关于画面的定位,这比时间上的一致性效果要好得多,图中展示的是一个特殊情况,图中圆点是基准点,内部方形是实际画面,外部是播放框。以实际画面为准,将它的宽和高定一个百分比作为标记点。即使这个视频被处理了,也可以根据相对标点找到实际位置。
这部分介绍我们系统的扩展性,图中是Ahri整个架构图,首先Ahri会创建work flow并下发任务,这些任务可能会在Ahri自己的服务上进行,也可能在云厂商服务上进行。如果云厂商质量达不到我们的精度,需要做自己的服务时,可以直接在workflow这一层做迁移,如果需要加比如第三方转码时,可以横向扩展我们的work flow。