如果在哔哩哔哩播放视频的过程中,出现了比较明显的卡顿,播放器的左下角会出现一个 Toast,提示“丢帧严重,已自动关闭防挡弹幕”。那么,播放器是如何检测出当前的丢帧是否严重的呢?
通过阅读哔哩哔哩播放器的部分源码,不难发现核心实现如下:
i.prototype.autoVisible = function() {
var i = this;
i.danmakuMask.maskIsShow() && (i.dropFramesTimer = setTimeout((() => {
// 默认检测间隔是 600ms
i.dropFramesTime = 600;
// 当前总丢失帧数
var e = i.droppedFrameCount();
// i.dropFrames 是上次检查时总丢失帧数
// 丢失超过 14 帧就认为丢帧严重
if (e - i.dropFrames > 14)
return i.player.toast.addTopHinter("丢帧严重,已自动关闭防挡弹幕", 2e3),
i.maskDanmaku.value(!1),
void i.danmakuMask.setting("dmask", !1);
// 更新总丢失帧数
i.dropFrames = e,
i.autoVisible()
}
), i.dropFramesTime))
}
,
i.prototype.droppedFrameCount = function() {
return this.player.video && this.player.video.webkitDroppedFrameCount || 0
}
简单来说,代码判断了 600 毫秒内,是否有超过 14 帧丢失,如果有的话,就认为丢帧严重,需要做一些计算的降级。而这里判断丢帧数量的核心代码,是获取了 video
上的 webkitDroppedFrameCount
属性。因为是 webkit
开头,可以知道这个是一个非标准的 API。
通过查询 MDN 相关文档,不难发现,在正式的标准(草稿阶段)中,对应的应该是 VideoPlaybackQuality
中的 droppedVideoFrames
属性。
要获取当前 video 的丢失情况,可以使用下面的代码:
const quality = video.getVideoPlaybackQuality();
const droppedVideoFrames = quality.droppedVideoFrames;
这里 droppedVideoFrames
和 webkitDroppedFrameCount
是一致的。
如果想知道丢帧的百分比,可以配合 totalVideoFrames
一起判断:
const quality = video.getVideoPlaybackQuality();
const percent = quality.droppedVideoFrames / quality.totalVideoFrames;
注:视频解码前后都有可能发生丢帧。只要浏览器判断认为当前帧已经不可能在正确的时间被播放,就会触发丢帧。