Captura una transmisión de video por Internet desde cualquier elemento

François Beaufort
François Beaufort

Con la API de Screen Capture, puedes capturar toda la pestaña actual. La API de Element Capture te permite capturar y grabar un elemento HTML específico. Transforma una captura de toda la pestaña en una captura de un subárbol DOM específico, y captura solo los elementos secundarios directos del elemento objetivo. En otras palabras, recorta y quita el contenido que ocluye y el contenido ocluido.

¿Por qué usar la función de captura de elementos?

Tener en cuenta los requisitos de una aplicación de videoconferencias puede ayudarte a comprender dónde es útil Element Capture. Si tienes una aplicación de videoconferencias que te permite incorporar aplicaciones de terceros en un iframe, es posible que, en ocasiones, quieras capturar ese iframe como un video y transmitirlo a los participantes remotos.

Captura de pantalla de una videollamada en Chrome.
Elad usa una aplicación de terceros en una llamada de videoconferencia con François.

Llamar a getDisplayMedia() y permitir que el usuario elija la pestaña actual transmitiría toda la pestaña actual. Es probable que se transmita el video de las personas. Puedes recortar esta parte con Captura de región.

Sin embargo, ¿qué sucede si el presentador interactúa con la aplicación de videoconferencias y parte del contenido, como una lista desplegable, se dibuja sobre el contenido que se pretende capturar?

Captura de pantalla de una lista desplegable que cubre el contenido que se desea capturar.
Aparece una lista desplegable sobre el contenido que se desea capturar.

La captura de región no te ayudaría en ese caso. Es posible que parte de la lista desplegable termine siendo visible en las pantallas de los participantes remotos.

Captura de pantalla de una lista desplegable.
La lista desplegable de Elad aparece sobre el contenido que recibió François.

El hecho de que la captura de regiones capture partes de elementos de esta manera (lo que se conoce como contenido ocluyente) genera varios problemas:

  • El contenido que ocluye puede obstruir la vista del contenido que el usuario quería compartir.
  • El contenido que se oculta puede ser privado (por ejemplo, las notificaciones de chat).
  • El contenido que ocluye puede ser confuso. (Por ejemplo, un cambio en el diseño de la aplicación podría mostrar brevemente los videos de los participantes remotos sobre el objetivo capturado).

La API de Element Capture resuelve todos estos problemas, ya que te permite segmentar el elemento que deseas compartir.

Captura de pantalla del elemento objetivo sin una lista desplegable a la vista.
François no ve la lista desplegable de Elad.

¿Cómo uso Element Capture?

El captureTarget es un elemento de tu página que contiene el contenido que el usuario desea capturar. Quieres que la app web de videoconferencias capture captureTarget y lo comparta con los participantes remotos. Por lo tanto, derivas un RestrictionTarget de captureTarget. Después de restringir la pista de video con este RestrictionTarget, los fotogramas de esa pista de video ahora solo constan de los píxeles que forman parte de captureTarget y sus elementos secundarios directos del DOM.

Si captureTarget cambia de tamaño, forma o ubicación, la pista de video lo sigue sin necesidad de ninguna entrada adicional de ninguna de las apps web. De manera similar, el contenido que se oculta, aparece o se mueve no requiere un tratamiento especial.

Vuelve a revisar estos pasos:

Comienza por permitir que el usuario capture la pestaña actual.

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

Define un RestrictionTarget llamando a RestrictionTarget.fromElement() con un elemento de tu elección como entrada.

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

Luego, llama a restrictTo() en la pista de video con RestrictionTarget como entrada. Una vez que se resuelva la última promesa, se restringirán todos los fotogramas posteriores.

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

// Enjoy! Transmit remotely.

Análisis detallado

Detección de características

Para verificar si se admite RestrictionTarget.fromElement(), usa lo siguiente:

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

Cómo derivar un RestrictionTarget

Enfócate en el elemento llamado captureTarget. Para derivar un RestrictionTarget de él, llama a RestrictionTarget.fromElement(captureTarget). Si la operación se realiza correctamente, la promesa devuelta se resolverá con un nuevo objeto RestrictionTarget. De lo contrario, se rechazará si acuñaste una cantidad irrazonable de objetos RestrictionTarget.

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

A diferencia de un elemento, un objeto RestrictionTarget es serializable. Por ejemplo, se puede pasar a otro documento con Window.postMessage().

Restringida

Cuando se captura una pestaña, la pista de video expone restrictTo(). Cuando se captura la pestaña actual, es válido llamar a restrictTo() con null o cualquier RestrictionTarget derivado de un elemento dentro de la pestaña actual.

Las llamadas a restrictTo(restrictionTarget) mutan la pista de video en una captura de captureTarget, como si se dibujara por sí sola, independientemente del resto del DOM. También se capturan los elementos secundarios de captureTarget, pero se eliminan los hermanos de captureTarget de la captura. El resultado es que cualquier fotograma que se entregue en la pista aparecerá como si se hubiera recortado según los contornos de captureTarget, y se quitará todo el contenido que ocluya y que esté ocluido.

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

