Захват видеопотока с любого элемента,Захват видеопотока с любого элемента

Франсуа Бофор
François Beaufort

С помощью API захвата экрана вы можете захватить всю текущую вкладку. API захвата элементов позволяет захватывать и записывать определенный элемент HTML. Он преобразует захват всей вкладки в захват определенного поддерева DOM, захватывая только прямых потомков целевого элемента. Другими словами, он обрезает и удаляет как перекрывающий, так и перекрытый контент.

Зачем использовать захват элементов?

Рассмотрение требований приложения для видеоконференций может помочь вам понять, где полезен Element Capture. Если у вас есть приложение для видеоконференций, которое позволяет встраивать сторонние приложения в iframe, иногда вам может потребоваться захватить этот iframe как видео и передать его удаленным участникам.

Скриншот звонка по видеоконференции в Chrome.
Элад использует стороннее приложение во время видеоконференции с Франсуа.

Вызов getDisplayMedia() и предоставление пользователю возможности выбрать текущую вкладку приведет к передаче всей текущей вкладки. Скорее всего, это приведет к передаче собственного видео людей обратно. Вы можете обрезать это с помощью «Захвата региона» .

Однако что, если докладчик взаимодействует с приложением для видеоконференций, а некоторый контент, например раскрывающийся список, отображается поверх контента, предназначенного для захвата?

Снимок экрана: раскрывающийся список, содержащий контент, предназначенный для захвата.
Раскрывающийся список отображается поверх содержимого, предназначенного для захвата.

Захват региона вам здесь не поможет. Часть раскрывающегося списка может оказаться видимой на экранах удаленных участников.

Сделан снимок экрана раскрывающегося списка.
Раскрывающийся список Elad отображается поверх содержимого, полученного Франсуа.

Тот факт, что Region Capture захватывает части элементов таким способом (известным как перекрытие контента ), создает множество проблем:

  • Закрытие контента может помешать просмотру контента, которым пользователь намеревался поделиться.
  • Закрывающий контент может быть конфиденциальным (например, уведомления чата).
  • Закрытие контента может сбить с толку. (Например, перепланировка приложения может на короткое время перенести собственные видео удаленных участников поверх захваченной цели.)

API Element Capture решает все эти проблемы, позволяя вам выбрать элемент, которым вы хотите поделиться.

Снимок экрана целевого элемента без раскрывающегося списка.
Франсуа не видит раскрывающийся список от Elad.

Как использовать захват элементов?

captureTarget — это элемент на вашей странице, который содержит контент, который пользователь хочет захватить. Вы хотите, чтобы веб-приложение для видеоконференций захватывал captureTarget и делился им с удаленными участниками. Таким образом, вы получаете RestrictionTarget из captureTarget . После ограничения видеодорожки с помощью этого RestrictionTarget кадры на этой видеодорожке теперь состоят только из пикселей, которые являются частью captureTarget и его прямых потомков DOM.

Если captureTarget меняет размер, форму или местоположение, видеодорожка следует за ней, не требуя каких-либо дополнительных входных данных из любого веб-приложения. Закрытие содержимого, которое появляется, исчезает или перемещается, также не требует специального лечения.

Просмотрите эти шаги еще раз:

Начните с разрешения пользователю захватить текущую вкладку.

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

Определите RestrictionTarget , вызвав RestrictionTarget.fromElement() с выбранным вами элементом в качестве входных данных.

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

Затем вызовите restrictTo() на видеодорожке, указав RestrictionTarget в качестве входных данных. Как только последнее обещание будет выполнено, все последующие кадры будут ограничены.

// 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) . В случае успеха возвращенное обещание будет разрешено с помощью нового объекта 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() успешен, возвращаемый Promise разрешается, когда можно гарантировать, что все последующие видеокадры будут ограничены captureTarget .

В случае неудачи обещание отклоняется. Неудачный вызов restrictTo() может произойти по одной из следующих причин:

  • Если restrictionTarget было создано на вкладке, отличной от той, которая была захвачена. (Обратите внимание, что с помощью кнопки «Поделиться этой вкладкой» пользователи могут изменить, какая вкладка будет сохранена в любой момент времени.)
  • Если restrictionTarget было получено из элемента, который больше не существует.
  • Если у трека есть клоны. (См. выпуск 1509418. )
  • Если текущая дорожка не является видеодорожкой самозахвата.
  • Если элемент, из которого был получен restrictionTarget , не подлежит ограничению.

