利用区域拍摄功能更好地分享标签页

François Beaufort
François Beaufort

Web 平台已允许 Web 应用捕获当前标签页的视频轨道。它现在附带了区域截取功能,该功能用于剪裁这些视频轨道。网络应用会将当前标签页的一部分指定为感兴趣的区域,然后浏览器会剪裁该区域之外的所有像素。

以前,Web 应用可以“手动”剪裁视频轨道。也就是说,Web 应用可以直接操控每个帧。这既不健壮也不高效。区域截取功能可以解决这些缺点。Web 应用现在可以指示浏览器代表其执行工作。

区域截取简介

您已使用 Dynamic Content™ 创建了一个网站。这是有史以来最好的 Web 应用,用户会爱不释手,而且经常会协同使用。下一步可能就是嵌入虚拟会议功能。您决定接受。您与现有的视频会议服务提供商合作,将其 Web 应用嵌入为跨源 iframe。视频会议 Web 应用会将当前标签页作为视频轨道捕获,并将其传输给远程参与者。

浏览器窗口的屏幕截图,其中显示了一个 Web 应用,突出显示了主要内容区域和跨源 iframe。
主要内容区域以蓝色显示,跨源 iframe 以红色显示。

慢着…您不会真的想将用户自己的视频传回给他们吧?最好剪掉该部分。但如何实现呢?嵌入的 iframe 不知道您要显示哪些内容以及在哪里显示,因此需要一些帮助才能进行剪裁。从理论上讲,您可以传递预期的坐标。但是,如果用户调整窗口大小,会怎么样?滚动视口?放大或缩小?以会导致布局更改的方式与网页互动?即使您向捕获 iframe 发送了新坐标,时间问题仍可能会导致一些画面被剪裁。

接下来,我们来使用区域截图功能。您的网页上有一个 Element(可能是 <div>),其中包含主要内容。我们将其命名为 mainContentArea。您希望视频会议 Web 应用远程捕获并分享此元素的边界框定义的区域。因此,您可以从 mainContentArea 派生出 CropTarget。您将此 CropTarget 传递给视频会议 Web 应用。使用此 CropTarget 剪裁视频轨道后,该轨道上的帧现在仅包含位于 mainContentArea 边界框内的像素。如果 mainContentArea 更改大小、形状或位置,视频轨道也会随之更改,而无需任何 Web 应用提供额外输入。

我们再来回顾一下这些步骤:

您可以通过调用 CropTarget.fromElement()(并将所选元素作为输入)在 Web 应用中定义 CropTarget

// In the main web app, associate mainContentArea with a new CropTarget
const mainContentArea = document.querySelector("#mainContentArea");
const cropTarget = await CropTarget.fromElement(mainContentArea);

您将 CropTarget 传递给视频会议 Web 应用。

// Send the CropTarget to the video conferencing web app.
const iframe = document.querySelector("#videoConferenceIframe");
iframe.contentWindow.postMessage(cropTarget);

视频会议 Web 应用会使用从主 Web 应用收到的剪裁目标,对自拍视频轨道调用 cropTo(),以便让浏览器将轨道剪裁到 CropTarget 定义的区域。

// In the embedded video conferencing web app, ask the user for permission
// to start capturing the current tab.
const stream = await navigator.mediaDevices.getDisplayMedia({
  preferCurrentTab: true,
});
const [track] = stream.getVideoTracks();

// Start cropping the self-capture video track using the CropTarget
// received over window.onmessage.
await track.cropTo(cropTarget);

// Enjoy! Transmit remotely the cropped video track with RTCPeerConnection.

Et voilà! 大功告成。

深入解析

功能检测

如需检查是否支持 CropTarget.fromElement(),请使用以下命令:

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

派生 CropTarget

我们来重点关注名为 mainContentArea 的元素。如需从中派生 CropTarget,请调用 CropTarget.fromElement(mainContentArea)。如果成功,返回的 Promise 将通过新的 CropTarget 对象解析。否则,如果您铸造的 CropTarget 对象数量不合理,则会被拒绝。

const mainContentArea = document.querySelector("#mainContentArea");
const cropTarget = await CropTarget.fromElement(mainContentArea);

Element 不同,CropTarget 对象是可序列化的。例如,可以使用 Window.postMessage() 将其传递给其他文档。

