Análisis detallado: VideoNG

Dale Curtis
Dale Curtis

Soy Dale Curtis, director de Ingeniería de la reproducción de contenido multimedia en Chromium. Mi equipo es responsable de las APIs web para la reproducción de video, como MSE y WebCodecs, y de los elementos internos específicos de la plataforma involucrados en la demuxificación, decodificación y renderización de audio y video.

En este artículo, te explicaré la arquitectura de renderización de video de Chromium. Si bien es probable que algunos detalles sobre la extensibilidad sean específicos de Chromium, la mayoría de los conceptos y diseños que se analizan aquí se aplican a otros motores de renderización y hasta a apps de reproducción nativas.

La arquitectura de reproducción de Chromium cambió significativamente con los años. Si bien no comenzamos con la idea de una pirámide del éxito, como se describe en la primera publicación de esta serie, en última instancia, seguimos pasos similares: confiabilidad, rendimiento y, luego, extensibilidad.

En el principio, la renderización de video era bastante simple: solo un bucle for que elegía qué software decodificaba los fotogramas de video para enviarlos al compositor. Durante años, esto fue lo suficientemente confiable, pero a medida que aumentó la complejidad de la Web, la necesidad de más rendimiento y eficiencia llevó a cambios arquitectónicos. Muchas mejoras requerían primitivas específicas del SO, por lo que nuestra arquitectura también tuvo que volverse más extensible para llegar a todas las plataformas de Chromium.

Diagrama del flujo de renderización a diferentes plataformas de Chromium.

La renderización de video se puede dividir en dos pasos: elegir qué entregar y entregar esa información de manera eficiente. Para facilitar la lectura, hablaré sobre la entrega eficiente antes de explicar cómo Chromium elige qué entregar.

Algunos términos y diseño

Como este artículo se enfoca en la renderización, solo mencionaré brevemente los aspectos de demuxificación y decodificación de la canalización.

Bytes que ingresan y paquetes estructurados que salen.

La decodificación y demuxificación en nuestro mundo moderno y consciente de la seguridad requiere bastante cuidado. Los analizadores binarios son entornos de destino enriquecidos, y la reproducción de contenido multimedia está llena de análisis binario. Por lo tanto, los problemas de seguridad en los analizadores de contenido multimedia son muy comunes.

Chromium practica la defensa en profundidad para reducir el riesgo de problemas de seguridad para nuestros usuarios. En términos prácticos, esto significa que la demuxificación y la decodificación de software siempre se realizan en un proceso de privilegios bajos, mientras que la decodificación de hardware se produce en un proceso con privilegios suficientes para comunicarse con la GPU del sistema.

Las zonas de pruebas de Chromium para el renderizador, la GPU y los procesos de audio

El mecanismo de comunicación entre procesos de Chromium se llama Mojo. Si bien no entraremos en detalles sobre Mojo en este artículo, como la capa de abstracción entre procesos, es un elemento fundamental de la canalización de medios extensible de Chromium. Es importante tener en cuenta esto a medida que recorremos la canalización de reproducción, ya que informa la orquestación compleja de componentes de procesos cruzados que interactúan para recibir, demux, decodificar y, finalmente, mostrar contenido multimedia.

Muchos bits

Para comprender las canalización de renderización de video actuales, es necesario saber por qué el video es especial: el ancho de banda. Una reproducción con una resolución de 3840 × 2160 (4K) a 60 fotogramas por segundo usa entre 9 y 12 gigabits por segundo de ancho de banda de memoria. Si bien los sistemas modernos pueden tener una gran cantidad de ancho de banda en cientos de gigabits por segundo, la reproducción de video sigue representando una parte sustancial. Si no se tiene cuidado, el ancho de banda total se puede multiplicar fácilmente debido a las copias o los viajes entre la memoria de la GPU y la CPU.

El objetivo de cualquier motor de reproducción de video moderno que tenga en cuenta la eficiencia es minimizar el ancho de banda entre el decodificador y el paso de renderización final. Por este motivo, la renderización de video está muy desacoplada de la canalización de renderización principal de Chromium. Específicamente, desde la perspectiva de nuestra canalización de renderización principal, el video es solo un orificio de tamaño fijo con opacidad. Chromium logra esto con un concepto llamado superficies, en el que cada video se comunica directamente con Viz.

Una página web con un espacio y una flecha que dice "Video goes here".

Debido a la popularidad de la computación móvil, la potencia y la eficiencia se han convertido en un enfoque importante en la generación actual. Como resultado, la decodificación y la renderización están más acopladas que nunca a nivel del hardware, lo que hace que el video se vea como un agujero con opacidad, incluso para el SO. Los decodificadores a nivel de la plataforma a menudo solo proporcionan búferes opacos que Chromium pasa al sistema de composición a nivel de la plataforma en forma de superposiciones.

Una página web con un agujero y una flecha que dice “Video goes here”, rodeado por un cuadro que representa el sistema operativo.

Cada plataforma tiene su propia forma de superposiciones con las que funcionan en conjunto sus APIs de decodificación de la plataforma. Windows tiene Composición directa y Transformaciones de Media Foundation, macOS tiene Capas de CoreAnimation y VideoToolbox, Android tiene SurfaceView y MediaCodec, y Linux tiene VASurfaces y VA-API. Las abstracciones de Chromium para estos conceptos se controlan a través de las interfaces OverlayProcessor y mojo::VideoDecoder, respectivamente.

