Análisis detallado: VideoNG

Dale Curtis
Dale Curtis

Soy Dale Curtis, jefe de ingeniería de reproducción de contenido multimedia en Chromium. Mi equipo es responsable de las APIs orientadas a la Web para la reproducción de video, como MSE y WebCodecs, y de las partes internas específicas de la plataforma que se usan en la depuración, la decodificación y el procesamiento de audio y video.

En este artículo, te explicaré la arquitectura de renderización de videos 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 e incluso a apps de reproducción nativas.

La arquitectura de reproducción de Chromium ha cambiado significativamente a lo largo de los años. Si bien no empezamos 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.

Al principio, el procesamiento de video era bastante simple: solo un bucle for eligiendo qué fotogramas de video decodificaban por software para enviar al compositor. Durante años, esto fue bastante confiable, pero a medida que aumentaba la complejidad de la Web, la necesidad de un mayor rendimiento y eficiencia dio lugar a cambios arquitectónicos. Muchas mejoras requerían primitivas específicas del SO. Por lo tanto, 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.

El procesamiento de video se puede dividir en dos pasos: elegir qué entregar y entregar esa información de manera eficiente. Para facilitar la lectura, abordaremos la entrega eficiente antes de sumergirnos en cómo Chromium elige qué entregar.

Algunos términos y diseño

Dado que este artículo se enfoca en la renderización, solo abordaré brevemente los aspectos de demuxe y decodificación de la canalización.

Bytes que entran y paquetes estructurados que salen.

En un mundo moderno consciente de la seguridad, se requiere un poco de cuidado para la decodificación y la demuxe. Los analizadores binarios son entornos de destino enriquecidos y la reproducción de contenido multimedia está llena de análisis de objetos binarios. Por lo tanto, los problemas de seguridad en los analizadores de medios son extremadamente comunes.

Chromium implementa una defensa en profundidad para reducir el riesgo de que los usuarios tengan problemas de seguridad. En términos prácticos, esto significa que la depuración y la decodificación de software siempre ocurren en un proceso de privilegios bajos, mientras que la decodificación de hardware ocurre en un proceso con los privilegios suficientes para comunicarse con la GPU del sistema.

Las zonas de pruebas de Chromium para los procesos de renderizado, GPU y audio

El mecanismo de comunicación entre procesos de Chromium se denomina Mojo. Si bien no entraremos en detalles en este artículo, como capa de abstracción entre procesos, es una pieza fundamental de la canalización de medios extensible de Chromium. Es importante tener esto en cuenta cuando exploramos la canalización de reproducción, ya que informa a la organización compleja de los componentes del proceso cruzado que interactúan para recibir, demuxir, decodificar y, por último, mostrar contenido multimedia.

Muchos bits

