Análise detalhada: VideoNG

Dale Curtis
Dale Curtis

Sou Dale Curtis, o chefe de engenharia para reprodução de mídia no Chromium. Minha equipe é responsável pelas APIs voltadas para a Web para reprodução de vídeo, como MSE e WebCodecs, e pelos componentes internos específicos da plataforma envolvidos na demuxing, decodificação e renderização de áudio e vídeo.

Neste artigo, você aprenderá sobre a arquitetura de renderização de vídeos do Chromium. Embora alguns detalhes sobre a extensibilidade sejam provavelmente específicos do Chromium, a maioria dos conceitos e designs discutidos aqui se aplica a outros mecanismos de renderização e até mesmo a apps de reprodução nativos.

A arquitetura de reprodução do Chromium mudou significativamente com os anos. Embora não tenhamos começado com a ideia de uma pirâmide de sucesso, conforme descrito na primeira postagem desta série, seguimos etapas semelhantes: confiabilidade, desempenho e extensibilidade.

No começo, a renderização de vídeos era bastante simples: apenas um loop "for" para escolher quais softwares decodificados os frames de vídeo seriam enviados ao compositor. Por anos, isso foi confiável o suficiente, mas, à medida que a complexidade da Web aumentava, a necessidade de mais desempenho e eficiência levou a mudanças na arquitetura. Muitas melhorias exigiram primitivos específicos do SO. Assim, nossa arquitetura também precisou se tornar mais extensível para alcançar todas as plataformas do Chromium.

Diagrama do fluxo de renderização para diferentes plataformas do Chromium.

A renderização de vídeos pode ser dividida em duas etapas: escolher o que exibir e enviar essas informações com eficiência. Para facilitar a leitura, vou abordar a entrega eficiente antes de explicar como o Chromium escolhe o que entregar.

Alguns termos e layout

Como o foco deste artigo é a renderização, vou falar brevemente sobre os aspectos de de multiplexação e decodificação do pipeline.

Bytes saindo e pacotes estruturados fluindo.

Decodificar e remover a multiplexação no nosso mundo moderno preocupado com a segurança requer muito cuidado. Analisadores binários são ambientes de destino avançados e a reprodução de mídia está repleta de análises binárias. Assim, problemas de segurança em analisadores de mídia são extremamente comuns.

O Chromium adota uma defesa em profundidade para reduzir o risco de problemas de segurança para nossos usuários. Em termos práticos, isso significa que a demuxing e a decodificação de software sempre acontecem em um processo de baixo privilégio, enquanto a decodificação de hardware ocorre em um processo com privilégios apenas suficientes para se comunicar com a GPU do sistema.

As sandboxes do Chromium para os processos de renderizador, GPU e áudio.

O mecanismo de comunicação entre processos do Chromium é chamado de Mojo. Embora não entremos em detalhes sobre o Mojo neste artigo, como a camada de abstração entre processos, ele é um dos pilares do pipeline de mídia extensível do Chromium. É importante estar ciente disso à medida que analisamos o pipeline de reprodução, já que ele informa a orquestração complexa de componentes de processo cruzado que interagem para receber, decodificar, decodificar e, por fim, exibir mídia.

Muitos bits

Para entender os pipelines de renderização de vídeo atuais, é preciso saber por que o vídeo é especial: a largura de banda. Uma reprodução com resolução de 3.840 x 2.160 (4K) a 60 quadros por segundo usa de 9 a 12 gigabits/segundo de largura de banda de memória. Embora os sistemas modernos possam ter um pico de largura de banda em centenas de gigabits por segundo, a reprodução de vídeo ainda representa uma parte significativa. Sem cuidado, a largura de banda total pode facilmente multiplicar-se devido a cópias ou viagens entre a GPU e a memória da CPU.

O objetivo de qualquer mecanismo moderno de reprodução de vídeo que priorize a eficiência é minimizar a largura de banda entre o decodificador e a etapa de renderização final. Por esse motivo, a renderização de vídeos é amplamente dissociada do pipeline de renderização principal do Chromium. Especificamente, da perspectiva do pipeline de renderização principal, o vídeo é apenas um buraco de tamanho fixo com opacidade. O Chromium faz isso usando um conceito chamado superfícies, em que cada vídeo se comunica diretamente com a Viz.

Uma página da Web com um buraco e uma seta dizendo "O vídeo vai aqui".

Devido à popularidade da computação móvel, a energia e a eficiência se tornaram um foco significativo na geração atual. Como resultado, a decodificação e a renderização estão mais acopladas do que nunca no nível do hardware, fazendo com que o vídeo pareça um buraco com opacidade, até mesmo para o próprio SO. Os decodificadores no nível da plataforma geralmente fornecem apenas buffers opacos que o Chromium passa para o sistema de composição no nível da plataforma na forma de sobreposições.

Uma página da Web com um buraco e uma seta dizendo "O vídeo vai aqui", dentro de uma caixa que representa o sistema operacional.

Cada plataforma tem sua própria forma de sobreposição, com as quais as APIs de decodificação da plataforma funcionam em conjunto. O Windows tem Direct Composition e Media Foundation Transforms, o macOS tem CoreAnimation Layers e VideoToolbox, o Android tem SurfaceView e MediaCodec, e o Linux tem VASurfaces e VA-API. As abstrações do Chromium para esses conceitos são processadas pelas interfaces OverlayProcessor e mojo::VideoDecoder, respectivamente.

