简述追帧的原理和追帧在直播同传的中的使用
关于直播和同传经常能看到一些源于想象的传言,类似:同传man会和主播单独连麦,所以会比一般观众更早看到直播;主播在直播中会开延迟推流,所以弹幕会需要10多秒才会上屏。类似传言本质上来源于对直播原理的不了解,所以这里我想简单的叙述下直播的一些基本机制,以及利用了这些机制的追帧脚本能实现的效果。
因为是简述所以专栏完全根据我个人的记忆进行写作,不保证完全准确。
直播系统
无关乎具体的平台,一个直播系统根本上就是要满足这么一个需求:利用计算机网络,将实时生成的音视频流从一个人分发给许多人。而这个需求具体来说至少包含了两个问题,第一是如果让一个实时生成的音视频流能像视频文件一样,让包括浏览器在内的客户端进行实时下载。第二是如何应对互联网连接中的丢包延迟等不稳定因素。
分发实时的音视频流
目前B站使用了两套推流协议,一套是HTTP-FLV,另一套是HLS,来实现直播的推流。
HTTP-FLV大致上可以理解为服务器虚拟了一个flv的视频文件,而这个flv里的内容并不是事先保存的视频,而是直播的视频流。服务器把接收到的直播推流按flv格式实时封装,再按照直播流生成的速度向浏览器发送flv“文件”,而浏览器也按照相同的速度播放这个“文件”,这样一来,浏览器就能像播放单个flv视频文件一样播放被包装成flv视频的直播数据。HTTP-FLV最大的优势就在于“实时”,只要服务器收到了一帧数据,理论上就可以立刻把这一帧数据封装进flv发送出去。
Bilibili早年从Flash时代就一直使用的FLV格式进行视频播放。后来Flash逐渐废弃,网页逐渐转向HTML5的时候,Bilibili推出了flv.js,实现了HTML5的FLV播放。不过Bilibili毕竟不是一个技术导向平台,现在也在逐渐转向YouTube等使用的DASH和HLS。
HLS是由反Flash先锋苹果提出的一套协议。HLS的原理就是服务器收到直播流之后,先在服务器上保存很多很短的视频片段,然后把这些视频片段的网址放进一个m3u8的文本文件里。浏览器则反复的获取最新的m3u8的文本文件,然后根据m3u8中的网址下载新的片段,再按顺序进行播放。HLS因为将直播提前在服务器上分割成了大量的视频片段,所以相对HTTP-FLV来说更稳定一些,但是因为需要缓存片段再分发,延迟会明显变高。
B站主要使用以fMp4为主的HLS,可以实现每个分片长度在1秒。但播放器必须下载完一个分片才能播放(而HTTP-FLV可以看作是逐帧下载),在小样本测试中,原画的HLS-fMp4延迟仍明显高于二压的HTTP-FLV。实际情况下,可以通过打开两个浏览器标签,分别启用/禁用“强制flv+avc”选项,切换一次画质后比较延迟。


(秒数是我个人目测的,不是实际测量,仅提供一个量级的参考)
对于同传追帧的应用场景来说,HTTP-FLV是一套足够稳定的协议,所以应当尽可能的选取HTTP-FLV的推流,并避免使用二压的推流。
应对网络的丢包延迟
通过互联网进行传输会不可避免地出现网络的丢包延迟等不稳定因素,虽然不稳定是偶尔的,但是一个合格的直播系统必须予以考虑。对于网上会议、语音连麦这种高度强调实时性的场景,解决方案就是降低音画质,以及部分跳过卡顿的部分的音视频。而对于视频网站的直播,则可以选择用数秒的缓冲延迟来保证视频的质量和流畅。Bilibili、Youtube在内的直播平台,都可以从右键打开统计菜单,查看当前的缓冲时间。
换言之,当播放器接收到直播的数据的时候,并不会立刻播放这部分数据,而是会将输入放入直播的缓冲里,再进行播放。这样的好处就是,即便有网络波动,导致2-3秒没收到数据,播放器也不会出现卡顿;等网络波动消失,播放器就可以从服务器拿到这期间的数据,补回消耗的缓冲长度,以应对下一次的网络波动。
多一秒缓冲,就能多应对一秒的网络波动,但相应的也就多了一秒的观看延迟。Bilibili网页端的播放器会缓冲4-6秒左右的直播,但事实上大部分情况只要有1秒左右的缓冲就可以保证网页端的流畅播放。所以让播放器提前播放出一部分缓冲的直播,削减缓冲的长度,就可以明显减少因为本地播放器缓冲带来的延迟。

具体来说,就是追帧脚本可以预设一个目标的缓冲长度,当播放器的缓冲长度大于目标长度时,就提高播放器的播放速度,这样播放比直播快,播放器的缓冲就会不断被消耗,缓冲带来的延迟也会不断减少,直至播放器的缓冲长度达到目标长度。
从追帧的视角来看直播延迟
当开启了缓冲的追帧,并使用HTTP-FLV的原画推流时(非二压“原画”/HEVC),实际就足以实现~1秒级的延迟。评估总延迟的方式很简单:发送一条弹幕,然后估测这条弹幕出现在直播画面上的时间。这一过程的延迟包括了:1. 发送弹幕到服务器的延迟,2. 服务器到主播弹幕姬的延迟,3. 主播推流的总延迟(编码推流至服务器,服务器推流到播放器,播放器缓冲)。当采用了合适的追帧时,完全可以达到发送的弹幕几乎实时上屏的效果。
于是我们就可以从纯技术的角度来回答,为什么“同传man不是和主播单独连麦”:因为开启了追帧就已经是实时的音视频了,所谓的单独连麦并不会明显减少延迟。同传追帧的核心是开启了追帧后和其他观众的延迟差距,而无关乎和主播的绝对延迟。

一个常见的疑惑是为什么同传的弹幕会比主播的语音先出现。一种带有节目效果的解释是主播是照着同传的弹幕念的。但是只要知道了直播中的延迟来源就不难理解。在开启追帧并使用HTTP-FLV的原画后,相对于一般的观众,同传man可以同时减少推流(2-4秒)和缓冲(3-8秒)带来的延迟。对于不长的语句,同传man完全可以在延迟差的时间内,听完整句,并完成翻译和发送弹幕。也正因为延迟的多少是推流+缓冲决定的,不同观众的延迟是各不相同的,所以同一条弹幕,可能在部分人看来比语音先出现,但在其他人看来则是比语音晚出现。