Przechwytuj strumień wideo z dowolnego elementu

François Beaufort
François Beaufort

Za pomocą interfejsu Screen Capture API możesz uchwycić cały bieżący kartę. Interfejs Element Capture API umożliwia przechwycenie i zapisanie konkretnego elementu HTML. Przekształca ona zrzut całej karty w zrzut konkretnego poddrzewa DOM, obejmujący tylko bezpośrednich potomków elementu docelowego. Inaczej mówiąc, przycina i usuwa zarówno zasłaniające, jak i zasłaniane treści.

Dlaczego warto korzystać z Element Capture?

Zapoznanie się z wymaganiami aplikacji do wideokonferencji może pomóc Ci zrozumieć, w jakich sytuacjach Element Capture może być przydatny. Jeśli masz aplikację do rozmów wideo, która umożliwia umieszczanie aplikacji innych firm w iframe, możesz czasem chcieć przechwycić ten iframe jako film i przesłać go do uczestników zdalnych.

Zrzut ekranu przedstawiający wideokonferencję w Chrome.
Elad używa aplikacji innej firmy podczas rozmowy wideo z François.

Wywołanie metody getDisplayMedia() i pozwolenienie użytkownikowi na wybranie bieżącej karty spowoduje przesłanie całej bieżącej karty. Prawdopodobnie przesyła ona filmy do użytkowników. Możesz je przyciąć, korzystając z funkcji Zrzut obszaru.

Co jednak, jeśli prowadzący korzysta z aplikacji do wideokonferencji, a niektóre treści, na przykład lista rozwijana, są nakładane na treści, które mają być rejestrowane?

Zrzut ekranu pokazujący listę rozwijaną z treścią, którą ma być wykonywany zrzut ekranu.
Nad treścią przeznaczoną do przechwycenia pojawi się lista.

W tym przypadku nie pomoże Ci przechwytywanie regionu. Część listy może być widoczna na ekranach uczestników zdalnych.

Zrzut ekranu z listą rozwijaną
Lista rozwijana Elada pojawia się nad treściami otrzymanymi przez Françoisa.

Fakt, że funkcja Region Capture rejestruje w ten sposób części elementów (tzw. zakrywanie treści), powoduje wiele problemów:

  • Zasłonięcie treści może uniemożliwić wyświetlenie treści, które użytkownik chce udostępnić.
  • Zasłonięte treści mogą być prywatne (np. powiadomienia na czacie).
  • Zasłonięcie treści może być mylące. (np. ponowne rozmieszczenie elementów aplikacji może na chwilę spowodować wyświetlenie filmów uczestników zdalnych na uchwyconym obszarze).

Interfejs API Element Capture rozwiązuje wszystkie te problemy, ponieważ pozwala na ukierunkowanie na element, który chcesz udostępnić.

Zrzut ekranu pokazujący element docelowy bez widocznej listy rozwijanej
François nie widzi listy rozwijanej Elad.

Jak korzystać z Element Capture?

captureTarget to element na stronie, który zawiera treści, które użytkownik chce uchwycić. Chcesz, aby aplikacja internetowa do rozmów wideo rejestrowała captureTarget i udostępniała ją uczestnikom zdalnym. W ten sposób uzyskujesz RestrictionTargetcaptureTarget. Po ograniczeniu ścieżki wideo za pomocą tego RestrictionTarget ramki na tej ścieżce wideo składają się teraz tylko z pikseli, które są częścią captureTarget i jego bezpośrednich elementów potomnych w DOM.

Jeśli captureTarget zmienia rozmiar, kształt lub położenie, ścieżka wideo podąża za nim, nie wymagając żadnych dodatkowych danych z żadnej z aplikacji internetowych. Zasłonięcie treści, które pojawiają się, znikają lub się przemieszczają, również nie wymaga specjalnego traktowania.

Ponownie wykonaj te czynności:

Najpierw zezwól użytkownikowi na przechwycenie bieżącej karty.

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

