媒体缓冲、查找和时间范围
有时了解 <audio>
或 <video>
已经下载了多少或可以立即播放多少内容会很有用——一个很好的例子就是音频或视频播放器的缓冲进度条。本文将讨论如何使用 TimeRanges 和媒体 API 的其他功能来构建一个缓冲/跳转条。
缓冲
buffered
属性将告诉我们媒体的哪些部分已被下载。它返回一个 TimeRanges
对象,该对象将告诉我们媒体的哪些块已被下载。这通常是连续的,但如果用户在媒体缓冲时跳转,它可能会包含空隙。
这适用于 <audio>
或 <video>
;现在,让我们以音频为例
<audio id="my-audio" controls src="music.mp3"></audio>
我们可以像这样访问这些属性
const audio = document.getElementById("my-audio");
const bufferedTimeRanges = audio.buffered;
TimeRanges 对象
TimeRanges 是由起始时间和停止时间组成的一系列不重叠的时间范围。(了解更多关于 TimeRanges 的信息)。
一个 TimeRanges
对象包含以下属性:
length
:对象中时间范围的数量。start(index)
:时间范围的起始时间(以秒为单位)。end(index)
:时间范围的结束时间(以秒为单位)。
在没有任何用户交互的情况下,通常只有一个时间范围,但如果你在媒体中跳转,可能会出现多个时间范围,如下面的可视化所示。这表示两个缓冲的时间范围——一个跨度为 0 到 5 秒,第二个跨度为 15 到 19 秒。
------------------------------------------------------ |=============| |===========| | ------------------------------------------------------ 0 5 15 19 21
对于这个音频实例,相关的 TimeRanges
对象将具有以下可用属性:
audio.buffered.length; // returns 2
audio.buffered.start(0); // returns 0
audio.buffered.end(0); // returns 5
audio.buffered.start(1); // returns 15
audio.buffered.end(1); // returns 19
为了尝试和可视化缓冲时间范围,我们可以编写一些 HTML
<p>
<audio id="my-audio" controls>
<source
src="https://cdn.freesound.org/previews/155/155386_326032-lq.mp3"
type="audio/mpeg" />
</audio>
</p>
<p>
<canvas id="my-canvas" width="300" height="20"> </canvas>
</p>
以及一些 JavaScript
const audio = document.getElementById("my-audio");
const canvas = document.getElementById("my-canvas");
const context = canvas.getContext("2d");
context.fillStyle = "lightgray";
context.fillRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "red";
context.strokeStyle = "white";
// Display TimeRanges
audio.addEventListener("seeked", () => {
const inc = canvas.width / audio.duration;
for (let i = 0; i < audio.buffered.length; i++) {
const startX = audio.buffered.start(i) * inc;
const endX = audio.buffered.end(i) * inc;
const width = endX - startX;
context.fillRect(startX, 0, width, canvas.height);
context.rect(startX, 0, width, canvas.height);
context.stroke();
}
});
这在较长的音频或视频片段上效果更好,但按下播放并点击播放器进度条,你应该会看到红色的片段。每个红色填充的白色矩形代表一个时间范围。
可跳转
seekable
属性返回一个 TimeRanges
对象,并告诉我们媒体的哪些部分可以立即播放;这与该部分是否已下载无关。媒体的某些部分可能是可跳转但未缓冲的,如果服务器启用了字节范围请求。字节范围请求允许从服务器交付媒体文件的部分,因此几乎可以立即播放——因此它们是可跳转的。有关字节范围请求的更多信息,请参阅 HTTP 范围请求。
const seekableTimeRanges = audio.seekable;
创建我们自己的缓冲反馈
如果我们想创建自己的自定义播放器,我们可能需要提供关于媒体已准备好播放多少的反馈。实际上,一种很好的方法是使用 seekable
属性,尽管如上所述,媒体的可跳转部分不一定是连续的——但它们通常是连续的,我们可以安全地近似这些信息来向用户指示哪些部分可以直接播放。我们可以使用以下代码行找到媒体中的这个点:
const seekableEnd = audio.seekable.end(audio.seekable.length - 1);
注意: audio.seekable.end(audio.seekable.length - 1)
实际上告诉我们最后一个可跳转时间范围的结束点(不是所有可跳转的媒体)。在实践中,这已经足够了,因为浏览器要么启用范围请求,要么不启用。如果不启用,audio.seekable
将等同于 audio.buffered
,这将给出可跳转媒体结束的有效指示。如果启用了范围请求,这个值通常会几乎立即变成媒体的时长。
也许最好能指示媒体实际下载了多少——浏览器原生播放器似乎就是这样显示的。
所以,让我们来实现它。我们播放器的 HTML 如下:
<audio id="my-audio" preload controls>
<source
src="https://cdn.freesound.org/previews/155/155386_326032-lq.mp3"
type="audio/mpeg" />
</audio>
<div class="buffered">
<span id="buffered-amount"></span>
</div>
<div class="progress">
<span id="progress-amount"></span>
</div>
我们将使用以下 CSS 来样式化缓冲显示:
.buffered {
height: 20px;
position: relative;
background: #555555;
width: 300px;
}
#buffered-amount {
display: block;
height: 100%;
background-color: #777777;
width: 0;
}
.progress {
margin-top: -20px;
height: 20px;
position: relative;
width: 300px;
}
#progress-amount {
display: block;
height: 100%;
background-color: #559955;
width: 0;
}
以下 JavaScript 提供了我们的功能:
const audio = document.getElementById("my-audio");
audio.addEventListener("progress", () => {
const duration = audio.duration;
if (duration > 0) {
for (let i = 0; i < audio.buffered.length; i++) {
if (
audio.buffered.start(audio.buffered.length - 1 - i) < audio.currentTime
) {
document.getElementById("buffered-amount").style.width = `${
(audio.buffered.end(audio.buffered.length - 1 - i) * 100) / duration
}%`;
break;
}
}
}
});
audio.addEventListener("timeupdate", () => {
const duration = audio.duration;
if (duration > 0) {
document.getElementById("progress-amount").style.width = `${
(audio.currentTime / duration) * 100
}%`;
}
});
当数据下载时,会触发 progress 事件,如果我们要显示下载或缓冲进度,这是一个很好的事件来响应。
当媒体播放时,timeupdate 事件每秒触发 4 次,我们可以在那里增加播放进度条。
这次,你应该会看到两种类型的段。浅灰色条表示缓冲进度,绿色条表示已播放进度。
关于已播放的快速说明
值得一提的是 played
属性——它告诉我们媒体中已播放的时间范围。例如:
const played = audio.played; // returns a TimeRanges object
这可能有助于确定你的媒体中最常收听或观看的部分。