我们可以通过下面这些指标来反映播放卡顿的情况:
卡顿率,在一次播放中发生过卡顿的播放次数在总的播放次数中的占比。
平均卡顿时长,用户观看视频发生卡顿的总时长与总的卡顿次数的比值。
百秒卡顿次数,统计下的播放 100s 视频时会出现多少次的卡顿,计算公式:sum(卡顿次数) / sum(播放时长(单位 s)) * 100。
百秒卡顿时长(毫秒):统计下的播放 100s 视频时会出现多少 ms 的卡顿时长是,计算公式:sum(卡顿时长(单位 ms)) / sum(播放时长(单位 s)) * 100。
当然,卡顿率、平均卡顿时长和百秒卡顿次数仍然可以作为辅助的指标来关注。
优化播放卡顿大致上可以分为几个大方向:
码率调控
码率适配
H.265 降码率
软编降码率
播放器策略
推流端策略
CDN 策略
码率调控
码率适配
下面是一些码率调控的措施:
H.265 推流:相对 H.264 降低推流码率。
H.265 软解:提高 H.265 低码率流的覆盖率。
推流 540P:相对 720P 降低推流码率。
OBS 限制推流码率:降低 OBS 推流码率。
推流软编:软编相对硬编降低推流码率。
LAS/播控策略:自适应码率选择,在用户卡顿时降低播放码率。
虽然有了上面这些码率调控的措施,但是通常我们也不能对用户一刀切,对所有的用户都用同样的码率调控方式。比如,从拉流端来看,对于使用 WIFI 网速稳定且高速的用户,我们可以播放高码率高分辨率的流;对于使用 4G 网速容易抖动的用户,我们可以播放低码率低分辨率的流。从推流端来看,我们可以计算直播间的 ACU(直播间用户总观看时长/直播间总推流时长)来评估直播间的热度及影响力,对于大主播我们可以推码率高一点的流来提升画质体验,对于数据较多而观众分散的小主播我们则可以适当降低推流码率。
H.265 降码率
H.265 相对于 H.264 压缩效率更高,在保持一定画质的情况下使用 H.265 替换 H.264 可以降低码率。
软编降码率
软编相对于硬编有更好的灵活性,在有些设备上通过配置合适的编码参数,可以在保持一定画质的前提下比硬编使用更少的码率。
播放器策略
使用音频缓冲区水位线来驱动起播
在直播流中,我们会发现有一些视频 AVPacket 的 duration 字段是空值的,但是它实际上是有时长的,如果在缓冲数据时,我们用视频水位线来驱动起播,那就要卡顿等待更长的时间才能起播。比如:我们设置的是应该等待 100ms 的视频数据才开始起播,由于有的视频 AVPacket 的时长是空值,那么累积到 100ms 时长的视频数据时,对应的实际视频时长其实是大于 100ms 的,这就意味着卡顿了比预期更久的时间才起播,这样就会造成百秒卡顿时长被拉高。
对于这种情况,我们发现音频 AVPacket 的 duration 字段值是正常的,所以可以使用音频缓冲区水位线来驱动起播,可以保证起播前的缓冲造成的卡顿时长是更符合预期的。
此外,还需要从直播流链路定位视频 AVPacket 的 duration 字段是空值的原因,解决这个问题后,使用视频缓冲区水位线来驱动起播也是可以的。
动态缓冲策略
当播放器发生卡顿后,先暂停播放流程,停止数据消耗,同时去等待下载线程加载更多的数据到缓冲区后再启动播放,从而降低后续发生卡顿的概率。这里的暂停时长应该是多久,可以通过设计更细致的策略来决定,这里的策略跟我们的目标有关:是减少卡顿次数更重要,还是减少卡顿时长更重要。
这里介绍一种策略:三级缓冲水位策略。
这里的水位对应的是视频缓冲时长或者音频缓冲时长。
比如,三级缓冲水位可以设置为:500ms、1000ms、5000ms。
第一级缓冲水位指的是播放器第一次加载多少视频数据后开始播放。这个值通常设置的比较低,这样可以加快首次播放启动的速度。比如上面设置的是 500ms。
第二级缓冲水位指的是播放器发生一次卡顿后,要加载多少视频数据后开始播放。比如上面设置的是 1000ms。
第三级缓冲水位指的是播放器在发生卡顿后,最多要加载多少视频数据后开始播放。比如上面设置的是 5000ms。
在第二级和第三级缓冲水位之间,可以有一个逐步升级策略。比如:第一次卡顿后,缓冲 1000ms 的视频数据后开始播放;第二次卡顿后,缓冲 2 * 1000ms = 2000ms 的视频数据后开始播放;第三次卡顿后,缓冲 2 * 2000ms = 4000ms 的视频数据后开始播放;第四次卡顿后,缓冲 MIN(2 * 4000ms = 8000ms, 5000ms) = 5000ms 的视频数据后开始播放;以后的卡顿都缓冲 5000ms 的视频数据后再开始播放。
低缓冲时低倍速播放
当播放器缓冲区的数据累积的较多时,对应的播放延时会比较大,这时候可以加速播放来加快对缓冲区数据的消耗从而降低延时;反之,当播放器缓冲区剩余的数据较少时,很有可能由于网络原因造成数据下载的速度跟不上数据消耗的速度而发生卡顿,这时候可以低速播放来减慢对缓冲区数据的消耗从而防止卡顿。
短视频缓存和预加载
短视频的卡顿大部分是由于网络原因导致的,加载本地数据比加载网络数据要更可靠,所以可以从缓存的角度来优化短视频的卡顿。
对于短视频的卡顿,初次播放的视频可以对视频进行预加载来优化视频播放卡顿。
重复播放的视频可以通过实现视频边下边播的缓存能力,并提升缓存命中率来优化。
设置卡顿超时
在实际的数据分析时,我们会发现有时候用户开始卡顿,并且持续了很长时间也未恢复。这种情况可能是由于网络状况较差,虽然数据传输速度很慢,但是连接一直也没有断开,所以不会触发播放器的报错,播放器由于累积不到足够数据,也无法启动播放,所以导致卡顿时长很久。
这种情况,我们可以设置卡顿超时时长,当发现卡顿持续超过一定时长后,就上报事件到业务层,业务可以重新连接,防止卡顿过久。
推流端
支持退后台继续推流
在主播中,观看端的有一些卡顿是由于主播的行为引起的,比如主播使用手机推流的时候有退后台的操作,这时候推流断流,相当于生产侧的数据断掉了,拉流端没有数据自然会卡顿。对于这种情况,可以支持退后台继续推流,不过有几点需要注意:
1)退后台如果继续采集音频可能涉及到隐私问题。对于这个问题,可以退后台停止采集,但是保持推静音音频数据。当然,如果产品上可以退后台继续采集音频,就使用系统的能力持续采集就好了。
2)退后台无法继续采集视频,这时候如果不推视频数据,那么可能会引起 CDN 和播放器的不兼容的问题。因为有的 CDN 和播放器是需要检查视频数据,以及根据视频数据做一些功能和策略的。对于这个问题,可以推退后台前的最后一帧画面,并且适当降低帧率来降低推流的码率。
3)由于退后台时间较长后,App 的网络请求可能被系统中断,甚至 App 可能被杀死。对于这个问题,可以尝试一些后台保活的方案,比如 iOS 可以在退后台后播放静音音频来保活。
CDN 策略
营商效应和百秒卡顿时长的关系
现在的运营商纷纷推出无限流量但超过特定值会限速的套餐。这样会造成使用流量套餐的观看视频或直播的用户从月初到月末卡顿概率越来越高,跟卡顿相关的数据指标也就越来越差。
CDN 的吐数据策略
在 CDN 服务端来控制下发视频数据的带宽和速度。比如,在拉取直播流时,服务端将以数倍于平时带宽的速度下发前面缓存的若干时长的数据给客户端,这样播放器在开播时能较快的拉取比较充足的数据,防止开播卡顿。
推流断开后的 CDN 状态优化
有的 CDN 厂商在会在拉流的节点缓存直播流的最后一个或多个 GOP,同时会配置这个缓存的有效时长(即在一定时长内没有请求来拉取这段数据,则超时清空这个缓存)。
这样一来,即使推流已经断开,拉流端也会拉到 CDN 缓存的数据开始播放,但是由于这段数据有限,当消费完后,CDN 的返回的 HTTP 状态码就有比较大的影响了。
如果 CDN 返回 404 等报错状态,播放器就会报错,此次播放终止。当然,如果客户端对拉流报错做了重试策略,这样就会不停的重试再去拉同一份缓存数据。这种情况,通常不会影响卡顿,但是会造成播放成功率降低。
如果 CDN 返回 200,那么播放器就不会报错,但是播放器的读数据线程会因为读不到数据进入加载状态而计入卡顿,这种情况就会造成百秒卡顿时长上升了。