Approfondimento: VideoNG

Dale Curtis
Dale Curtis

Sono Dale Curtis, responsabile ingegneristica per la riproduzione di contenuti multimediali in Chromium. Il mio team è responsabile delle API lato web per la riproduzione di video come MSE e WebCodecs, nonché degli interni specifici della piattaforma coinvolti nella demuxing, nella decodifica e nel rendering di audio e video.

In questo articolo illustreremo l'architettura di rendering video di Chromium. Anche se alcuni dettagli sull'estensibilità sono probabilmente specifici di Chromium, la maggior parte dei concetti e dei progetti discussi qui riguarda altri motori di rendering e persino le app di riproduzione native.

L'architettura di riproduzione di Chromium è cambiata in modo significativo nel corso degli anni. Non abbiamo iniziato con l'idea di una piramide di successo come descritto nel primo post di questa serie, ma alla fine abbiamo seguito passaggi simili: affidabilità, prestazioni ed estensibilità.

All'inizio, il rendering video era piuttosto semplice: solo un ciclo for che sceglieva quale software decodificava i frame video da inviare al compositore. Per anni è stato abbastanza affidabile, ma con l'aumento della complessità del web, la necessità di maggiori prestazioni ed efficienza ha portato a cambiamenti dell'architettura. Molti miglioramenti hanno richiesto primitive specifiche del sistema operativo; di conseguenza, la nostra architettura è stata anche più estensibile per raggiungere tutte le piattaforme di Chromium.

Diagramma del flusso di rendering su diverse piattaforme Chromium.

Il rendering video può essere suddiviso in due passaggi: la scelta di cosa fornire e la distribuzione efficiente. Per una migliore leggibilità, parlerò di una pubblicazione efficiente prima di spiegare in che modo Chromium sceglie cosa fornire.

Alcuni termini e layout

Poiché questo articolo è incentrato sul rendering, parlerò solo brevemente degli aspetti di demuxing e decodifica della pipeline.

Byte in entrata e pacchetti strutturati in uscita.

Nel nostro mondo moderno attento alla sicurezza, la decodifica e il demuxing richiedono un certo grado di attenzione. I parser binari sono ambienti di destinazione avanzati e la riproduzione di contenuti multimediali è piena di analisi binarie. Di conseguenza, i problemi di sicurezza nei parser multimediali sono estremamente comuni.

Chromium utilizza la difesa approfondita per ridurre il rischio di problemi di sicurezza per i nostri utenti. In pratica, ciò significa che il demux e la decodifica del software avvengono sempre in un processo con privilegi ridotti, mentre la decodifica hardware avviene in un processo con privilegi sufficienti per comunicare con la GPU del sistema.

Le sandbox di Chromium per i processi di renderer, GPU e audio.

Il meccanismo di comunicazione tra processi di Chromium è chiamato Mojo. Anche se non entreremo nei dettagli di Mojo in questo articolo, in quanto livello di astrazione tra i processi, è un cardine della pipeline multimediale estensibile di Chromium. È importante esserne a conoscenza man mano che analizziamo la pipeline di riproduzione, poiché questa procedura fornisce informazioni sulla complessa orchestrazione dei componenti cross-process che interagiscono per ricevere, eseguire il demux, decodificare e infine visualizzare i contenuti multimediali.

Tantissimi dati

Comprendere le attuali pipeline di rendering video richiede la conoscenza del motivo per cui i video sono speciali: la larghezza di banda. Una riproduzione con una risoluzione di 3840 x 2160 (4K) a 60 frame al secondo utilizza una larghezza di banda di memoria compresa tra 9 e 12 gigabit/secondo. Anche se i sistemi moderni possono avere un picco di larghezza di banda pari a centinaia di gigabit al secondo, la riproduzione video rappresenta comunque una parte considerevole. Senza attenzione, la larghezza di banda totale può facilmente moltiplicarsi a causa di copie o corse tra GPU e memoria della CPU.

L'obiettivo di qualsiasi motore di riproduzione video moderno che mira all'efficienza è ridurre al minimo la larghezza di banda tra il decoder e la fase di rendering finale. Per questo motivo, il rendering video è in gran parte disaccoppiato dalla pipeline di rendering principale di Chromium. Nello specifico, dal punto di vista della nostra pipeline di rendering principale, un video è solo un'area con opacità a dimensione fissa. Chromium raggiunge questo obiettivo utilizzando un concetto chiamato surfaces, in cui ogni video parla direttamente con Viz.

Una pagina web con un foro e una freccia che dice "Il video va qui".

Data la popolarità del mobile computing, potenza ed efficienza sono diventati una priorità significativa nell'attuale generazione. Il risultato è che la decodifica e il rendering sono più abbinati che mai a livello di hardware, quindi i video somigliano a un vuoto con opacità, anche nel sistema operativo stesso. I decoder a livello di piattaforma spesso forniscono solo buffer opachi che Chromium trasmette al sistema di composizione a livello di piattaforma sotto forma di overlay.

Una pagina web con un foro e una freccia che dice "Il video va qui" e circondata da un riquadro che rappresenta il sistema operativo.

Ogni piattaforma utilizza la propria forma di overlay con cui le API di decodifica della piattaforma funzionano insieme. Windows dispone di Composizione diretta e Media Foundation Transforms, MacOS ha Livelli CoreAnimation e VideoToolbox, SurfaceView e MediaCodec e Linux con VASurfaces e VA-API. Le astrazioni di Chromium per questi concetti sono gestite rispettivamente dalle interfacce OverlayProcessor e mojo::VideoDecoder.

