Transmisiones insertables para MediaStreamTrack

El contenido de un MediaStreamTrack se expone como una transmisión que se puede manipular o usar para generar contenido nuevo

Segundo plano

En el contexto de la API de Media Capture and Streams, la interfaz MediaStreamTrack representa una sola pista multimedia dentro de una transmisión. Por lo general, estas son pistas de audio o video, pero pueden existir otros tipos de pistas. Los objetos MediaStream constan de cero o más objetos MediaStreamTrack que representan varias pistas de audio o video. Cada MediaStreamTrack puede tener uno o más canales. El canal representa la unidad más pequeña de una transmisión de contenido multimedia, como una señal de audio asociada a un altavoz determinado, como izquierda o derecha en una pista de audio estéreo.

¿Qué son las transmisiones insertables para MediaStreamTrack?

La idea principal detrás de las transmisiones insertables para MediaStreamTrack es exponer el contenido de un MediaStreamTrack como una colección de transmisiones (como se define en la API de Streams de WHATWG). Estos flujos se pueden manipular para agregar nuevos componentes.

Si les otorgas a los desarrolladores acceso directo a la transmisión de video (o audio), podrán aplicar modificaciones directamente a la transmisión. Por el contrario, realizar la misma tarea de manipulación de video con métodos tradicionales requiere que los desarrolladores usen intermediarios, como elementos <canvas>. (Para obtener detalles sobre este tipo de proceso, consulta, por ejemplo, video + lienzo = magia).

Navegadores compatibles

Las transmisiones insertables para MediaStreamTrack son compatibles a partir de Chrome 94.

Casos de uso

Estos son algunos casos de uso de las transmisiones insertables de MediaStreamTrack:

  • Gadgets de videoconferencia, como "sombreros divertidos" o fondos virtuales
  • Procesamiento de voz, como vocoders de software

Cómo usar flujos insertables para MediaStreamTrack

Detección de funciones

Puedes detectar funciones de transmisiones insertables para la compatibilidad con MediaStreamTrack de la siguiente manera.

if ('MediaStreamTrackProcessor' in window && 'MediaStreamTrackGenerator' in window) {
  // Insertable streams for `MediaStreamTrack` is supported.
}

Conceptos básicos

Las transmisiones insertables para MediaStreamTrack se basan en conceptos que WebCodecs propuso anteriormente y dividen conceptualmente el MediaStreamTrack en dos componentes:

  • El MediaStreamTrackProcessor, que consume la fuente de un objeto MediaStreamTrack y genera una transmisión de fotogramas de contenido multimedia, específicamente objetos VideoFrame o AudioFrame. Puedes pensar en esto como un destino de pista que es capaz de exponer los fotogramas sin codificar de la pista como un ReadableStream.
  • El MediaStreamTrackGenerator, que consume una transmisión de marcos multimedia y expone una interfaz MediaStreamTrack Se puede proporcionar a cualquier receptor, como una pista de getUserMedia(). Toma fotogramas multimedia como entrada.

MediaStreamTrackProcessor

Un objeto MediaStreamTrackProcessor expone una propiedad, readable. Permite leer las tramas de MediaStreamTrack. Si la pista es de video, los fragmentos que se lean de readable serán objetos VideoFrame. Si se trata de una pista de audio, los fragmentos leídos de readable serán objetos AudioFrame.

MediaStreamTrackGenerator

Un objeto MediaStreamTrackGenerator también expone una propiedad, writable, que es un WritableStream que permite escribir fotogramas de contenido multimedia en MediaStreamTrackGenerator, que a su vez es un MediaStreamTrack. Si el atributo kind es "audio", la transmisión acepta objetos AudioFrame y falla con cualquier otro tipo. Si kind es "video", la transmisión acepta objetos VideoFrame y falla con cualquier otro tipo. Cuando se escribe un fotograma en writable, se invoca automáticamente el método close() del fotograma, de modo que ya no se puede acceder a sus recursos multimedia desde JavaScript.

