适用于 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 对象,并失败并显示任何其他类型。如果种类为 "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 实现中存在的错误?或者,实现方式是否不同于规范? 请在 new.crbug.com 提交 bug。请务必提供尽可能多的详情和简单的重现说明,并在组件框中输入 Blink>MediaStreamGlitch 非常适合快速轻松地分享重现的视频。

显示对该 API 的支持

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

请使用 # 标签 #InsertableStreams@ChromiumDev 发送一条推文,并告诉我们您使用该产品的位置和方式。

致谢

符合 MediaStreamTrack 规范的可插入流由 Harald AlvestrandGuido Urdaneta 编写。本文由 Harald Alvestrand、Joe MedleyBen WagnerHuib KleinhoutFrançois Beaufort 审阅。主打图片由 Chris Montgomery 拍摄,来源是 Unsplash 用户。