In alcuni casi è possibile che questi buffer siano mappabili nella memoria di sistema, pertanto non devono essere opachi e non consumano larghezza di banda fino all'accesso: Chromium chiama questi buffer GpuMemoryBuffers. Su Windows sono supportati da buffer DXGI, su macOS IOSurfaces, su Android AHardwareBuffers e su buffer DMA di Linux. Sebbene la riproduzione video non richieda generalmente questo accesso, questi buffer sono importanti per l'acquisizione video e garantiscono una larghezza di banda minima tra il dispositivo di acquisizione e gli eventuali codificatori.

Diagramma dei buffer menzionati nel testo precedente.

Poiché la GPU è spesso responsabile sia della decodifica sia della visualizzazione, l'uso di questi buffer (spesso) opachi assicura che i dati video a larghezza di banda elevata non escano mai dalla GPU. Come abbiamo già detto, la conservazione dei dati sulla GPU è estremamente importante per l'efficienza, soprattutto ad alta risoluzione e frequenza fotogrammi.

Maggiore è il vantaggio delle primitive del sistema operativo come overlay e buffer GPU, minore è la larghezza di banda spesa a shuffling dei byte video inutilmente. Tenere tutto in un unico posto, dalla decodifica fino al rendering, può portare a un'incredibile efficienza energetica. Ad esempio, quando Chromium ha attivato gli overlay su macOS, il consumo energetico durante la riproduzione dei video a schermo intero si è dimezzato. Su altre piattaforme come Windows, Android e ChromeOS, possiamo utilizzare gli overlay anche in custodie non a schermo intero, risparmiando fino al 50% praticamente ovunque.

Rendering

Ora che abbiamo esaminato i meccanismi di consegna ottimali, possiamo discutere in che modo Chromium sceglie cosa fornire. Lo stack di riproduzione di Chromium utilizza un'architettura basata su "pull", nel senso che ogni componente nello stack richiede i propri input da quello sottostante in ordine gerarchico. Nella parte superiore dello stack c'è il rendering dei frame audio e video, poi in basso c'è la decodifica, poi il demuxing e infine l'I/O. Ogni frame audio visualizzato fa avanzare un orologio, che viene utilizzato per scegliere i fotogrammi video per il rendering quando vengono combinati con un intervallo di presentazione.

A ogni intervallo di presentazione (ogni aggiornamento della visualizzazione), al renderer del video viene chiesto di fornire un fotogramma video da un CompositorFrameSink collegato al SurfaceLayer menzionato in precedenza. Per i contenuti con una frequenza fotogrammi inferiore a quella di visualizzazione, ciò significa che lo stesso frame viene mostrato più volte, mentre se la frequenza fotogrammi è maggiore di quella di visualizzazione, alcuni frame non vengono mai mostrati.

Inoltre, sincronizzare audio e video in modi piacevoli agli spettatori. Per una discussione più lunga su come ottenere la fluidità video ottimale in Chromium, consulta Project Bur. Spiega come il rendering video può essere suddiviso in sequenze ideali che rappresentano quante volte deve essere mostrato ogni frame. Ad esempio: "1 fotogramma ogni intervallo di visualizzazione ([1], 60 f/s a 60 Hz)", "1 fotogramma ogni 2 intervalli ([2], 30 f/s a 60 Hz)" o pattern più complicati come [2:3:2:3:2 (25 f/s a 60 Hz) che coprono più fotogrammi e intervalli di visualizzazione distinti. Più un renderer video si avvicina a questo pattern ideale, più è probabile che un utente percepisca una riproduzione uniforme.

La sequenza di demuxing, decodifica e rendering.

La maggior parte delle piattaforme Chromium esegue il rendering fotogramma per fotogramma, ma non tutte. La nostra architettura estensibile consente anche il rendering in batch. Il rendering in batch è una tecnica di efficienza in cui il compositore a livello di sistema operativo viene informato in anticipo di più frame e gestisce il loro rilascio in base a una pianificazione temporale fornita dall'applicazione.

Il futuro è adesso?

Ci siamo concentrati su come Chromium sfrutta le primitive del sistema operativo per offrire la migliore esperienza di riproduzione del settore. E per quanto riguarda i siti web che vogliono andare oltre la riproduzione di video di base? Possiamo offrire loro le stesse potenti primitive che Chromium stesso utilizza per inaugurare la prossima generazione di contenuti web?

Pensiamo che la risposta sia sì. L'estensibilità è al centro del modo in cui concepiamo la piattaforma web al giorno d'oggi. Stiamo collaborando con altri browser e sviluppatori per creare nuove tecnologie come WebGPU e WebCodecs in modo che gli sviluppatori web possano utilizzare le stesse funzionalità primitive di Chromium quando comunica con il sistema operativo. WebGPU supporta i buffer GPU, mentre WebCodecs offre primitive di decodifica e codifica della piattaforma compatibili con i suddetti sistemi di buffer GPU e overlay.

Relazione tra WebCodecs e WebGPU.

Fine dello stream

Grazie per l'attenzione. Spero che tu abbia potuto conoscere meglio i moderni sistemi di riproduzione e come Chromium sia in grado di gestire diverse centinaia di milioni di ore di tempo di visualizzazione ogni giorno. Se hai bisogno di ulteriori letture sui codec e sui video sul web moderni, ti consiglio H.264 is magic di Sid Bala, How Modern Video Players Work di Erica Beaves, e Packaging Award- accedono con una tecnologia pluripremiata di Cyril Concolato.

Un'illustrazione (quella carina!) di Una Kravets.