适用于 MediaStreamTrack 的可插入流

MediaStreamTrack 的内容会以流的形式公开,可进行操控或用于生成新内容

背景

Media Capture and Streams API 的上下文中,MediaStreamTrack 接口表示流中的单个媒体轨道;通常,这些是音频或视频轨道,但也可能存在其他轨道类型。MediaStream 对象由零个或多个 MediaStreamTrack 对象组成,表示各种音轨或视频轨。每个 MediaStreamTrack 可以有一个或多个通道。声道表示媒体流的最小单元,例如与给定扬声器关联的音频信号,例如立体声音轨中的左声道或右声道。

什么是 MediaStreamTrack 的可插入式数据流?

MediaStreamTrack 可插入式数据流背后的核心理念是将 MediaStreamTrack 的内容作为一系列数据流(如 WHATWG Streams API 所定义)进行公开。这些数据流可用于引入新组件。

直接向开发者授予对视频(或音频)串流的访问权限,可让他们直接对串流应用修改。相比之下,若要使用传统方法实现相同的视频处理任务,开发者需要使用 <canvas> 元素等中介。(如需详细了解此类流程,请参阅视频 + 画布 = 魔力一文。)

浏览器支持

从 Chrome 94 开始,系统支持 MediaStreamTrack 的可插入式数据流。

使用场景

MediaStreamTrack 的可插入式串流的用例包括但不限于:

  • 视频会议小工具,例如“搞笑的帽子”或虚拟背景。
  • 语音处理,例如软件声码器

如何为 MediaStreamTrack 使用可插入式数据流

功能检测

您可以按如下方式针对 MediaStreamTrack 支持进行可插入式数据流特征检测。

if ('MediaStreamTrackProcessor' in window && 'MediaStreamTrackGenerator' in window) {
  // Insertable streams for `MediaStreamTrack` is supported.
}

核心概念

适用于 MediaStreamTrack 的可插入串流基于 WebCodecs 之前提出的概念,并从概念上将 MediaStreamTrack 拆分为两个组件:

  • MediaStreamTrackProcessor,用于使用 MediaStreamTrack 对象的来源并生成媒体帧流,具体而言是 VideoFrameAudioFrame 对象。您可以将其视为轨道接收器,该接收器能够将轨道中的未编码帧公开为 ReadableStream
  • MediaStreamTrackGenerator,用于使用媒体帧流并公开 MediaStreamTrack 接口。它可以提供给任何接收器,就像 getUserMedia() 中的轨道一样。它将媒体帧作为输入。

MediaStreamTrackProcessor

MediaStreamTrackProcessor 对象公开一个属性:readable。它允许从 MediaStreamTrack 读取帧。如果轨道是视频轨道,则从 readable 读取的块将是 VideoFrame 对象。如果轨道是音轨,则从 readable 读取的块将是 AudioFrame 对象。

MediaStreamTrackGenerator

MediaStreamTrackGenerator 对象同样公开了一个属性,即 writable,它是一个 WritableStream,允许将媒体帧写入 MediaStreamTrackGenerator(本身就是一个 MediaStreamTrack)。如果 kind 属性为 "audio",则串流接受 AudioFrame 对象,并会因任何其他类型而失败。如果 kind 为 "video",则串流接受 VideoFrame 对象,并会因任何其他类型而失败。将帧写入 writable 时,系统会自动调用帧的 close() 方法,这样便无法再通过 JavaScript 访问其媒体资源。

MediaStreamTrackGenerator 是指通过将媒体帧写入其 writable 字段来实现自定义源的轨道。

综合应用

核心思想是创建如下处理链:

平台轨道 → 处理器 → 转换 → 生成器 → 平台接收器

以下示例展示了条形码扫描器应用的此链条,该应用会在实时视频流中突出显示检测到的条形码。

const stream = await getUserMedia({ video: true });
const videoTrack = stream.getVideoTracks()[0];

const trackProcessor = new MediaStreamTrackProcessor({ track: videoTrack });
const trackGenerator = new MediaStreamTrackGenerator({ kind: 'video' });

const transformer = new TransformStream({
  async transform(videoFrame, controller) {
    const barcodes = await detectBarcodes(videoFrame);
    const newFrame = highlightBarcodes(videoFrame, barcodes);
    videoFrame.close();
    controller.enqueue(newFrame);
  },
});

trackProcessor.readable.pipeThrough(transformer).pipeTo(trackGenerator.writable);

const videoBefore = document.getElementById('video-before');
const videoAfter = document.getElementById('video-after');
videoBefore.srcObject = stream;
const streamAfter = new MediaStream([trackGenerator]);
videoAfter.srcObject = streamAfter;

演示

您可以在桌面浏览器或移动浏览器中查看上一部分中的二维码扫描器演示。将二维码放在摄像头前方,应用会检测到二维码并将其突出显示。您可以在 Glitch 上查看应用的源代码。

桌面浏览器标签页中运行的二维码扫描器,显示了用户在笔记本电脑摄像头前方举着的手机上检测到的突出显示的二维码。

安全和隐私权注意事项

此 API 的安全性依赖于 Web 平台中的现有机制。由于数据是使用 VideoFrameAudioFrame 接口公开的,因此这些接口用于处理来源污染数据的规则适用。例如,由于对访问此类资源的现有限制,无法访问来自跨源资源的数据(例如,无法访问跨源图片或视频元素的像素)。此外,应用必须获得用户授权,才能访问摄像头、麦克风或屏幕中的媒体数据。此 API 公开的媒体数据已通过其他 API 提供。

反馈

Chromium 团队希望了解您使用 MediaStreamTrack 插入式串流的体验。

请向我们说明 API 设计

API 是否有某些方面未按预期运行?或者,您是否缺少实现想法所需的方法或属性?您对安全模型有疑问或意见吗?在相应的 GitHub 代码库中提交规范问题,或在现有问题中添加您的想法。

报告实现方面的问题

您是否发现了 Chromium 实现中的 bug?或者实现方式是否与规范不同? 请访问 new.crbug.com 提交 bug。请务必提供尽可能详细的信息、简单的重现说明,并在 Components 框中输入 Blink>MediaStream故障非常适合分享快速简便的重现步骤。

显示对该 API 的支持

您是否打算为 MediaStreamTrack 使用可插入式串流?您的公开支持有助于 Chromium 团队确定功能的优先级,并向其他浏览器供应商表明支持这些功能的重要性。

使用 #InsertableStreams 标签向 @ChromiumDev 发送推文,告诉我们您在哪里以及如何使用该工具。

致谢

MediaStreamTrack 规范的可插入式数据流由 Harald AlvestrandGuido Urdaneta 编写。本文由 Harald Alvestrand、Joe MedleyBen WagnerHuib KleinhoutFrançois Beaufort 审核。主打图片由 Unsplash 用户 Chris Montgomery 提供。