Skip to content

screen-share/element-capture

Repository files navigation

Element Capture

Introduction

Pre-existing mechanisms such as getDisplayMedia() allow Web applications to initiate screen-capture. If the user chooses to capture a tab, mechanisms such as Region Capture mutate the resulting video track and perform an operation on all subsequent frames produced. (In the example of Region Capture, the operation consists of cropping frames to the frame's intersection with the bounding box of a target-element.)

Element Capture introduces a new mutation mechanism which we name "restriction". When an application "restricts" a video track to a given target-element, frames produced on the restricted video track only consist of information from the target-element and its descendants. Phrased differently, the track becomes a capture of the DOM sub-tree rooted at the target-element.

Sample use cases

Consider the following Web application. image

This Web app combines a productivity suite and a video conferencing tool. It uses Region Capture to crop away remote participants' own videos before it transmits the main content area to everyone.

But if other HTMLElements end up being drawn on top of the "main content area", they also get captured. This is not always desirable - see the following illustration.

Element Capture allows this app to capture only the main content area, excluding any occluding content such as drop-down lists.

A partial list of use-cases includes:

  • Removing sensitive content from video-captures, such as private messages.
  • Removing distracting content from video-captures, such as drop-down lists.
  • Client-side rendering.

Sample Code

Code in the capture-target:

const mainContentArea = navigator.getElementById('mainContentArea');
const restrictionTarget = await RestrictionTarget.fromElement(mainContentArea);
sendRestrictionTarget(restrictionTarget);

function sendRestrictionTarget(restrictionTarget) {
  // Either send the restriction-target using postMessage(),
  // or pass it on locally within the same document.
}

Code in the capturing-document:

async function startRestrictedCapture(restrictionTarget) {
  const stream = await navigator.mediaDevices.getDisplayMedia();
  const [track] = stream.getVideoTracks();
  if (!!track.restrictTo) {
    handleError(stream);
    return;
  }
  await track.restrictTo(restrictionTarget);
  transmitVideoRemotely(track);
}

Demos