Рекомендации по самозахвату

Когда приложение вызывает getDisplayMedia() и пользователь решает захватить собственную вкладку приложения, мы называем это «самозахватом».

Метод restrictTo() доступен для любой видеодорожки захвата табуляции, а не только для самостоятельного захвата. Но захват элемента на данный момент включен только для самостоятельного захвата. Поэтому рекомендуется проверить, выбрал ли пользователь текущую вкладку, прежде чем пытаться ограничить дорожку. Это можно сделать с помощью Capture Handle . Также можно попросить браузер подтолкнуть пользователя к самозахвату с помощью preferCurrentTab .

Прозрачность

Видеокадры, которые приложение получает через getDisplayMedia() не содержат альфа-канала. Если приложение устанавливает частично прозрачную цель захвата, удаление альфа-канала может иметь некоторые возможные последствия:

  • Цвета могут измениться. Частично прозрачные целевые элементы, нарисованные на светлом фоне, могут выглядеть темнее при удалении альфа-канала, а элементы, нарисованные на темном фоне, могут казаться светлее.
  • Цвета, которые были невидимы или неощутимы для пользователя, когда альфа-канал был установлен на максимум, появятся после удаления альфа-канала. Например, это могло привести к появлению неожиданных черных областей в захваченных кадрах, если прозрачные участки имели код RGBA rgba(0, 0, 0, 0) .
Снимок экрана с результатом прозрачной цели захвата непрямоугольной формы.
Непрямоугольный прозрачный целевой видеопоток захвата (справа) представляет собой прямоугольник на черном фоне, содержащий непрозрачный синий круг.

Неподходящие цели для захвата

Всегда можно начать ограничивать трек любой допустимой целью захвата. Однако кадры не будут создаваться при определенных условиях , например, если элемент или предок имеет display:none . Общее обоснование заключается в том, что ограничение применяется только к элементу, который представляет собой единую связную двумерную прямоугольную область, пиксели которой могут быть логически определены изолированно от любых родительских или родственных элементов.

Одним из важных соображений, гарантирующих, что элемент имеет право на ограничение, является то, что он должен сформировать свой собственный контекст стекирования . Чтобы гарантировать это, вы можете указать свойство CSS изоляции , установив для него значение isolate .

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

Обратите внимание, что целевой элемент может переключаться между правомочностью и непригодностью ограничения в любой произвольной точке, например, если приложение меняет свои свойства CSS. Приложение должно использовать разумные цели захвата и избегать неожиданного изменения их свойств. Если целевой элемент становится неприемлемым, новые кадры просто не будут отправляться на дорожку до тех пор, пока целевой элемент снова не станет доступным для ограничения.

Включение захвата элементов

API Element Capture доступен в Chrome на рабочем столе под флагом Element Capture и может быть включен по адресу chrome://flags/#element-capture .

Эта функция также проходит пробную версию Chrome 121 для настольных компьютеров , которая позволяет разработчикам включить эту функцию для посетителей своих сайтов для сбора данных от реальных пользователей. Дополнительную информацию о пробных версиях оригинального продукта см. в разделе Начало работы с пробными версиями оригинального продукта.

Безопасность и конфиденциальность

Чтобы понять компромиссы в области безопасности, ознакомьтесь с разделом «Вопросы конфиденциальности и безопасности» спецификации Element Capture.

Браузер Chrome рисует синюю рамку по краям захваченных вкладок.

Демо

Вы можете поиграть с Element Capture, запустив демо-версию на Glitch. Обязательно ознакомьтесь с исходным кодом .

Обратная связь

Команда Chrome и сообщество веб-стандартов хотят услышать о вашем опыте работы с Element Capture.

Расскажите о дизайне

Что-то в функции «Захват региона» работает не так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности?

  • Сообщите о проблеме спецификации в репозитории GitHub или добавьте свои мысли к существующей проблеме.

Проблема с реализацией?

Вы нашли ошибку в реализации Chrome? Или реализация отличается от спецификации?

  • Сообщите об ошибке на https://new.crbug.com . Обязательно включите как можно больше деталей и простые инструкции по воспроизведению. Glitch отлично подходит для быстрого и простого обмена репродукциями.

Благодарности

Фото Пола Скорупскаса на Unsplash