MediaSource

可用性有限

此特性不是基线特性,因为它在一些最广泛使用的浏览器中不起作用。

注意:此功能在 专用 Web Workers 中可用。

MediaSource 接口是 Media Source Extensions API 的一部分,它代表了 HTMLMediaElement 对象的媒体数据源。MediaSource 对象可以附加到 HTMLMediaElement 以在用户代理中播放。

EventTarget MediaSource

构造函数

MediaSource()

构造并返回一个新的 MediaSource 对象,不关联任何源缓冲区(source buffers)。

实例属性

MediaSource.activeSourceBuffers 只读

返回一个 SourceBufferList 对象,其中包含 MediaSource.sourceBuffers 中的 SourceBuffer 对象的一个子集 — 该列表提供了选定的视频轨道、启用的音频轨道以及显示/隐藏的文本轨道。

MediaSource.duration

获取并设置当前正在呈现的媒体的时长。

MediaSource.handle 只读

在专用工作线程(dedicated worker)中,返回一个 MediaSourceHandle 对象,它是 MediaSource 的一个代理,可以从工作线程传输回主线程,并通过其 HTMLMediaElement.srcObject 属性附加到媒体元素。

MediaSource.readyState 只读

返回一个枚举值,表示当前 MediaSource 的状态:未附加到媒体元素(closed)、已附加并准备好接收 SourceBuffer 对象(open)、已附加但流已通过 MediaSource.endOfStream() 结束(ended)。

MediaSource.sourceBuffers 只读

返回一个 SourceBufferList 对象,其中包含与此 MediaSource 关联的 SourceBuffer 对象列表。

静态属性

MediaSource.canConstructInDedicatedWorker 只读

一个布尔值;如果实现了 MediaSource 的工作线程支持,则返回 true,提供了一种低延迟的特性检测机制。

实例方法

继承其父接口 EventTarget 的方法。

MediaSource.addSourceBuffer()

创建给定 MIME 类型的新 SourceBuffer,并将其添加到 MediaSource.sourceBuffers 列表中。

MediaSource.clearLiveSeekableRange()

清除之前通过调用 setLiveSeekableRange() 设置的可搜索范围。

MediaSource.endOfStream()

发出流结束的信号。

MediaSource.removeSourceBuffer()

MediaSource.sourceBuffers 列表中移除给定的 SourceBuffer

MediaSource.setLiveSeekableRange()

设置用户可以在媒体元素中搜索的范围。

静态方法

MediaSource.isTypeSupported()

返回一个布尔值,指示当前用户代理是否支持给定的 MIME 类型 — 即,是否能成功为该 MIME 类型创建 SourceBuffer 对象。

事件

sourceclose

MediaSource 实例不再附加到媒体元素时触发。

sourceended

MediaSource 实例仍附加到媒体元素,但已调用 endOfStream() 时触发。

sourceopen

MediaSource 实例已由媒体元素打开,并且可以开始向 SourceBuffer 对象(位于 sourceBuffers 中)追加数据时触发。

示例

完整的基本示例

以下简单示例使用 XMLHttpRequest 加载视频,并在可以播放时立即播放。此示例由 Nick Desaulniers 编写,可在此处 查看实时演示(您也可以 下载源代码 进行进一步研究)。函数 getMediaSource()(此处未定义)返回一个 MediaSource

js
const video = document.querySelector("video");

const assetURL = "frag_bunny.mp4";
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
let mediaSource;

if ("MediaSource" in window && MediaSource.isTypeSupported(mimeCodec)) {
  mediaSource = getMediaSource();
  console.log(mediaSource.readyState); // closed
  video.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener("sourceopen", sourceOpen);
} else {
  console.error("Unsupported MIME type or codec: ", mimeCodec);
}

function sourceOpen() {
  console.log(this.readyState); // open
  const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
  fetchAB(assetURL, (buf) => {
    sourceBuffer.addEventListener("updateend", () => {
      mediaSource.endOfStream();
      video.play();
      console.log(mediaSource.readyState); // ended
    });
    sourceBuffer.appendBuffer(buf);
  });
}

function fetchAB(url, cb) {
  console.log(url);
  const xhr = new XMLHttpRequest();
  xhr.open("get", url);
  xhr.responseType = "arraybuffer";
  xhr.onload = () => {
    cb(xhr.response);
  };
  xhr.send();
}

在专用工作线程中构造 MediaSource 并将其传递给主线程

可以在专用工作线程中访问 handle 属性,然后通过 postMessage() 调用将生成的 MediaSourceHandle 对象传输回创建工作线程的线程(在此例中为主线程)。

js
// Inside dedicated worker
let mediaSource = new MediaSource();
let handle = mediaSource.handle;
// Transfer the handle to the context that created the worker
postMessage({ arg: handle }, [handle]);

mediaSource.addEventListener("sourceopen", () => {
  // Await sourceopen on MediaSource before creating SourceBuffers
  // and populating them with fetched media — MediaSource won't
  // accept creation of SourceBuffers until it is attached to the
  // HTMLMediaElement and its readyState is "open"
});

在主线程中,我们通过 message 事件处理器接收句柄,通过其 HTMLMediaElement.srcObject 属性将其附加到 <video> 元素,然后 play 视频。

js
worker.addEventListener("message", (msg) => {
  let mediaSourceHandle = msg.data.arg;
  video.srcObject = mediaSourceHandle;
  video.play();
});

注意: MediaSourceHandle 无法成功传输到共享工作线程或服务工作线程中,或通过它们进行传输。

规范

规范
Media Source Extensions™
# mediasource

浏览器兼容性

另见