Análise detalhada: VideoNG

Dale Curtis
Dale Curtis

Meu nome é Dale Curtis, e sou líder de engenharia de reprodução de mídia no Chromium. Minha equipe é responsável pelas APIs da Web para reprodução de vídeo, como MSE e WebCodecs, e os recursos internos específicos da plataforma envolvidos na demuxagem, decodificação e renderização de áudio e vídeo.

Neste artigo, vamos explicar a arquitetura de renderização de vídeo do Chromium. Embora alguns detalhes sobre a extensibilidade sejam específicos do Chromium, a maioria dos conceitos e designs discutidos aqui se aplicam a outros mecanismos de renderização e até mesmo a apps de reprodução nativos.

A arquitetura de reprodução do Chromium mudou significativamente ao longo dos 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 início, a renderização de vídeo era bem simples: apenas um laço for escolhendo quais frames de vídeo decodificados pelo software seriam enviados ao compositor. Por anos, isso foi confiável o suficiente, mas, à medida que a complexidade da Web aumentou, a necessidade de mais desempenho e eficiência levou a mudanças na arquitetura. Muitas melhorias exigiam primitivas específicas do SO. Por isso, nossa arquitetura também precisava 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ídeo pode ser dividida em duas etapas: escolher o que entregar e entregar essas informações de maneira eficiente. Para facilitar a leitura, vou abordar a entrega eficiente antes de mergulhar em como o Chromium escolhe o que entregar.

Alguns termos e layout

Como este artigo se concentra na renderização, vou abordar brevemente os aspectos de demuxing e de decodificação do pipeline.

Bytes que entram e pacotes estruturados que saem.

A decodificação e a demuxagem no nosso mundo moderno, que se preocupa com a segurança, exigem um pouco de cuidado. Os analisadores binários são ambientes de destino ricos, e a reprodução de mídia está cheia de análise binária. Por isso, problemas de segurança em analisadores de mídia são extremamente comuns.

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

Os sandboxes do Chromium para o renderizador, a GPU e os processos de áudio.

O mecanismo de comunicação entre processos do Chromium é chamado de Mojo. Não vamos entrar em detalhes sobre o Mojo neste artigo, mas, como a camada de abstração entre processos, ele é uma das bases do pipeline de mídia extensível do Chromium. É importante estar ciente disso ao percorrer o pipeline de reprodução, porque ele informa a orquestração complexa de componentes entre processos que interagem para receber, demuxar, decodificar e, por fim, mostrar mídia.

Muitos bits

Para entender os pipelines de renderização de vídeo atuais, é preciso saber por que o vídeo é especial: largura de banda. A reprodução com resolução de 3840 x 2160 (4K) a 60 quadros por segundo usa entre 9 e 12 gigabits/segundo de largura de banda de memória. Embora os sistemas modernos tenham uma largura de banda máxima de centenas de gigabits por segundo, a reprodução de vídeo ainda representa uma parte substancial. Sem cuidado, a largura de banda total pode se multiplicar facilmente 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 com eficiência em mente é minimizar a largura de banda entre o decodificador e a etapa de renderização final. Por esse motivo, a renderização de vídeo é amplamente desvinculada do pipeline principal de renderização do Chromium. Especificamente, do ponto de vista do nosso 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 Viz.

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

Devido à popularidade da computação para dispositivos móveis, a potência e a eficiência se tornaram um foco importante 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, resultando em um vídeo que parece um buraco com opacidade, até mesmo para o SO. Os decodificadores no nível da plataforma geralmente fornecem apenas buffers opacos que o Chromium transmite 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 "Vídeo aqui", envolvida por uma caixa que representa o sistema operacional.

Cada plataforma tem uma forma de sobreposição com que as APIs de decodificação da plataforma funcionam em conjunto. O Windows tem Composição direta e Transformações da Media Foundation, o macOS tem Camadas de animação do Core 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 para a memória do sistema, portanto, eles nem precisam ser opacos e não consomem largura de banda até serem acessados. O Chromium chama esses GpuMemoryBuffers. No Windows, elas são apoiadas por buffers DXGI, no macOS IOSurfaces, no Android AHardwareBuffers e no Linux buffers DMA. Embora a reprodução de vídeo geralmente não precise desse acesso, esses buffers são importantes para a captura de vídeo para garantir a largura de banda mínima entre o dispositivo de captura e os codificadores.

Diagrama dos buffers mencionados no texto anterior.

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

Quanto mais aproveitarmos as primitivas do SO, como sobreposições e buffers de GPU, menos largura de banda será usada para embaralhar bytes de vídeo desnecessariamente. Manter tudo em um só lugar, da decodificação até a renderização, pode levar a uma eficiência de energia incrível. Por exemplo, quando o Chromium ativou 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 são de tela cheia, economizando até 50% em quase todos os lugares.

Renderização

Agora que abordamos os mecanismos de entrega ideais, vamos 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 na pilha solicita as entradas do componente abaixo em ordem hierárquica. Na parte de cima da pilha, está a renderização de frames de áudio e vídeo. A próxima camada é a decodificação, seguida pela demuxagem 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 (cada atualização da tela), o renderizador de vídeo é solicitado a fornecer um frame de vídeo por um CompositorFrameSink anexado à SurfaceLayer mencionada anteriormente. Para conteúdo com uma taxa de frames menor que a taxa de exibição, isso significa mostrar o mesmo frame mais de uma vez. Já se a taxa de frames for maior que a taxa de exibição, alguns frames nunca serão mostrados.

Sincronizar áudio e vídeo de uma forma agradável para os espectadores é muito mais do que isso. Consulte o Project Butter para mais informações sobre como a fluidez ideal do vídeo é alcançada no Chromium. Ele explica como a renderização de vídeo pode ser dividida em sequências ideais que representam quantas vezes cada frame precisa ser mostrado. 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 abrange vários frames e intervalos de exibição distintos. Quanto mais um renderizador de vídeo se aproximar desse padrão ideal, maior será a probabilidade de um usuário perceber uma reprodução como suave.

A sequência de demuxagem, decodificação e renderização.

Embora a maioria das plataformas do Chromium renderize frame por frame, nem todas fazem isso. 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 do 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?

Focamos em como o Chromium aproveita as primitivas do SO para oferecer a melhor experiência de reprodução. Mas e os sites que querem ir além da reprodução básica de vídeo? Podemos oferecer a eles as mesmas primitivas poderosas que o próprio Chromium usa para dar início à próxima geração de conteúdo da Web?

Acreditamos que a resposta é sim. A extensibilidade é o centro da nossa visão sobre a plataforma da Web atualmente. Temos trabalhado com outros navegadores e desenvolvedores para criar novas tecnologias, como WebGPU e WebCodecs, para que os desenvolvedores da Web possam usar as mesmas primitivas que o Chromium usa ao se comunicar com o SO. A WebGPU oferece suporte a buffers de GPU e o WebCodecs oferece primitivas de decodificação e codificação de plataforma compatíveis com os sistemas de buffer de GPU e sobreposição mencionados.

Relação entre WebCodecs e WebGPU.

Fim da transmissão

Agradecemos por ler. Esperamos que você tenha entendido melhor os sistemas de reprodução modernos e como o Chromium gera centenas de milhões de horas de exibição todos os dias. Se você quiser ler mais sobre codecs e vídeos da Web modernos, recomendamos H.264 is magic (link em inglês) de Sid Bala, How Modern Video Players Work (link em inglês) de Erica Beaves e Packaging award-winning shows with award-winning technology (link em inglês) de Cyril Concolato.

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