Zdefiniuj RestrictionTarget, wywołując funkcję RestrictionTarget.fromElement() z dowolnym elementem jako argumentem.

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

Następnie wywołaj funkcję restrictTo() na ścieżce wideo, podając jako dane wejściowe funkcję RestrictionTarget. Gdy ostatnie obietnice zostaną spełnione, wszystkie kolejne ramki zostaną ograniczone.

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

// Enjoy! Transmit remotely.

Szczegółowa analiza

Wykrywanie funkcji

Aby sprawdzić, czy RestrictionTarget.fromElement() jest obsługiwane, użyj:

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

Tworzenie obiektu RestrictionTarget

Zwróć uwagę na element o nazwie captureTarget. Aby uzyskać z niego wartość RestrictionTarget, wywołaj funkcję RestrictionTarget.fromElement(captureTarget). W przypadku powodzenia zwrócona obietnica zostanie rozwiązana z nowym obiektem RestrictionTarget. W przeciwnym razie zostanie odrzucony, jeśli wyemitujesz nieuzasadnione ilości obiektów RestrictionTarget.

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

W przeciwieństwie do obiektu Element obiekt RestrictionTarget można zserializować. Można go przekazać do innego dokumentu za pomocą na przykład elementu Window.postMessage().

Kierowanie ograniczone

Podczas przechwytywania karty ścieżka wideo ujawnia restrictTo(). Podczas przechwytywania bieżącej karty można wywołać funkcję restrictTo() z parametrami null lub dowolnym parametrem RestrictionTarget pochodzącym z elementu na bieżącej karcie.

Wywołania funkcji restrictTo(restrictionTarget) zmieniają ścieżkę wideo na uchwyt captureTarget, tak jakby była ona rysowana samodzielnie, niezależnie od reszty modelu DOM. Wszystkie potomki elementu captureTarget są też rejestrowane; elementy pokrewne do captureTarget są eliminowane z rejestracji. W efekcie wszystkie klatki dostarczone na ścieżce wyglądają tak, jakby zostały przycięte do kontur captureTarget, a zasłonięte i zasłonięte treści są usuwane.

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

wywołania restrictTo(null), które przywracają ścieżkę do jej pierwotnego stanu.

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

Jeśli wywołanie metody restrictTo() zakończy się pomyślnie, zwrócona obietnica zostanie rozwiązana, gdy będzie można zagwarantować, że wszystkie kolejne klatki filmu będą ograniczone do captureTarget.

Jeśli nie uda się tego zrobić, obietnica zostanie odrzucona. Nieudany wywołanie do restrictTo() może być spowodowany jednym z tych powodów:

  • Jeśli restrictionTarget został wyemitowany na karcie innej niż ta, która jest rejestrowana. (za pomocą przycisku „Udostępnij tę kartę” użytkownicy mogą w dowolnym momencie zmienić kartę, która ma być przechwycona).
  • Jeśli restrictionTarget pochodzi z elementu, który już nie istnieje.
  • Jeśli utwór ma kopie. (zobacz problem 1509418).
  • Jeśli bieżąca ścieżka nie jest ścieżką z filmem nagranym przez użytkownika.
  • Jeśli element, z którego pochodzi restrictionTarget, nie kwalifikuje się do ograniczenia.

Uwagi dotyczące samodzielnego rejestrowania

Gdy aplikacja wywołuje getDisplayMedia(), a użytkownik zdecyduje się na przechwycenie własnej karty aplikacji, nazywamy to „samoprzechwyceniem”.

Metoda restrictTo() jest dostępna na dowolnym ścieżce wideo z przechwytem karty, a nie tylko w przypadku przechwytu własnego. Element Capture jest obecnie dostępny tylko do samodzielnego nagrywania. Dlatego przed próbą zablokowania utworu należy sprawdzić, czy użytkownik wybrał bieżącą kartę. Można to zrobić za pomocą funkcji chwytania uchwytu. Można też poprosić przeglądarkę o zachęcenie użytkownika do samodzielnego wykonania zdjęcia za pomocą preferCurrentTab.

