提示💡
Fetch 的 body 或 XHR 的 arraybuffer
video 元素本身支持 H.264 编码的 MP4、vp8编码的 WebM、theora 编码的 Ogg 视频格式。浏览器内部处理拉流逻辑。
对于像flv格式的视频流数据,我们需要自行拉取数据。
浏览器依赖 HTTP FLV 或者 WebSocket 中的一种协议来传输FLV。其中HTTP FLV需通过流式IO去拉取数据,支持流式IO的有fetch或者stream。
相关用法如下:
Fetch API
Fetch API 会在发起请求后得到的 Promise 对象中返回一个 Response 对象,而 Response 对象除了提供 headers、redirect() 等参数和方法外,还实现了 Body 这个 mixin 类,而在 Body 上我们才看到我们常用的那些 res.json()、res.text()、res.arrayBuffer() 等方法。在 Body 上还有一个 body 参数,这个 body 参数就是一个 ReadableStream。
fetch(this.url, {
method: "GET"
}).then(resp => {
const { status, statusText } = resp;
resp.body.getReader().then(result => {
let { value, done } = result;
value = new Uint8Array(value ? value : 0);
this.data = concat(this.data, value);
if (done) {
this.done = true;
} else if (this.data.length < this.chunkSize) {
// ...,
}
});
});Streams API
Streams API 赋予了网络请求以片段处理数据的能力,过去我们使用 XMLHttpRequest 获取一个文件时,我们必须等待浏览器下载完整的文件,等待浏览器处理成我们需要的格式,收到所有的数据后才能处理它。现在有了流,我们可以以 TypedArray 片段的形式接收一部分二进制数据,然后直接对数据进行处理,这就有点像是浏览器内部接收并处理数据的逻辑。甚至我们可以将一些操作以流的形式封装,再用管道把多个流连接起来,管道的另一端就是最终处理好的数据。
this.xhr = new XMLHttpRequest();
this.xhr.open("GET", this.url);
this.xhr.responseType = "arraybuffer";
this.xhr.setRequestHeader("Range", `bytes=${startIndex}-${endIndex}`);
this.xhr.onload = () => {
if (this.xhr.readyState == 4) {
if (this.xhr.status >= 200 && this.xhr.status <= 299) {
if (!this.emitted) {
this.emitted = true;
}
this.startIndex = endIndex + 1;
resolve(new Uint8Array(this.xhr.response));
}
}
};
this.xhr.send();