Para comprender las canalizaciones de procesamiento de video actuales, es necesario conocer por qué el video es especial: el ancho de banda. Una reproducción con resolución de 3,840 × 2,160 (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 un ancho de banda máximo de cientos de gigabits por segundo, la reproducción de video representa una parte sustancial. Sin cuidado, el ancho de banda total se puede multiplicar fácilmente debido a las copias o los viajes entre la GPU y la memoria de la CPU.

El objetivo de cualquier motor de reproducción de video moderno teniendo en cuenta la eficiencia es minimizar el ancho de banda entre el decodificador y el paso final de renderización. Por esta razón, el procesamiento de video está desvinculado en gran medida de la canalización de procesamiento principal de Chromium. Específicamente, desde la perspectiva de nuestra canalización de renderización principal, el video es solo un agujero de tamaño fijo con opacidad. Chromium lo logra mediante un concepto llamado superficies, en el que cada video se comunica directamente con la visualización.

Una página web con un agujero y una flecha que dice "Aquí va el video".

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 de esto, la decodificación y la renderización están más vinculadas que nunca a nivel del hardware, lo que hace que los videos parezcan un agujero con opacidad, incluso para el propio SO. Los decodificadores a nivel de la plataforma a menudo solo proporcionan búferes opacos que Chromium pasa por el 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 va aquí", envuelta en 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 plataformas. Windows tiene composición directa y Media Foundation Transforms, 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 mediante las interfaces de 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 no es necesario que sean opacos y no consuman ancho de banda hasta que se acceda a ellos. Chromium llama a estos GpuMemoryBuffers. En Windows, están respaldados por búferes DXGI, en macOS IOSurfaces, en AHardwareBuffers y en los búferes DMA de Linux. Si bien la reproducción de video no suele necesitar este acceso, estos búferes son importantes para la captura de video a fin de garantizar un ancho de banda mínimo entre el dispositivo de captura y los eventuales 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 con ancho de banda alto nunca salgan de la GPU. Como se mencionó antes, conservar los datos en la GPU es increíblemente importante para la eficiencia, en especial con altas resoluciones y velocidades de fotogramas.

Cuanto más podamos aprovechar las primitivas del SO, como las superposiciones y los búferes de la GPU, menos ancho de banda se invertirá en redistribución de bytes de video innecesariamente. Mantener todo en un solo lugar, desde la decodificación hasta la renderización, puede lograr 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 permite ahorrar hasta un 50% en casi todos los casos.

Renderización

Ahora que analizamos 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 a la 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 la parte inferior de la pila, se encuentra la decodificación, seguida de demux y, por último, E/S. Cada fotograma de audio renderizado hace avanzar un reloj que se usa para elegir los fotogramas de video que se renderizará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 procesador de video que proporcione un fotograma mediante un CompositorFrameSink adjunto a la SurfaceLayer que se mencionó anteriormente. Para el contenido con una velocidad de fotogramas inferior a la velocidad de visualización, eso significa que se muestra el mismo fotograma más de una vez, mientras que, si la velocidad es superior a la de visualización, algunos fotogramas nunca se muestran.

Hay mucho más para sincronizar audio y video de una manera que resulte agradable para los espectadores. Consulta Project Butter para obtener un análisis más extenso sobre cómo se logra una fluidez óptima de los videos en Chromium. Explica cómo se puede dividir la renderización de videos en secuencias ideales que representan la cantidad de veces que se debe mostrar cada fotograma. Por ejemplo: "1 fotograma por intervalo de visualización ([1], 60 FPS en 60 Hz)", "1 fotograma cada 2 intervalos ([2], 30 FPS en 60 Hz)" o patrones más complicados, como [2:3:2:3:2] (25 FPS a 60 Hz) que abarcan intervalos de varios fotogramas y pantallas distintos. Cuanto más cerca se adhiera un procesador de video a este patrón ideal, más probabilidades tendrá de que un usuario perciba que una reproducción es fluida.

Es la secuencia de demuxing, 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 el procesamiento por lotes. La renderización en lotes es una técnica eficiente en la que se informa al compositor de nivel del SO sobre varios fotogramas por adelantado y 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 brindar una experiencia de reproducción de primer nivel. Pero ¿qué pasa con los sitios web que quieren ir más allá de la reproducción básica de videos? ¿Podemos ofrecerles las mismas potentes primitivas que Chromium usa para abrir la nueva generación de contenido web?

Creemos que la respuesta es sí. En la actualidad, la extensibilidad es el centro de nuestra forma de concebir la plataforma web. Trabajamos con otros navegadores y desarrolladores para crear nuevas tecnologías, como WebGPU y WebCodecs, a fin de que los desarrolladores web puedan usar las mismas primitivas que usa Chromium cuando se comunica con el SO. WebGPU es compatible con búferes de GPU, y WebCodecs ofrece decodificación y codificación primitivas compatibles con los sistemas de búfer de GPU y superposición 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 brinda varios cientos de millones de horas de tiempo de reproducción todos los días. Si deseas obtener más información sobre códecs y videos web modernos, te recomiendo H.264 is Wizard de Sid Bala, How Modern Video Players Work de Erica Beaves y Empaqueta programas galardonados con tecnología galardonada de Cyril Concolato.

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