En algunos casos, es posible que estos búferes se puedan asignar a la memoria del sistema, por lo que ni siquiera es necesario que sean opacos y no consumen ancho de banda hasta que se accede a ellos. Chromium los llama GpuMemoryBuffers. En Windows, están respaldados por buffers de DXGI, en macOS por IOSurfaces, en Android por AHardwareBuffers y en Linux por buffers de DMA. Si bien, en general, la reproducción de video no necesita este acceso, estos búferes son importantes para la captura de video, ya que garantizan un ancho de banda mínimo entre el dispositivo de captura y los posibles codificadores.

Diagrama de los búferes mencionados en el texto anterior.

Dado que la GPU suele ser responsable de la decodificación y la visualización, el uso de estos búferes opacos (también a menudo) garantiza que los datos de video de alta velocidad de banda nunca salgan de la GPU. Como mencionamos antes, mantener los datos en la GPU es increíblemente importante para la eficiencia, especialmente en resoluciones y velocidades de fotogramas altas.

Cuanto más podamos aprovechar las primitivas del SO, como las superposiciones y los búferes de GPU, menos ancho de banda se usará para mover bytes de video de forma innecesaria. Mantener todo en un solo lugar, desde la decodificación hasta la renderización, puede generar una eficiencia energética increíble. Por ejemplo, cuando Chromium habilitó las superposiciones en macOS, el consumo de energía durante la reproducción de video en pantalla completa se redujo a la mitad. En otras plataformas, como Windows, Android y ChromeOS, podemos usar superposiciones incluso en casos que no son de pantalla completa, lo que ahorra hasta un 50% en casi todas partes.

Renderización

Ahora que cubrimos los mecanismos de entrega óptimos, podemos analizar cómo Chromium elige qué entregar. La pila de reproducción de Chromium usa una arquitectura basada en "extracción", lo que significa que cada componente de la pila solicita sus entradas al que está debajo en orden jerárquico. En la parte superior de la pila, se encuentra la renderización de fotogramas de audio y video, en el siguiente nivel inferior, la decodificación, seguida de la demuxificación y, por último, la E/S. Cada fotograma de audio renderizado avanza un reloj que se usa para elegir fotogramas de video para la renderización cuando se combina con un intervalo de presentación.

En cada intervalo de presentación (cada actualización de la pantalla), se le solicita al renderizador de video que proporcione un fotograma de video a través de un CompositorFrameSink conectado a la SurfaceLayer mencionada anteriormente. En el caso del contenido con una tasa de fotogramas inferior a la tasa de visualización, se muestra el mismo fotograma más de una vez. Por el contrario, si la tasa de fotogramas es mayor que la tasa de visualización, algunos fotogramas nunca se muestran.

Sincronizar audio y video de manera que sea agradable para los usuarios es mucho más que eso. Consulta Project Butter para obtener una explicación más detallada sobre cómo se logra la fluidez óptima de los videos en Chromium. Explica cómo la renderización de video se puede desglosar en secuencias ideales que representan cuántas veces se debe mostrar cada fotograma. Por ejemplo: "1 fotograma por intervalo de visualización ([1], 60 fps en 60 Hz)", "1 fotograma por 2 intervalos ([2], 30 fps en 60 Hz)", o patrones más complicados, como [2:3:2:3:2] (25 fps en 60 Hz) que cubren varios fotogramas y intervalos de visualización distintos. Cuanto más se adapte un renderizador de video a este patrón ideal, es más probable que un usuario perciba una reproducción fluida.

Es la secuencia de demuxificación, decodificación y renderización.

Si bien la mayoría de las plataformas de Chromium renderizan fotograma por fotograma, no todas lo hacen. Nuestra arquitectura extensible también permite la renderización por lotes. La renderización por lotes es una técnica de eficiencia en la que se le informa al compositor a nivel del SO sobre varios fotogramas con anticipación y se controla su lanzamiento en un programa de tiempo proporcionado por la aplicación.

¿El futuro es ahora?

Nos enfocamos en cómo Chromium aprovecha las primitivas del SO para ofrecer una experiencia de reproducción de primer nivel. Pero ¿qué sucede con los sitios web que quieren ir más allá de la reproducción de video básica? ¿Podemos ofrecerles las mismas primitivas potentes que usa Chromium para presentar la próxima generación de contenido web?

Creemos que la respuesta es sí. La extensibilidad es fundamental en la forma en que pensamos en la plataforma web en la actualidad. Hemos estado trabajando con otros navegadores y desarrolladores para crear nuevas tecnologías, como WebGPU y WebCodecs, de modo que los desarrolladores web puedan usar las mismas primitivas que Chromium cuando se comunica con el SO. WebGPU admite buffers de GPU, y WebCodecs ofrece primitivas de decodificación y codificación de plataformas compatibles con los sistemas de superposición y búfer de GPU mencionados anteriormente.

Relación entre WebCodecs y WebGPU.

Fin de la transmisión

¡Gracias por leer esta información! Espero que hayas comprendido mejor los sistemas de reproducción modernos y cómo Chromium potencia cientos de millones de horas de reproducción todos los días. Si quieres obtener más información sobre los códecs y los videos web modernos, te recomiendo H.264 is magic de Sid Bala, How Modern Video Players Work de Erica Beaves y Packaging award-winning shows with award-winning technology de Cyril Concolato.

Una ilustración (la bonita) de Una Kravets.