超出缓冲配额

Joe Medley
Joe Medley

如果您使用了 Media Source Extensions (MSE),您需要做的一件事就是 超满缓冲区出现这种情况时 即获取所谓的 QuotaExceededError。在本文中,我将介绍 处理方式

什么是 QuotaExceededError?

基本上,如果您尝试添加太多数据,就会得到 QuotaExceededError 添加到 SourceBuffer 对象中。(向父级添加更多 SourceBuffer 对象 MediaSource 元素也会抛出此错误。这不在 本文。)如果 SourceBuffer 包含太多数据,则调用 SourceBuffer.appendBuffer() 会在 Chrome 中触发以下消息 控制台窗口。

配额控制台错误。

关于此功能,有几点需要注意。首先,请注意 邮件中没有 QuotaExceededError 出现。要查看该信息,请将 在断点处设置断点,以便捕获错误并在 监视或范围窗口。我在下面演示了这些方法。

配额监控窗口。

其次,没有确切的方法来了解 SourceBuffer

在其他浏览器中的行为

在撰写本文时,Safari 在许多情况下都不会抛出 QuotaExceededError, 。而是使用两步算法来移除帧,如果 有足够的空间来处理 appendBuffer()。首先,它会释放帧 。接下来, 将 30 秒的帧从时长回放至接近 30 秒 在 currentTime 秒钟后。如需了解详情,请参阅 2014 年以来的 Webkit 变更集

幸运的是,Chrome、Edge 和 Firefox 确实会抛出此错误。如果您 如果使用其他浏览器,则需要自行进行测试。但可能不会 您为现实媒体播放器构建的内容:François Beaufort 的源缓冲区限制测试 至少能让你观察相应行为

我可以附加多少数据?

具体数量因浏览器而异。由于您无法查询 您需要跟踪自己的数据量 附加。关于精彩视频,我掌握了最实用的数据 。对于 Chrome,这些数字表示上限 在系统遇到内存压力时,可以减小内存值。

Chrome Chromecast* Firefox Safari Edge
视频 150MB 30MB 100MB 290MB 未知
音频 12MB 2MB 15MB 14MB 未知
  • 或其他内存有限的 Chrome 设备。

我该怎么办?

由于支持的数据量变化很大,您无法找到 SourceBuffer 中的数据量,因此必须通过处理 QuotaExceededError。现在,我们来了解几种实现方法。

处理 QuotaExceededError 的方法有多种。事实上, 最好结合使用一种或多种方法。您的方法应该以 除了处理数据之外,您还需要提取和尝试附加多少数据 HTMLMediaElement.currentTime,然后根据 QuotaExceededError。同时使用某种清单(例如 mpd 文件) (MPEG-DASH) 或 m3u8 文件 (HLS) 可帮助您跟踪要附加到缓冲区的数据。

现在,我们来看几种 QuotaExceededError

  • 移除不需要的数据,然后重新附加。
  • 附加较小的 fragment。
  • 降低播放分辨率。

虽然这两种方法可以组合使用,但我将逐一介绍。

移除不需要的数据并重新附加

实际上,这项测试应该命名为“移除不太可能被使用的数据”, 然后重新尝试附加可能即将使用的数据。”标题太长。 你只需要记住我的真正意思。

移除最近的数据并不像调用 SourceBuffer.remove() 那么简单。接收者 从 SourceBuffer 中移除数据,其更新标志必须为 false。如果 否则,请在移除任何数据之前调用 SourceBuffer.abort()

调用 SourceBuffer.remove() 时,有几点需要注意。

  • 这可能会对播放产生负面影响。例如,如果您 希望视频很快重放或循环播放,则您可能不想删除 视频开头。同样,如果您或用户寻求 您需要重新将这些数据附加到 来满足这种追求
  • 尽可能保守地将其移除。请注意,移除当前的 播放从某个时间点或之前该关键帧处开始的一组帧 currentTime,因为这会导致播放停滞。此类信息 因为 Web 应用可能需要从字节流中解析出该字节 。媒体清单或应用对关键帧的了解 媒体中的间隔时间设置可以帮助应用在选择移除范围时, 阻止移除当前播放的媒体。无论移除什么 删除当前播放的一组图片,甚至 这一点。一般来说,请不要移除当前时间之后的内容,除非您确定 不再需要相应媒体。如果您移除靠近 进度条指针可能会导致停顿
  • Safari 9 和 Safari 10 未正确实现 SourceBuffer.abort()。 事实上,它们会抛出错误,从而停止播放。幸运的是, 点击此处打开 bug 跟踪器 和此处。在 在此期间,您必须设法解决此问题Shaka Player 做到了 方法是在这些版本的 Safari 上对一个空的 abort() 函数执行桩。

附加较小的 fragment

具体流程如下。这种方法并非适用于所有情况 这样,可以根据需要调整小区块的大小 需求。也不需要返回网络 为部分用户支付额外的流量费用

const pieces = new Uint8Array([data]);
(function appendFragments(pieces) {
    if (sourceBuffer.updating) {
    return;
    }
    pieces.forEach(piece => {
    try {
        sourceBuffer.appendBuffer(piece);
    }
    catch e {
        if (e.name !== 'QuotaExceededError') {
        throw e;
        }

        // Reduction schedule: 80%, 60%, 40%, 20%, 16%, 12%, 8%, 4%, fail.
        const reduction = pieces[0].byteLength * 0.8;
        if (reduction / data.byteLength < 0.04) {
        throw new Error('MediaSource threw QuotaExceededError too many times');
        }
        const newPieces = [
        pieces[0].slice(0, reduction),
        pieces[0].slice(reduction, pieces[0].byteLength)
        ];
        pieces.splice(0, 1, newPieces[0], newPieces[1]);
        appendBuffer(pieces);  
    }
    });
})(pieces);

降低播放分辨率

这类似于移除最近的数据然后重新附加。事实上 但以下示例仅展示了降低分辨率。

使用此方法时,请注意以下几点:

  • 您必须附加一个新的初始化段。您必须随时执行此操作 你会改变表示法新的初始化代码段必须适用于 一些媒体细分。
  • 附加媒体的呈现时间戳应与时间戳一致 缓冲区中的数据,但不要向前跳转。 重叠已缓冲数据可能会导致卡顿或短暂失速,具体取决于 。无论您附加了什么内容,都不要将进度条指针重叠在一起 则会引发错误。
  • 跳转可能会中断播放。您可能会被诱导寻找 并从该位置继续播放。请注意,这会导致 播放中断,直到跳转完成。