MediaStreamTrack
的内容以流的形式公开,可用于操纵或生成新内容
背景
在 Media Capture and Streams API 的上下文中,MediaStreamTrack
接口表示流中的单个媒体轨道;通常,这些是音轨或视频轨道,但也可能存在其他轨道类型。MediaStream
对象包含零个或多个 MediaStreamTrack
对象,表示各种音轨或视频轨道。每个 MediaStreamTrack
可以有一个或多个频道。声道表示媒体流的最小单位,例如与给定扬声器(如立体声音轨中的左声道或右声道)关联的音频信号。
什么是 MediaStreamTrack
的可插入流?
MediaStreamTrack
的可插入流背后的核心思想是将MediaStreamTrack
的内容公开为一组流(由 WHATWG Streams API 定义)。您可以操纵这些流来引入新组件。
授予开发者直接访问视频(或音频)流的权限后,他们便可以直接对该流进行修改。相比之下,如果使用传统方法实现相同的视频处理任务,开发者需要使用 <canvas>
元素等中介。(如需详细了解此类流程,请参阅视频 + 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
对象的来源并生成媒体帧(具体为VideoFrame
或AudioFrame
)对象流。您可以将此视为一种轨道接收器,能够将轨道中的未编码帧作为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;
演示
您可以在桌面版或移动版浏览器中观看上方部分中的 QR 码扫描器演示。将二维码放在摄像头前,应用会检测到并突出显示该二维码。您可以在 GitHub 上查看应用的源代码。
安全性和隐私权注意事项
此 API 的安全性依赖于 Web 平台中的现有机制。由于数据是通过 VideoFrame
和 AudioFrame
接口公开的,因此这些接口用于处理源污染数据的规则也适用。例如,由于目前对访问此类资源存在限制,因此无法访问来自跨源资源的数据(例如,无法访问跨源图片或视频元素的像素)。此外,对来自摄像头、麦克风或屏幕的媒体数据的访问也需要获得用户授权。此 API 公开的媒体数据已通过其他 API 提供。
反馈
Chromium 团队希望了解您在使用可插入流时遇到的问题(针对 MediaStreamTrack
)。
介绍 API 设计
API 是否存在未按预期运行的情况?或者,是否有缺少的方法或属性需要您来实现自己的想法?您对安全模型有任何疑问或意见吗?在相应的 GitHub 代码库中提交规范问题,或在现有问题中添加您的想法。
报告实现方面的问题
您是否发现了 Chromium 的实现存在 bug?或者实现是否与规范不同?
请前往 new.crbug.com 提交 bug。请务必尽可能详细地说明问题,提供简单的重现说明,并在组件框中输入 Blink>MediaStream
。
显示对 API 的支持
您是否计划为 MediaStreamTrack
使用可插入的视频流?您的公开支持有助于 Chromium 团队确定功能优先级,并向其他浏览器供应商展示支持这些功能的重要性。
使用 #ChromiumDev 标签向 @ChromiumDev 发送推文,告诉我们您在何处以及如何使用它。#InsertableStreams
实用链接
致谢
MediaStreamTrack
规范的可插入流由 Harald Alvestrand 和 Guido Urdaneta 编写。本文由 Harald Alvestrand、Joe Medley、Ben Wagner、Huib Kleinhout 和 François Beaufort 审核。主打图片由 Unsplash 上的 Chris Montgomery 提供。