从任何元素捕获视频流

François Beaufort
François Beaufort

借助 Screen Capture API,您可以捕获整个当前标签页。借助 Element Capture API,您可以捕获并记录特定的 HTML 元素。它将整个标签页的捕获内容转换为特定 DOM 子树的捕获内容,仅捕获目标元素的直接后代。换句话说,它会裁剪并移除遮挡内容和被遮挡内容。

为何要使用元素捕获?

考虑视频会议应用的要求有助于您了解元素捕获的用途。如果您使用的视频会议应用允许您在 iframe 中嵌入第三方应用,您有时可能需要将该 iframe 捕获为视频并将其传输给远程参与者。

Chrome 中的视频会议通话的屏幕截图。
Elad 在与 François 进行视频会议通话时使用第三方应用。

调用 getDisplayMedia() 并让用户选择当前标签页会传输整个当前标签页。这可能会将用户的视频回传给用户本人。您可以使用区域截图功能将其裁剪掉。

不过,如果演示者与视频会议应用互动,并且某些内容(例如下拉列表)恰好绘制在要捕获的内容之上,会发生什么情况?

屏幕截图:下拉列表遮盖了要捕获的内容。
下拉列表显示在要捕获的内容上方。

区域捕获功能无法帮您实现此目的。下拉列表的部分内容可能会显示在远程参与者的屏幕上。

拍摄的下拉列表的屏幕截图。
Elad 的下拉列表显示在 François 收到的内容之上。

区域捕获以这种方式捕获元素的部分内容(称为“遮挡内容”),会带来多个问题:

  • 遮挡内容可能会妨碍用户查看其打算分享的内容。
  • 遮挡的内容可能是私密内容(例如聊天通知)。
  • 遮挡内容可能会造成混淆。(例如,重新布局应用可能会短暂地将远程参与者自己的视频置于拍摄目标之上。)

Element Capture API 可让您指定要分享的元素,从而解决上述所有问题。

屏幕截图:目标元素,但未显示下拉列表。
弗朗索瓦看不到 Elad 发来的下拉列表。

如何使用元素捕获?

captureTarget 是网页上的一个元素,其中包含用户希望捕获的内容。您希望视频会议 Web 应用捕获 captureTarget 并与远程参会者分享。因此,您从 captureTarget 派生出 RestrictionTarget。使用此 RestrictionTarget 限制视频轨道后,该视频轨道上的帧现在仅包含属于 captureTarget 及其直接 DOM 后代的像素。

如果 captureTarget 更改大小、形状或位置,视频轨道会随之变化,而无需任何来自 Web 应用的额外输入。对于出现、消失或四处移动的遮挡内容,同样无需特殊处理。

再次查看以下步骤:

首先,允许用户捕获当前标签页。

// Ask the user for permission to start capturing the current tab.
const stream = await navigator.mediaDevices.getDisplayMedia({
 preferCurrentTab: true,
});
const [track] = stream.getVideoTracks();

通过调用 RestrictionTarget.fromElement() 并将所选元素作为输入,定义 RestrictionTarget

// Associate captureTarget with a new RestrictionTarget
const captureTarget = document.querySelector("#captureTarget");
const restrictionTarget = await RestrictionTarget.fromElement(captureTarget);

然后,对视频轨道调用 restrictTo(),并将 RestrictionTarget 作为输入。一旦最后一个 promise 解析完成,所有后续帧都会受到限制。

// Start restricting the self-capture video track using the RestrictionTarget.
await track.restrictTo(restrictionTarget);

// Enjoy! Transmit remotely.

深入探究

功能检测

如需检查是否支持 RestrictionTarget.fromElement(),请使用:

if ("RestrictionTarget" in self && "fromElement" in RestrictionTarget) {
  // Deriving a restriction target is supported.
}

派生 RestrictionTarget

重点关注名为 captureTarget元素。如需从中派生 RestrictionTarget,请调用 RestrictionTarget.fromElement(captureTarget)。如果成功,返回的 Promise 将解析为新的 RestrictionTarget 对象。否则,如果您铸造了数量不合理的 RestrictionTarget 对象,系统会拒绝您的请求。

const captureTarget = document.querySelector("#captureTarget");
const restrictionTarget = await RestrictionTarget.fromElement(captureTarget);

与元素不同,RestrictionTarget 对象是可序列化的。例如,可以使用 Window.postMessage() 将其传递给另一个文档。

限制

捕获标签页时,视频轨道会公开 restrictTo()。在捕获当前标签页时,可以调用 restrictTo(),并使用 null 或从当前标签页内的元素派生的任何 RestrictionTarget

