Videostream von einem beliebigen Element erfassen

François Beaufort
François Beaufort

Mit der Screen Capture API können Sie den gesamten aktuellen Tab erfassen. Mit der Element Capture API können Sie ein bestimmtes HTML-Element erfassen und aufzeichnen. Sie wandelt die Erfassung des gesamten Tabs in eine Erfassung einer bestimmten DOM-Unterstruktur um, wobei nur direkte Nachfolgerelemente des Zielelements erfasst werden. Mit anderen Worten: Sie schneidet sowohl verdeckende als auch verdeckte Inhalte zu und entfernt sie.

Vorteile von Element Capture

Wenn Sie die Anforderungen einer Videokonferenzanwendung berücksichtigen, können Sie besser verstehen, wo Element Capture nützlich ist. Wenn Sie eine Videokonferenzanwendung haben, mit der Sie Drittanbieteranwendungen in einen iFrame einbetten können, möchten Sie diesen iFrame manchmal als Video erfassen und an die Teilnehmer an anderen Standorten senden.

Screenshot einer Videokonferenz in Chrome.
Elad verwendet in einer Videokonferenz mit François eine Drittanbieteranwendung.

Wenn getDisplayMedia() aufgerufen und der Nutzer den aktuellen Tab auswählen lässt, wird der gesamte aktuelle Tab übertragen. Dadurch wird wahrscheinlich das Video der Nutzer an sie zurückgesendet. Mit Region Capture können Sie das Bild zuschneiden.

Was passiert jedoch, wenn die vortragende Person die App für Videokonferenzen nutzt und einige Inhalte, z. B. eine Drop-down-Liste, über den für die Aufnahme vorgesehenen Inhalt gelegt werden?

Screenshot einer Drop-down-Liste mit den für die Aufnahme vorgesehenen Inhalten
Über dem für die Aufnahme vorgesehenen Inhalt wird eine Drop-down-Liste angezeigt.

Die Funktion „Region Capture“ wäre hier nicht hilfreich. Möglicherweise ist ein Teil der Drop-down-Liste auf den Bildschirmen der Teilnehmer im Homeoffice sichtbar.

Screenshot einer erfassten Drop-down-Liste.
Elads Drop-down-Liste wird über den Inhalten angezeigt, die François empfangen hat.

Die Tatsache, dass mit der Regionserfassung Teile von Elementen auf diese Weise erfasst werden (als verdeckende Inhalte bezeichnet), entstehen mehrere Probleme:

  • Versteckte Inhalte können dazu führen, dass die Inhalte, die der Nutzer teilen wollte, nicht mehr sichtbar sind.
  • Verdeckte Inhalte sind möglicherweise privat (z. B. Chatbenachrichtigungen).
  • Das Schließen von Inhalten kann verwirrend sein. (Beispielsweise könnte ein neues Layout der Anwendung dazu führen, dass die eigenen Videos der Teilnehmer, die nicht vor Ort sind, kurz über dem Aufnahmeziel zu bleiben.)

Die Element Capture API löst all diese Probleme, da Sie ein Targeting auf das Element vornehmen können, das Sie teilen möchten.

Screenshot des Zielelements ohne Drop-down-Liste.
François sieht die Drop-down-Liste von Elad nicht.

Wie verwende ich Element Capture?

Das captureTarget ist ein Element auf Ihrer Seite, das den Inhalt enthält, den der Nutzer erfassen möchte. Sie möchten, dass die Web-App für Videokonferenzen captureTarget erfasst und für Remote-Teilnehmer freigibt. Also leiten Sie ein RestrictionTarget von captureTarget ab. Nachdem der Videotrack mithilfe von RestrictionTarget eingeschränkt wurde, bestehen die Frames in diesem Videotrack jetzt nur aus den Pixeln, die Teil von captureTarget und seinen direkten DOM-Nachfolgern sind.

Wenn sich captureTarget an Größe, Form oder Position ändert, folgt der Videotrack ohne weitere Eingaben über die Web-App. Das Verdecken von Inhalten, die angezeigt, verschwindet oder verschoben werden, erfordert ebenfalls keine besondere Behandlung.

Gehen Sie diese Schritte noch einmal durch:

Lassen Sie zunächst zu, dass der Nutzer den aktuellen Tab erfassen kann.

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

Definieren Sie ein RestrictionTarget, indem Sie RestrictionTarget.fromElement() mit einem Element Ihrer Wahl als Eingabe aufrufen.

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

