})
.then(function(audioSegment1) {
audioSourceBuffer.appendBuffer(audioSegment1);
})
.then(function() {
return fetchSegment(“http://server.com/audio/segment2.mp4”);
})
.then(function(audioSegment2) {
audioSourceBuffer.appendBuffer(audioSegment2);
})
// …
// same thing for video segments
fetchSegment(“http://server.com/video/segment0.mp4”)
.then(function(videoSegment0) {
videoSourceBuffer.appendBuffer(videoSegment0);
});
// …
这意味着我们在服务器端也有那些多个段。在前面的示例中,我们的服务器至少包含以下文件:
./audio/
├── segment0.mp4
├── segment1.mp4
└── segment2.mp4
./video/
└── segment0.mp4
注意:音频或视频文件可能不会在服务器端真正进行切片,客户端可能会使用Range HTTP标头代替来获取切片的文件(或者,实际上,服务器可能会根据您的请求进行任何操作您返回具体内容)。
但是,这些情况是实现细节。在这里,我们将始终认为服务器端具有这些分片文件。
所有这些意味着, 我们不必等待整个音频或视频内容下载就可以开始播放。我们通常只需要第一部分。
当然,大多数播放器并不像我们在此处那样为每个视频和音频段手动执行此逻辑,但是他们遵循相同的想法:依次下载段并将其推入源缓冲区。
看到这种逻辑在现实生活中发生的一种有趣方式是,可以在Firefox / Chrome / Edge上打开网络监视器(在Linux或Windows上,键入“ Ctrl + Shift + i”,然后转到“网络”标签,在Mac上应依次为Cmd + Alt + i和“网络”),然后在您喜欢的流媒体网站中启动视频。
您应该可以看到各种视频和音频片段正在快速下载:
顺便说一句,您可能已经注意到,我们的段只是\被推送到源缓冲区中,而没有指示 WHERE, 参考时间正确的位置的地方进行添加。
实际上,片段的容器确实定义了应将它们放入整个媒体的时间。这样,我们不必在JavaScript中立即进行同步。
自适应码流 Adaptive Streaming
许多视频播放器具有“自动播放清晰度”功能,根据用户的网络和处理能力自动选择具体视频质量。
这是称为自适应流的网络播放器的核心问题。
借助媒体分片的概念,也可以启用此行为。
在服务器端,段实际上是用多种质量编码的。例如,我们的服务器可能存储了以下文件:
./audio/
├── ./128kbps/
| ├── segment0.mp4
| ├── segment1.mp4
| └── segment2.mp4
└── ./320kbps/
├── segment0.mp4
├── segment1.mp4
└── segment2.mp4
./video/
├── ./240p/
| ├── segment0.mp4
| ├── segment1.mp4
| └── segment2.mp4
└── ./720p/
├── segment0.mp4
├── segment1.mp4
└── segment2.mp4
然后,网络播放器将随着网络或CPU条件的变化自动选择正确的段进行下载。
这完全是用JavaScript完成的。例如,对于音频片段,它可能看起来像这样:
/**
-
Push audio segment in the source buffer based on its number
-
and quality
-
@param {number} nb
-
@param {string} language
-
@param {string} wantedQuality
-
@returns {Promise}
*/
function pushAudioSegment(nb, wantedQuality) {
// The url begins to be a little more complex here:
const url = “http://my-server/audio/” +
wantedQuality + “/segment” + nb + “.mp4”);
return fetch(url)
.then((response) => response.arrayBuffer());
.then(function(arrayBuffer) {
audioSourceBuffer.appendBuffer(arrayBuffer);
});
}
/**
-
Translate an estimated band