restrictTo(restrictionTarget) 的调用会将视频轨道变异为 captureTarget 的捕获,就像它是由自身绘制的,独立于 DOM 的其余部分。captureTarget 的任何后代也会被捕获;captureTarget 的同级元素会被排除在捕获范围之外。这样一来,轨道上交付的任何帧看起来都像是被裁剪为 captureTarget 的轮廓,并且任何遮挡和被遮挡的内容都会被移除。

// Start restricting the self-capture video track using the RestrictionTarget.
await track.restrictTo(restrictionTarget);

restrictTo(null) 的调用会将轨道恢复到其原始状态。

// Stop restricting.
await track.restrictTo(null);

如果对 restrictTo() 的调用成功,则当可以保证所有后续视频帧都将限制为 captureTarget 时,返回的 Promise 会解析。

如果失败,则拒绝 Promise。对 restrictTo() 的调用失败的原因包括:

  • 如果 restrictionTarget 是在被捕获的标签页以外的标签页中铸造的。(请注意,用户可以使用“改用此标签页”按钮随时更改要捕获的标签页。)
  • 如果 restrictionTarget 是从不再存在的元素派生的。
  • 如果轨道有克隆。(请参阅问题 1509418。)
  • 如果当前轨道不是自行拍摄的视频轨道。
  • 如果派生出 restrictionTarget 的元素不符合限制条件。

自行拍摄注意事项

当应用调用 getDisplayMedia() 且用户选择捕获应用自己的标签页时,我们称之为“自捕获”。

restrictTo() 方法在任何标签页捕获视频轨道上公开,而不仅仅是用于自行捕获。不过,元素捕获功能目前仅适用于自拍。因此,建议在尝试限制轨道之前,先检查用户是否选择了当前标签页。可以使用 Capture Handle 来实现此目的。您还可以使用 preferCurrentTab 让浏览器提示用户进行自拍。

透明度

应用通过 getDisplayMedia() 获取的视频帧不包含 alpha 通道。如果应用设置了部分透明的捕获目标,剥离 Alpha 通道可能会产生以下后果:

  • 颜色可能会发生变化。绘制在浅色背景上的部分透明目标元素在移除 Alpha 通道后可能会显得更深色,而绘制在深色背景上的部分透明目标元素可能会显得更浅色。
  • 当 Alpha 通道设置为最大值时,用户看不到或感知不到的颜色会在移除 Alpha 通道后显示出来。例如,如果透明部分的 RGBA 代码为 rgba(0, 0, 0, 0),则可能会导致捕获的帧中出现意外的黑色区域。
非矩形透明捕获目标的捕获结果的屏幕截图。
非矩形透明拍摄目标视频流(右)是一个包含不透明蓝色圆圈的黑色背景矩形。

不符合条件的捕获目标

始终可以开始将轨道限制为任何有效的捕获目标。不过,在某些情况下,系统不会生成帧,例如,如果元素或其祖先是 display:none。一般而言,限制仅适用于包含单个内聚二维矩形区域的元素,该区域的像素可以从任何父元素或同级元素中逻辑地分离出来。

确保元素符合限制条件的一个重要考虑因素是,它必须形成自己的堆叠上下文。为确保这一点,您可以指定 isolation CSS 属性,将其设置为 isolate

<div id="captureTarget" style="isolation: isolate;"></iframe>

请注意,目标元素随时可能在符合限制条件和不符合限制条件之间切换,例如,如果应用更改了其 CSS 属性。应用应使用合理的捕获目标,并避免意外更改其属性。如果目标元素变得不符合条件,系统将不会在轨道上发出新的帧,直到目标元素再次符合限制条件为止。

浏览器支持

元素捕获功能仅适用于桌面版 Chrome 132 及更高版本。

安全和隐私设置

如需了解安全方面的权衡取舍,请参阅元素捕获规范的隐私权和安全性注意事项部分。

Chrome 浏览器会在捕获的标签页边缘绘制蓝色边框。

演示

您可以运行演示来试用元素捕获功能。

反馈

Chrome 团队和 Web 标准社区希望了解您在使用元素捕获功能时的体验。

介绍一下设计

元素捕获功能是否未按预期运行?或者,是否有缺少的方法或属性需要您来实现自己的想法?对安全模型有疑问或意见?

  • GitHub 代码库中提交规范问题,或在现有问题中添加您的想法。

实现存在问题?

您是否发现 Chrome 的实现存在 bug?还是实现与规范不同?

致谢

照片提供者:Paul Skorupskas;来源:Unsplash