Rufen Sie dann im Videotrack restrictTo() mit RestrictionTarget als Eingabe auf. Sobald das letzte Promise aufgelöst wurde, werden alle nachfolgenden Frames eingeschränkt.

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

// Enjoy! Transmit remotely.

Im Detail

Funktionserkennung

So prüfen Sie, ob RestrictionTarget.fromElement() unterstützt wird:

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

RestrictionTarget ableiten

Fokussieren Sie sich auf das Element namens captureTarget. Um ein RestrictionTarget daraus abzuleiten, rufen Sie RestrictionTarget.fromElement(captureTarget) auf. Das zurückgegebene Promise wird bei erfolgreicher Ausführung mit einem neuen RestrictionTarget-Objekt aufgelöst. Andernfalls wird sie abgelehnt, wenn Sie eine unangemessene Anzahl von RestrictionTarget Objekten erstellt haben.

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

Im Gegensatz zu einem Element ist ein RestrictionTarget-Objekt serialisierbar. Er kann beispielsweise mit Window.postMessage() an ein anderes Dokument übergeben werden.

Eingeschränkt

Beim Aufzeichnen eines Tabs werden im Videotrack restrictTo() angezeigt. Beim Erfassen des aktuellen Tabs ist es zulässig, restrictTo() mit null oder einem beliebigen RestrictionTarget aufzurufen, das von einem Element auf dem aktuellen Tab abgeleitet wird.

Aufrufe von restrictTo(restrictionTarget) ändern den Videotrack zu einer Erfassung von captureTarget, als wäre er für sich allein und unabhängig vom Rest des DOMs gezeichnet. Alle Nachkommen von captureTarget werden ebenfalls erfasst und gleichgeordnete Elemente von captureTarget werden aus der Erfassung ausgeschlossen. Das hat zur Folge, dass alle auf dem Track bereitgestellten Frames so aussehen, als wären sie auf die Konturen von captureTarget zugeschnitten. Verdeckte und verdeckte Inhalte werden entfernt.

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

Durch Aufrufe an restrictTo(null) wird der Track auf seinen ursprünglichen Zustand zurückgesetzt.

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

Wenn der Aufruf von restrictTo() erfolgreich ist, wird das zurückgegebene Promise aufgelöst, wenn garantiert werden kann, dass alle nachfolgenden Videoframes auf captureTarget beschränkt werden.

Bei Nichtbestehen wird das Promise abgelehnt. Ein Aufruf von restrictTo() schlägt aus einem der folgenden Gründe fehl:

  • Ob restrictionTarget auf einem anderen Tab als dem aufgenommen wurde. Hinweis: Wenn Nutzer die Schaltfläche „Stattdessen diesen Tab teilen“ verwenden, können sie jederzeit ändern, welcher Tab erfasst wird.
  • Wenn restrictionTarget von einem Element abgeleitet wurde, das nicht mehr existiert.
  • Ob der Track Klone hat Weitere Informationen finden Sie unter Problem 1509418.
  • Der aktuelle Track ist kein von Ihnen selbst aufgenommener Videotrack.
  • Wenn das Element, von dem restrictionTarget abgeleitet wurde, nicht für eine Einschränkung infrage kommt.

Überlegungen zu Selbstaufnahmen

Wenn eine App getDisplayMedia() aufruft und der Nutzer entscheidet, den eigenen Tab der App zu erfassen, bezeichnen wir dies als „Selbstaufnahme“.

Die Methode restrictTo() wird in jedem Track, auf dem ein Tab aufgezeichnet wird, angezeigt und nicht nur zum Aufnehmen von Videos selbst. Die Elementerfassung ist jedoch vorerst nur für Selbstaufnahmen aktiviert. Sie sollten daher prüfen, ob der Nutzer den aktuellen Tab ausgewählt hat, bevor Sie versuchen, den Titel einzuschränken. Das ist mit dem Erfassungs-Alias möglich. Sie können den Browser auch bitten, den Nutzer mit preferCurrentTab zur Selbstaufnahme anzuregen.

Transparenz