Las llamadas a restrictTo(null) revierten el segmento a su estado original.

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

Si la llamada a restrictTo() se realiza correctamente, la promesa devuelta se resuelve cuando se puede garantizar que todos los fotogramas de video posteriores se restringirán a captureTarget.

Si no se realiza correctamente, se rechaza la promesa. Una llamada sin éxito a restrictTo() se debe a uno de los siguientes motivos:

  • Si el restrictionTarget se generó en una pestaña que no es la que se está capturando (Ten en cuenta que, con el botón "Compartir esta pestaña", los usuarios pueden cambiar la pestaña que se captura en cualquier momento).
  • Si el restrictionTarget se derivó de un elemento que ya no existe.
  • Indica si la pista tiene clones. (Consulta el problema 1509418).
  • Si la pista actual no es una pista de video de captura propia.
  • Si el elemento del que se derivó restrictionTarget no es apto para la restricción.

Consideraciones sobre la captura personal

Cuando una app llama a getDisplayMedia() y el usuario elige capturar la propia pestaña de la app, llamamos a eso "autocaptura".

El método restrictTo() se expone en cualquier pista de video de captura de pestaña, no solo para la autocaptura. Sin embargo, por el momento, la captura de elementos solo está habilitada para la autocaptura. Por lo tanto, es recomendable verificar si el usuario seleccionó la pestaña actual antes de intentar restringir el segmento. Esto se puede lograr con Capture Handle. También es posible pedirle al navegador que incite al usuario a realizar la autocaptura con preferCurrentTab.

Transparencia

Los fotogramas de video que la app obtiene a través de getDisplayMedia() no incluyen un canal alfa. Si una app establece un objetivo de captura parcialmente transparente, quitar el canal alfa puede tener algunas consecuencias:

  • Los colores pueden cambiar. Los elementos objetivo parcialmente transparentes dibujados sobre un fondo claro pueden parecer más oscuros cuando se quita el canal alfa, y los que se dibujan sobre un fondo oscuro pueden parecer más claros.
  • Los colores que eran invisibles o imperceptibles para el usuario cuando el canal alfa se estableció en su máximo aparecerían una vez que se quitara el canal alfa. Por ejemplo, esto podría generar regiones negras inesperadas en los fotogramas capturados si las secciones transparentes tenían el código RGBA rgba(0, 0, 0, 0).
Captura de pantalla del resultado de un objetivo de captura transparente que no es rectangular.
El flujo de video del objetivo de captura transparente no rectangular (derecha) es un rectángulo de fondo negro que contiene un círculo azul opaco.

Objetivos de captura no aptos

Siempre es posible comenzar a restringir un segmento a cualquier objetivo de captura válido. Sin embargo, no se producirán fotogramas en ciertas condiciones, por ejemplo, si el elemento o un elemento superior es display:none. La justificación general es que la restricción solo se aplica a un elemento que comprende un área rectangular bidimensional única y cohesiva, cuyos píxeles se pueden determinar lógicamente de forma aislada de cualquier elemento principal o secundario.

Una consideración importante para garantizar que el elemento sea apto para la restricción es que debe formar su propio contexto de apilamiento. Para garantizar esto, puedes especificar la propiedad CSS isolation y establecerla en isolate.

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

Ten en cuenta que el elemento objetivo puede alternar entre ser apto y no apto para la restricción en cualquier punto arbitrario, por ejemplo, si la app cambia sus propiedades de CSS. Depende de la app usar objetivos de captura razonables y evitar cambiar sus propiedades de forma inesperada. Si el elemento objetivo deja de ser apto, simplemente no se emitirán nuevos fotogramas en el segmento hasta que el elemento objetivo vuelva a ser apto para la restricción.

Navegadores compatibles

La función Element Capture está disponible a partir de Chrome 132 solo en computadoras de escritorio.

Seguridad y privacidad

Para comprender las compensaciones de seguridad, consulta la sección Consideraciones sobre la privacidad y la seguridad de la especificación de Element Capture.

El navegador Chrome dibuja un borde azul alrededor de los bordes de las pestañas capturadas.

Demostración

Puedes probar Element Capture ejecutando la demostración.

Comentarios

El equipo de Chrome y la comunidad de estándares web quieren conocer tu experiencia con Element Capture.

Cuéntanos sobre el diseño

¿Hay algo sobre Element Capture que no funciona como esperabas? ¿O faltan métodos o propiedades que necesitas para implementar tu idea? ¿Tienes alguna pregunta o comentario sobre el modelo de seguridad?

  • Informa un problema de especificación en el repositorio de GitHub o agrega tu opinión a un problema existente.

¿Tienes problemas con la implementación?

¿Encontraste un error en la implementación de Chrome? ¿O la implementación es diferente de la especificación?

Reconocimientos

Foto de Paul Skorupskas en Unsplash