提示💡

Fetch 的 body 或 XHR 的 arraybuffer

video 元素本身支持 H.264 编码的 MP4vp8编码的 WebMtheora 编码的 Ogg 视频格式。浏览器内部处理拉流逻辑。

对于像flv格式的视频流数据,我们需要自行拉取数据

浏览器依赖 HTTP FLV 或者 WebSocket 中的一种协议来传输FLV。其中HTTP FLV需通过流式IO去拉取数据,支持流式IO的有fetch或者stream

相关用法如下:

Fetch API 

Fetch API 会在发起请求后得到的 Promise 对象中返回一个 Response 对象,而 Response 对象除了提供 headersredirect() 等参数和方法外,还实现了 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();