Videoframes, die über getDisplayMedia() übertragen werden, enthalten keinen Alphakanal. Wenn eine App ein teilweise transparentes Aufnahmeziel festlegt, hat das Entfernen des Alphakanals einige mögliche Folgen:

  • Die Farben können sich ändern. Teilweise transparente Zielelemente, die über einen hellen Hintergrund gezeichnet wurden, erscheinen möglicherweise dunkler, wenn der Alphakanal entfernt wird, und solche, die über einem dunklen Hintergrund gezeichnet wurden, erscheinen möglicherweise heller.
  • Farben, die für den Nutzer unsichtbar oder nicht wahrnehmbar waren, wenn der Alphakanal auf das Maximum eingestellt war, werden angezeigt, sobald der Alphakanal entfernt wurde. Dies könnte beispielsweise zu unerwarteten schwarzen Bereichen in den erfassten Frames führen, wenn die transparenten Abschnitte den RGBA-Code rgba(0, 0, 0, 0) hätten.
Screenshot des Ergebnisses eines transparenten Erfassungsziels ohne Rechteck
Der nicht rechteckige Videostream für das transparente Erfassungsziel (rechts) ist ein Rechteck mit schwarzem Hintergrund, das einen undurchsichtigen blauen Kreis enthält.

Unzulässige Erfassungsziele

Es ist immer möglich, einen Track auf ein beliebiges gültiges Erfassungsziel zu beschränken. Unter bestimmten Bedingungen werden jedoch keine Frames erstellt, z. B. wenn das Element oder ein Ancestor display:none ist. Die allgemeine Begründung ist, dass die Einschränkung nur für ein Element gilt, das einen einzelnen, zusammenhängenden, zweidimensionalen, rechteckigen Bereich umfasst, dessen Pixel sich logisch getrennt von übergeordneten oder gleichgeordneten Elementen bestimmen lassen.

Ein wichtiger Aspekt, um sicherzustellen, dass das Element für Einschränkungen infrage kommt, besteht darin, dass es einen eigenen Stapelkontext bilden muss. Um dies sicherzustellen, können Sie die CSS-Eigenschaft isolation angeben und auf isolate setzen.

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

Das Zielelement kann jederzeit zwischen „Aktiv“ und „Nicht zulässig“ wechseln, z. B. wenn die App die CSS-Properties ändert. Es liegt in der Entscheidung der App, angemessene Erfassungsziele zu verwenden und zu vermeiden, dass ihre Eigenschaften unerwartet geändert werden. Wenn das Zielelement nicht mehr zulässig ist, werden einfach keine neuen Frames für den Track ausgegeben, bis das Zielelement wieder für eine Einschränkung infrage kommt.

Elementerfassung aktivieren

Die Element Capture API ist in Chrome auf Computern hinter dem Flag „Element Capture“ verfügbar und kann unter chrome://flags/#element-capture aktiviert werden.

Diese Funktion nimmt auch an einem Ursprungstest von Chrome 121 auf Computern teil, mit dem Entwickler die Funktion für Besucher ihrer Websites aktivieren können, um Daten von echten Nutzern zu erheben. Weitere Informationen zu Ursprungstests finden Sie unter Erste Schritte mit Ursprungstests.

Sicherheit und Datenschutz

Weitere Informationen zu den Vor- und Nachteilen der Sicherheit finden Sie im Abschnitt Überlegungen zu Datenschutz und Sicherheit der Element Capture-Spezifikation.

Der Chrome-Browser zeichnet an den Rändern der aufgenommenen Tabs einen blauen Rahmen.

Demo

Du kannst Element Capture ausprobieren, indem du die Demo auf Glitch ausführst. Sehen Sie sich unbedingt den Quellcode an.

Feedback

Das Chrome-Team und die Webstandards-Community möchten mehr über Ihre Erfahrungen mit Element Capture erfahren.

Erzähl uns etwas über das Design

Gibt es etwas an der Regionserfassung, das nicht wie erwartet funktioniert? Oder fehlen Methoden oder Eigenschaften, die du zur Umsetzung deiner Idee benötigst? Haben Sie eine Frage oder einen Kommentar zum Sicherheitsmodell?

  • Reichen Sie ein Spezifikationsproblem im GitHub-Repository ein oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.

Probleme bei der Implementierung?

Haben Sie bei der Implementierung von Chrome einen Fehler gefunden? Oder weicht die Implementierung von der Spezifikation ab?

  • Melde den Fehler unter https://new.crbug.com. Gib dabei so viele Details wie möglich und eine einfache Anleitung für die Reproduktion an. Glitch eignet sich hervorragend, um schnelle und einfache Reproduktionen zu teilen.

Danksagung

Foto von Paul Skorupskas auf Unsplash