剪裁

进行标签页捕获时,视频轨道会实例化为 BrowserCaptureMediaStreamTrack,它是 MediaStreamTrack 的子类。该子类会公开 cropTo()。调用 track.cropTo(cropTarget) 以开始按 mainContentArea(cropTarget 派生的元素)的轮廓进行剪裁。

如果成功,当能够保证所有后续视频帧都包含位于 mainContentArea 边界框内的像素时,Promise 将解析。

如果失败,Promise 将被拒绝。如果出现以下情况,就会发生这种情况:

  • CropTarget 是在其他标签页中铸造的。(目前 - 敬请期待。)
  • CropTarget 派生自不存在的元素。
  • 轨道有克隆。(请参阅问题 1509418。)
  • 当前轨道不是自拍视频轨道;请参阅下文。

cropTo() 方法会在任何标签页截取视频轨道上公开,而不仅仅是自拍。因此,建议先检查用户是否选择了当前标签页,然后再尝试剪裁轨道。这可以使用捕获句柄来实现。您还可以使用 preferCurrentTab 指示浏览器引导用户进行自拍。

// Start cropping the self-capture video track using the CropTarget.
await track.cropTo(cropTarget);

如需还原为未剪裁状态,请使用 null 调用 cropTo()

// Stop cropping.
await track.cropTo(null);

遮挡内容和被遮挡的内容

对于区域截取,只有目标的坐标和大小起作用,z 轴顺序无关紧要。系统会捕获遮挡目标的像素。系统不会捕获目标的遮挡部分。

这是因为区域截取本质上就是剪裁。一种替代方案(未来将成为自己的 API)是元素级捕获;也就是说,仅捕获与目标关联的像素,而不管是否存在遮挡。与简单剪裁相比,此类 API 具有一组不同的安全和隐私要求。

区域捕获 API 和元素级捕获 API 的不同结果示意图。
区域截取在存在遮挡内容时的行为。

安全和隐私设置

借助区域截取功能,已经在观察标签页中所有像素的 Web 应用可以自行移除其中的部分像素。这非常安全,因为系统无法获取任何新信息。

区域捕获功能可用于限制向远程参与者发送的信息。例如,您可能希望分享某些幻灯片,但不分享演讲者备注。

包含幻灯片和演讲者备注的浏览器窗口的屏幕截图。
包含幻灯片和演讲者备注的 Web 应用。
强烈建议不要远程共享备注。提示区域捕获。

请注意,在本地,区域截取功能不会提供任何安全保证。将轨道交给其他文档后,接收文档仍可以取消剪裁轨道,并获得对所捕获标签页的所有像素的访问权限。

Chrome 会在截取的标签页边缘绘制蓝色边框。剪裁时,Chrome 通常会在剪裁的目标周围绘制蓝色边框。

演示

您可以在 Glitch 上运行演示版,试用区域截取功能。请务必查看源代码

浏览器支持

浏览器支持

  • Chrome:104。
  • Edge:104。
  • Firefox:不受支持。
  • Safari:不受支持。

区域截图功能仅适用于 Chrome 104 桌面版。

后续步骤

下面简要介绍了我们即将推出的一系列功能,它们将改进网页上的屏幕共享体验:

  • 区域截图功能将支持截取其他标签页。
  • 条件焦点可让捕获的 Web 应用指示浏览器将焦点切换到捕获的显示屏 Surface,或避免进行此类焦点更改。
  • 可能会提供元素级捕获 API

反馈

Chrome 团队和 Web 标准社区希望了解您使用区域截图的体验。

请说明设计

区域截取功能是否未按预期运行?或者,您是否缺少实现想法所需的方法或属性?对安全模型有疑问或意见?

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

实现方面存在问题?

您是否发现了 Chrome 实现中的 bug?或者实现与规范不同?

  • 请访问 https://new.crbug.com 提交 bug。请务必提供尽可能详细的信息,并附上简单的重现说明。故障非常适合分享快速简便的重现步骤。

表达支持

您打算使用区域截取功能吗?您的公开支持有助于 Chrome 团队确定功能的优先级,并向其他浏览器供应商表明支持这些功能的重要性。

@ChromiumDev 发推文,告诉我们您在哪里以及如何使用它。

致谢

感谢 Joe Medley 审核本文。