直播播放延时,指的是从主播推流一帧画面到用户观看到这帧画面之间的时间差。字节跳动曾经提供过一份数据来说明直播延时对用户的影响:对比直播延时在 15s 和 5s 时,用户观看延时更低的直播流,观看时长会增长 0.8% 以上,同时,用户付费渗透增长 1.4%,进房转化率增长 1.2%。
要统计直播播放延时,可以在推流端编码视频时增加 SEI 信息,其中可以添加时间戳信息。在播放时,将 SEI 中的时间戳解出来,同时获取本地的时间戳,这两个时间戳的差值即直播播放延时。
这里有一个问题:这两个时间戳如果是从本地取得,则可能由于设备对时问题存在误差。这种情况下可以从服务端的 NTP 服务来取时间。
1、播放策略
1.1、高缓冲高倍速播放
当播放器缓冲区的数据累积的较多时,对应的播放延时会比较大,这时候可以加速播放来加快对缓冲区数据的消耗从而降低延时;反之,当播放器缓冲区剩余的数据较少时,很有可能由于网络原因造成数据下载的速度跟不上数据消耗的速度而发生卡顿,这时候可以低速播放来减慢对缓冲区数据的消耗从而防止卡顿。
下图示例了一种倍速播放策略:
倍速播放策略
max-play-rate
和min-play-rate
表示播放器的最大播放速率和最低播放速率。通常来讲,播放速率过低或过高会影响视频观看的体验。一般来讲,[0.9, 1.2]
是一个可以接受的区间,具体情况可以测试确定。- 当缓存时长在
[0, normal-low-cache)
区间时,播放器使用慢速播放。其中,当缓存时长在[0, min-cache]
区间时,播放器使用设定的最低播放速率min-play-rate
进行播放。 - 当缓存时长在
[normal-low-cache, normal-high-cache]
区间时,播放器正常播放,播放速率 1.0。 - 当缓存时长在
(normal-high-cache, limit-cache]
区间时,播放器使用快速播放。其中,当缓存时长在[max-cache, limit-cache]
区间时,播放器使用设定的最高播放速率max-play-rate
进行播放。limit-cache
是播放器缓冲区大小的上限。
1.2、丢帧
当缓冲区的累积的数据已经非常多(通常是发生卡顿后播放器等待数据加载时间较长造成),通过倍速播放可能需要较长的时间才能消耗掉累积起来的延时,这时候如果要快速的消耗掉这个延时,可以直接丢掉缓冲区的音视频帧。
丢帧策略可以配合倍速播放来做,接着上面的策略:
- 当缓存时长在
[drop-cache, limit-cache]
区间时,触发播放器的丢帧策略。 - 丢帧会将缓存时长从
drop-cache
丢到drop-to-cache
。drop-to-cache
一般可以设定在[normal-low-cache, normal-high-cache]
区间,这样丢帧后就能保持正常速度进行播放。
2、CDN 策略
2.1、CDN 吐数据控制
在直播中,CDN 的基本原则是从一个 GOP 开始吐数据,因为 GOP 是以 I 帧开始,这样才能保证播放器拿到数据就可以解码出画面,防止出现解码错误引起花屏。
这里示例一种快手使用的 CDN 吐数据策略,该策略总的来说遵循三个原则:
- 1、下发数据长度不能超过快手拉流端接受缓冲区长度。
- 2、必须从一个 GOP(Group of Pictures)的开始下发。
- 3、在不违背前面两点的情况下,下发尽可能多的数据。
GOP 吐数据策略
上图是两个根据服务端缓存的不同 GOP 结构,决定下发数据策略的实际 case,假设快手拉流端接收缓冲区长度是 5 秒。
第一个例子,如果从第一个 GOP 开始下发数据,总数据长度 6.5s,大于快手接受缓冲区长度,所以只能从第二个 GOP 开始下发,总数据长度是 4.5s,在缓冲区长度的限制下,做到了下发数据长度最大。
第二个例子,如果从第二个 GOP 的开始下发,数据长度已经达到 6s,那么只能从最后一个 GOP 的开始下发,数据长度 3s,在接受缓冲区长度限制范围内。
3、传输协议优化
3.1、基于 WebRTC 实现直播推拉流
目前直播场景大多是基于 RTMP 推流、HTTP-FLV/HLS 拉流的技术方案,在不考虑网络延时的情况下都会产生秒级延时。RTMP 推流主要基于 TCP 传输,TCP 为了保证传输质量,因此会产生很多 ACK,在网络不好的情况下会产生很多重传包,所以延时自然就相对较高了。通过调整 CDN 缓冲和吐数据策略、播放器缓冲区策略,可以在一定程度上降低延时,但最终还是会受限于传输协议的制约,无法将延时降低到更低的水平。这时候我们就可以考虑基于 WebRTC 来实现更低延时的直播推拉流了。
WebRTC 传输是基于 RTP 和 RTCP 实现,而 RTP/RTCP 底层是基于 UDP 协议进行传输,UDP 协议的头小,而且不用保证可靠性,所以传输延时通常更低。WebRTC 的重传策略是基于 NACK 完成,并且可以进行调整,从而有比较大的可控空间。