Un MediaStreamTrackGenerator es una pista para la que se puede implementar una fuente personalizada escribiendo marcos de medios en su campo writable.

Reúne todo en un solo lugar

La idea principal es crear una cadena de procesamiento de la siguiente manera:

Itinerario de la plataforma → Procesador → Transformación → Generador → Sinks de la plataforma

En el siguiente ejemplo, se ilustra esta cadena para una aplicación de escáner de códigos de barras que destaca el código de barras detectado en una transmisión de video en vivo.

const stream = await getUserMedia({ video: true });
const videoTrack = stream.getVideoTracks()[0];

const trackProcessor = new MediaStreamTrackProcessor({ track: videoTrack });
const trackGenerator = new MediaStreamTrackGenerator({ kind: 'video' });

const transformer = new TransformStream({
  async transform(videoFrame, controller) {
    const barcodes = await detectBarcodes(videoFrame);
    const newFrame = highlightBarcodes(videoFrame, barcodes);
    videoFrame.close();
    controller.enqueue(newFrame);
  },
});

trackProcessor.readable.pipeThrough(transformer).pipeTo(trackGenerator.writable);

const videoBefore = document.getElementById('video-before');
const videoAfter = document.getElementById('video-after');
videoBefore.srcObject = stream;
const streamAfter = new MediaStream([trackGenerator]);
videoAfter.srcObject = streamAfter;

Demostración

Puedes ver la demostración del escáner de códigos QR de la sección anterior en acción en un navegador para computadoras o dispositivos móviles. Sostén un código QR frente a la cámara y la app lo detectará y destacará. Puedes ver el código fuente de la aplicación en Glitch.

Escáner de códigos QR que se ejecuta en la pestaña del navegador para computadoras de escritorio que muestra un código QR detectado y destacado en el teléfono que el usuario sostiene frente a la cámara de la laptop.

Consideraciones de seguridad y privacidad

La seguridad de esta API se basa en mecanismos existentes en la plataforma web. A medida que los datos se exponen con las interfaces VideoFrame y AudioFrame, se aplican las reglas de esas interfaces para controlar los datos contaminados de origen. Por ejemplo, no se puede acceder a los datos de los recursos de origen cruzado debido a las restricciones existentes para acceder a esos recursos (p.ej., no es posible acceder a los píxeles de una imagen o un elemento de video de origen cruzado). Además, el acceso a los datos multimedia desde cámaras, micrófonos o pantallas está sujeto a la autorización del usuario. Los datos multimedia que expone esta API ya están disponibles a través de otras APIs.

Comentarios

El equipo de Chromium quiere conocer tus experiencias con las transmisiones insertables para MediaStreamTrack.

Cuéntanos sobre el diseño de la API

¿Hay algo en la API 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 correspondiente o agrega tus comentarios a un problema existente.

Denuncia un problema con la implementación

¿Encontraste un error con la implementación de Chromium? ¿O la implementación es diferente de la especificación? Informa un error en new.crbug.com. Asegúrate de incluir tantos detalles como sea posible, instrucciones simples para reproducirlo y, luego, ingresa Blink>MediaStream en el cuadro Componentes. Glitch es excelente para compartir reproducciones rápidas y fáciles.

Cómo mostrar compatibilidad con la API

¿Planeas usar transmisiones insertables para MediaStreamTrack? Tu apoyo público ayuda al equipo de Chromium a priorizar las funciones y les muestra a otros proveedores de navegadores lo importante que es admitirlas.

Envía un tweet a @ChromiumDev con el hashtag #InsertableStreams y cuéntanos dónde y cómo lo usas.

Agradecimientos

Harald Alvestrand y Guido Urdaneta escribieron las transmisiones insertables para la especificación MediaStreamTrack. Harald Alvestrand, Joe Medley, Ben Wagner, Huib Kleinhout y François Beaufort revisaron este artículo. Hero image de Chris Montgomery en Unsplash.