Em alguns casos, é possível que esses buffers sejam mapeáveis na memória do sistema. Assim, eles não precisam ser opacos e não consomem nenhuma largura de banda até serem acessados. O Chromium chama esses GpuMemoryBuffers. No Windows, eles são apoiados por buffers DXGI, no IOSurfaces do macOS, no Android AHardwareBuffers e no buffers DMA do Linux. Embora a reprodução de vídeo geralmente não precise desse acesso, esses buffers são importantes para a captura de vídeo, garantindo largura de banda mínima entre o dispositivo de captura e os codificadores finais.

Diagrama dos buffers mencionados no texto anterior.

Como a GPU geralmente é responsável pela decodificação e exibição, o uso desses buffers (também geralmente) opacos garante que os dados de vídeo com alta largura de banda nunca saiam da GPU. Como discutimos anteriormente, armazenar dados na GPU é extremamente importante para a eficiência, especialmente em altas resoluções e frame rates.

Quanto mais podemos aproveitar os primitivos do SO, como sobreposições e buffers de GPU, menos largura de banda será gasta em ordem aleatória de bytes de vídeo desnecessariamente. Manter tudo em um só lugar, desde a decodificação até a renderização, pode levar a uma incrível eficiência de energia. Por exemplo, quando o Chromium ativou as sobreposições no macOS, o consumo de energia durante a reprodução de vídeo em tela cheia foi reduzido pela metade. Em outras plataformas, como Windows, Android e ChromeOS, é possível usar sobreposições mesmo em casos que não sejam de tela cheia, economizando até 50% em praticamente qualquer lugar.

Renderização

Agora que abordamos os mecanismos de entrega ideais, podemos discutir como o Chromium escolhe o que entregar. A pilha de reprodução do Chromium usa uma arquitetura baseada em "pull", ou seja, cada componente da pilha solicita as entradas dele daquele que está abaixo dele em ordem hierárquica. No topo da pilha está a renderização de frames de áudio e vídeo, depois, está a decodificação, seguida pela desmuxação e, por fim, a E/S. Cada frame de áudio renderizado avança um relógio, que é usado para escolher frames de vídeo para renderização quando combinado com um intervalo de apresentação.

Em cada intervalo de apresentação (a cada atualização da tela), o renderizador de vídeo é solicitado a fornecer um frame de vídeo por um CompositorFrameSink anexado à SurfaceLayer mencionado anteriormente. Para conteúdo com frame rate menor do que o de exibição, isso significa mostrar o mesmo frame mais de uma vez. Se ele for maior que o valor, alguns frames nunca serão mostrados.

Há muito mais para sincronizar áudio e vídeo de maneiras agradáveis aos espectadores. Consulte Project Butter para ver uma discussão mais longa sobre como a suavidade de vídeo ideal é alcançada no Chromium. Ela explica como a renderização de vídeo pode ser dividida em sequências ideais que representam quantas vezes cada frame deve ser exibido. Por exemplo: "1 frame a cada intervalo de exibição ([1], 60 QPS em 60 Hz)", "1 frame a cada 2 intervalos ([2], 30 QPS em 60 Hz)" ou padrões mais complicados, como [2:3:2:3:2] (25 QPS em 60 Hz) que cobre vários frames distintos e intervalos de 60 Hz. Quanto mais próximo um renderizador de vídeo aderir a esse padrão ideal, maior será a probabilidade de o usuário perceber uma reprodução como sendo suave.

É a sequência de demuxing, decodificação e renderização.

Embora a maioria das plataformas do Chromium renderize frame a frame, nem todas fazem. Nossa arquitetura extensível também permite a renderização em lote. A renderização em lote é uma técnica de eficiência em que o compositor no nível do SO é informado sobre vários frames com antecedência e processa o lançamento deles em uma programação de tempo fornecida pelo aplicativo.

O futuro é agora?

Nos concentramos em como o Chromium aproveita os primitivos do SO para oferecer a melhor experiência de reprodução da categoria. Mas e os sites que querem ir além da reprodução básica de vídeo? Podemos oferecer a eles os mesmos primitivos poderosos que o próprio Chromium usa para liderar a próxima geração de conteúdo da Web?

Acreditamos que a resposta é sim. A extensibilidade é o foco da nossa forma de pensar na plataforma da Web atualmente. Estamos trabalhando com outros navegadores e desenvolvedores para criar novas tecnologias, como WebGPU e WebCodecs, para que os desenvolvedores da Web possam usar os mesmos primitivos que o Chromium usa ao falar com o SO. A WebGPU oferece suporte a buffers de GPU, e o WebCodecs oferece primitivos de decodificação e codificação de plataforma compatíveis com os sistemas de buffer de GPU e sobreposição mencionados acima.

Relação entre WebCodecs e WebGPU.

Fim da transmissão

Agradecemos por ler. Espero que você tenha aprendido melhor sobre os sistemas modernos de reprodução e como o Chromium gera centenas de milhões de horas de exibição todos os dias. Se você estiver procurando mais informações sobre codecs e vídeos modernos da Web, recomendo H.264 is magic, de Sid Bala, How Modern Video Players Work, de Erica Beaves, e Empacotando programas premiados com tecnologia premiada de Cyril Concolato.

Uma ilustração (a mais bonita) de Una Kravets.