Przejrzystość

Klatka filmu, którą aplikacja przesyła do getDisplayMedia(), nie zawiera kanału alfa. Jeśli aplikacja ustawia cel przechwytywania z częściowo przezroczystym kanałem alfa, usunięcie tego kanału może mieć pewne konsekwencje:

  • Kolory mogą się zmienić. Po usunięciu kanału alfa częściowo przezroczyste elementy docelowe narysowane na jasnym tle mogą wydawać się ciemniejsze, a te narysowane na ciemnym tle mogą wydawać się jaśniejsze.
  • Kolory, które były niewidoczne lub niewyczuwalne dla użytkownika, gdy kanał alfa był ustawiony na maksimum, będą widoczne po usunięciu tego kanału. Może to na przykład spowodować nieoczekiwane czarne obszary na zarejestrowanych klatkach, jeśli przezroczyste sekcje mają kod RGBA rgba(0, 0, 0, 0).
Zrzut ekranu z wynikiem przezroczystego celu przechwytywania o nieprostokątnym kształcie.
Przekaz wideo docelowego z przezroczystym tłem (po prawej) to czarny prostokąt na tle, który zawiera nieprzezroczysty niebieski okrąg.

Niekwalifikujące się cele przechwytywania

W każdej chwili możesz zacząć ograniczać ścieżkę do dowolnego prawidłowego celu przechwytywania. Jednak w pewnych warunkach nie będą one tworzone, np. gdy element lub jego przodek ma wartość display:none. Ogólnie chodzi o to, że ograniczenie dotyczy tylko elementu, który składa się z jednego spójnego, dwuwymiarowego prostokątnego obszaru, którego piksele można logicznie określić niezależnie od elementów nadrzędnych lub elementów siostrza.

Aby element mógł zostać objęty ograniczeniem, musi mieć własny kontekst nakładania się. Aby to zrobić, możesz ustawić właściwość CSS isolation na isolate.

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

Pamiętaj, że element docelowy może w dowolnym momencie stać się odpowiedni lub nieodpowiedni do ograniczenia, np. gdy aplikacja zmieni swoje właściwości CSS. Aplikacja musi używać odpowiednich celów przechwytywania i nie zmieniać ich właściwości w nieoczekiwany sposób. Jeśli element docelowy nie spełnia kryteriów, nowe klatki nie będą emitowane na ścieżce, dopóki element docelowy nie będzie ponownie spełniał kryteriów ograniczenia.

Obsługa przeglądarek

Element Capture jest dostępny w Chrome 132 tylko na komputerach.

Bezpieczeństwo i prywatność

Aby dowiedzieć się więcej o kompromisach w zakresie bezpieczeństwa, zapoznaj się z sekcją Uwzględnianie prywatności i zabezpieczeń w specyfikacji Element Capture.

Przeglądarka Chrome rysuje niebieską ramkę wokół krawędzi przechwyconych kart.

Prezentacja

Możesz wypróbować Element Capture, uruchamiając demo na Glitch. Pamiętaj, aby sprawdzić kod źródłowy.

Prześlij opinię

Zespół Chrome i społeczność zajmująca się standardami internetowymi chce poznać Twoje wrażenia z korzystania z Element Capture.

Opowiedz nam o projektie

Czy Element Capture nie działa zgodnie z oczekiwaniami? A może brakuje metod lub właściwości, których potrzebujesz do wdrożenia swojego pomysłu? Masz pytania lub uwagi dotyczące modelu zabezpieczeń?

  • Zgłoś problem ze specyfikacją w repozytorium GitHub lub podziel się opinią na temat istniejącego problemu.

Problem z implementacją?

Czy znalazłeś/znalazłaś błąd w implementacji Chrome? A może implementacja różni się od specyfikacji?

Podziękowania

Zdjęcie: Paul Skorupskas z Unsplash