Detailanalyse: VideoNG

Dale Curtis
Dale Curtis

Ich bin Dale Curtis, Engineering Lead für die Medienwiedergabe in Chromium. Mein Team ist verantwortlich für die webbasierten APIs für die Videowiedergabe wie MSE und WebCodecs sowie für die plattformspezifischen internen Komponenten, die für das Demuxing, das Decodieren und das Rendern von Audio- und Videoinhalten erforderlich sind.

In diesem Artikel lernen Sie die Video-Rendering-Architektur von Chromium kennen. Während einige Details zur Erweiterbarkeit wahrscheinlich Chromium-spezifisch sind, gelten die meisten der hier beschriebenen Konzepte und Designs auch für andere Rendering-Engines und sogar native Wiedergabe-Apps.

Die Wiedergabearchitektur von Chromium hat sich im Laufe der Jahre erheblich verändert. Obwohl wir nicht mit der Idee einer Erfolgspyramide begonnen haben, wie im ersten Beitrag dieser Reihe beschrieben, sind wir letztendlich ähnlichen Schritten gefolgt: Zuverlässigkeit, Leistung und dann Erweiterbarkeit.

Am Anfang war das Video-Rendering recht einfach – nur eine For-Schleife, um auszuwählen, welche Software decodierten Videoframes an den Compositor senden soll. Jahrelang war dies zuverlässig genug, aber als die Komplexität des Webs zunahm, führte die Notwendigkeit von mehr Leistung und Effizienz zu Architekturänderungen. Viele Verbesserungen erforderten betriebssystemspezifische Primitive. Daher musste unsere Architektur auch erweitert werden, um alle Chromium-Plattformen zu erreichen.

Diagramm des Rendering-Ablaufs für verschiedene Chromium-Plattformen

Video-Rendering kann in zwei Schritte unterteilt werden: die Auswahl der zu liefernden Informationen und die effiziente Bereitstellung dieser Informationen. Im Interesse der besseren Lesbarkeit werde ich auf eine effiziente Bereitstellung eingehen, bevor wir darauf eingehen, wie Chromium die Inhalte auswählt.

Einige Begriffe und Layout

Da sich dieser Artikel auf das Rendering konzentriert, gehe ich nur kurz auf die Decodierungs- und Decodierungsaspekte der Pipeline ein.

Eingehende Byte und ausgehende strukturierte Pakete.

Das Decodieren und Abmuxieren in einer modernen, sicherheitsbewussten Welt erfordert gewisse Sorgfalt. Binäre Parser sind umfangreiche Zielumgebungen und die Medienwiedergabe ist voll von Binärdateien, um sie zu parsen. Daher sind Sicherheitsprobleme bei Medienparsern äußerst häufig.

Chromium nutzt gestaffelte Sicherheitsebenen, um das Risiko von Sicherheitsproblemen für unsere Nutzer zu verringern. In der Praxis bedeutet dies, dass das Decodieren und die Software-Decodierung immer in einem Prozess mit geringen Berechtigungen erfolgen, während die Hardwaredecodierung in einem Prozess erfolgt, bei dem gerade genug Berechtigungen vorhanden sind, um mit der GPU des Systems zu kommunizieren.

Chromium führt eine Sandbox für den Renderer, die GPU und die Audioprozesse aus.

Der prozessübergreifende Kommunikationsmechanismus von Chromium heißt Mojo. Auch wenn wir in diesem Artikel nicht auf die Details von Mojo eingehen, bildet es als Abstraktionsschicht zwischen Prozessen einen Eckpfeiler der erweiterbaren Medienpipeline von Chromium. Es ist wichtig, sich dieser Tatsache bewusst zu sein, wenn wir die Wiedergabe-Pipeline durchgehen, da sie die komplexe Orchestrierung von prozessübergreifenden Komponenten vorgibt, die interagieren, um Medien zu empfangen, zu decodieren und schließlich anzuzeigen.

So viele Informationen

Um die heutigen Video-Rendering-Pipelines zu verstehen, müssen Sie wissen, warum Videos etwas Besonderes sind: Bandbreite. Eine Wiedergabe mit einer Auflösung von 3840 x 2160 (4K) bei 60 Bildern pro Sekunde benötigt eine Arbeitsspeicherbandbreite von 9–12 Gigabit/Sekunde. Obwohl moderne Systeme eine Spitzenbandbreite von Hunderten Gigabit pro Sekunde haben können, macht die Videowiedergabe immer noch einen erheblichen Teil aus. Ohne Sorgfalt kann sich die Gesamtbandbreite aufgrund von Kopien oder Fahrten zwischen GPU und CPU-Arbeitsspeicher leicht vervielfachen.

Das Ziel jeder modernen Video-Wiedergabe-Engine, die auf Effizienz ausgerichtet ist, besteht darin, die Bandbreite zwischen dem Decoder und dem abschließenden Renderingschritt so gering wie möglich zu halten. Aus diesem Grund ist das Video-Rendering weitgehend von der Haupt-Rendering-Pipeline von Chromium entkoppelt. Aus der Sicht unserer Haupt-Rendering-Pipeline ist ein Video nur ein Loch mit fester Größe und Deckkraft. Chromium nutzt dazu das Konzept Oberflächen, bei dem jedes Video direkt mit Viz kommuniziert.

Eine Webseite mit einem Loch und einem Pfeil mit der Aufschrift „Video einfügen“.

Aufgrund der Beliebtheit des mobilen Computings sind Leistung und Effizienz in der aktuellen Generation ein wichtiger Schwerpunkt. Dies hat zur Folge, dass Decodierung und Rendering auf Hardwareebene stärker gekoppelt sind als je zuvor. Videos sehen also wie eine Lücke mit Deckkraft aus, selbst mit dem Betriebssystem selbst. Decodierer auf Plattformebene stellen häufig nur intransparente Puffer bereit, die Chromium in Form von Overlays an das Compositing-System auf Plattformebene weiterleitet.

Eine Webseite mit einem Loch und einem Pfeil mit der Aufschrift „Video einfügen“, umschlossen von einem Feld, das das Betriebssystem repräsentiert.

Jede Plattform hat ihre eigene Form von Overlays, mit denen die APIs zur Decodierung der Plattform zusammenwirken. Windows hat Direct Composition und Media Foundation Transforms, macOS verfügt über CoreAnimation Layers und VideoToolbox, Android bietet SurfaceView und MediaCodec und Linux hat VASurfaces und VA-API. Die Abstraktionen von Chromium für diese Konzepte werden von den Schnittstellen OverlayProcessor und mojo::VideoDecoder verarbeitet.

In einigen Fällen ist es möglich, dass diese Puffer im Systemspeicher zugeordnet werden können. Sie müssen also nicht einmal intransparent sein und verbrauchen keine Bandbreite, bis darauf zugegriffen wird. Chromium nennt diese Zwischenspeicher (GpuMemoryBuffers). Unter Windows werden diese von DXGI-Puffern, unter macOS IOSurfaces, unter Android AHardwareBuffers und unter Linux DMA-Zwischenspeicher abgesichert. Dieser Zugriff ist für die Videowiedergabe normalerweise nicht erforderlich. Diese Zwischenspeicher sind jedoch für die Videoaufnahme wichtig, um eine minimale Bandbreite zwischen dem Erfassungsgerät und den späteren Encodern sicherzustellen.

Diagramm der im vorherigen Text erwähnten Puffer.

Da die GPU oft sowohl für das Decodieren als auch für die Anzeige verantwortlich ist, sorgt die Verwendung dieser (auch oft) intransparenten Puffer dafür, dass Videodaten mit hoher Bandbreite die GPU nie verlassen. Wie bereits erwähnt, ist es für die Effizienz unglaublich wichtig, Daten auf der GPU zu behalten, insbesondere bei hohen Auflösungen und Framerates.

Je mehr wir Betriebssystem-Primitive wie Overlays und GPU-Zwischenspeicher nutzen können, desto weniger Bandbreite wird benötigt, um Videobyte unnötig zu zufällig herumzusortieren. Wenn Sie alles an einem Ort speichern, von der Decodierung bis hin zum Rendering, kann dies zu einer enormen Effizienz führen. Wenn Chromium beispielsweise unter macOS Overlays aktiviert hat, wurde der Stromverbrauch bei der Videowiedergabe im Vollbildmodus halbiert. Auf anderen Plattformen wie Windows, Android und ChromeOS können wir Overlays auch nicht im Vollbildmodus verwenden. Dadurch sparen wir fast überall bis zu 50% ein.

Rendering

Nachdem wir uns mit den optimalen Übermittlungsmechanismen beschäftigt haben, können wir besprechen, wie Chromium die Inhalte auswählt. Der Wiedergabestack von Chromium verwendet eine Pull-basierte Architektur. Das bedeutet, dass jede Komponente im Stack ihre Eingaben von der darunterliegenden Komponente in hierarchischer Reihenfolge anfordert. An der Spitze des Stacks befindet sich das Rendering von Audio- und Videoframes, darunter die Decodierung, die Decodierung, die Schlussfolgerung und schließlich E/A. Mit jedem gerenderten Audioframe wird eine Uhr weiter abgespielt, mit der in Kombination mit einem Präsentationsintervall Videoframes für das Rendering ausgewählt werden.

Bei jedem Präsentationsintervall (bei jeder Aktualisierung der Anzeige) wird der Video-Renderer aufgefordert, einen Videoframe über CompositorFrameSink bereitzustellen, das an das zuvor erwähnte SurfaceLayer-Element angehängt ist. Bei Inhalten mit einer Framerate, die unter der Anzeigerate liegt, bedeutet das, dass derselbe Frame mehr als einmal angezeigt wird. Wenn die Framerate höher als die Anzeigerate ist, werden einige Frames nie angezeigt.

Es gibt noch viel mehr, Audio- und Videoinhalte auf eine Weise zu synchronisieren, die den Zuschauern gefällt. Unter Project Butter findest du ein ausführlicheres Gespräch darüber, wie eine optimale Video-Flüssigkeit in Chromium erreicht werden kann. Darin wird erläutert, wie das Video-Rendering in ideale Sequenzen unterteilt werden kann, die angeben, wie oft jeder Frame angezeigt werden soll. Beispiele: „1 Frame pro Anzeigeintervall ([1], 60 fps in 60 Hz)“, „1 Frame alle 2 Intervalle ([2], 30 fps in 60 Hz)“ oder kompliziertere Muster wie [2:3:2:3:2] (25 fps in 60 Hz) und Anzeigeintervalle Je näher ein Video-Renderer dieses ideale Muster aufweist, desto wahrscheinlicher nimmt ein Nutzer eine Wiedergabe als gleichmäßig wahr.

Die Abfolge von Decodierung, Decodierung und Rendering.

Die meisten Chromium-Plattformen rendern Frame für Frame, aber nicht alle. Unsere erweiterbare Architektur ermöglicht auch Batch-Rendering. Batch-Rendering ist ein Effizienzverfahren, bei dem der Compositor auf Betriebssystemebene im Voraus über mehrere Frames informiert und diese gemäß einem von der Anwendung vorgegebenen Zeitplan freigegeben wird.

Die Zukunft liegt jetzt?

Wir haben uns darauf konzentriert, wie Chromium die Grundfunktionen des Betriebssystems nutzt, um eine erstklassige Wiedergabequalität zu bieten. Aber was ist mit Websites, die über die einfache Videowiedergabe hinausgehen? Können wir ihnen dieselben leistungsstarken Primitiven anbieten, mit denen Chromium selbst die nächste Generation von Webinhalten einleitet?

Die Antwort lautet „Ja“. Erweiterbarkeit steht im Mittelpunkt unserer heutigen Meinung über die Webplattform. Wir haben mit anderen Browsern und Entwicklern zusammengearbeitet, um neue Technologien wie WebGPU und WebCodecs zu entwickeln, damit Webentwickler dieselben Primitive verwenden können, die Chromium für die Kommunikation mit dem Betriebssystem nutzt. WebGPU unterstützt GPU-Zwischenspeicher und WebCodecs bietet Plattformdecodierungs- und Codierungselemente, die mit den oben genannten Overlay- und GPU-Puffersystemen kompatibel sind.

Beziehung zwischen WebCodecs und WebGPU.

Ende des Streams

Vielen Dank, dass Sie sich die Zeit zum Lesen dieser E-Mail genommen haben. Ich hoffe, du hast einen guten Überblick über moderne Wiedergabesysteme und darüber, wie Chromium täglich eine Wiedergabezeit von mehreren hundert Millionen Stunden ermöglicht. Wenn Sie mehr über Codecs und moderne Webvideos erfahren möchten, empfehle ich Ihnen H.264 is Magic von Sid Bala, How Modern Video Players Work von Erica Beaves und Die Verpackung preisgekrönter Serien mit preisgekrönter Technologie von Cyril Concolato.

Eine (die hübsche!) Illustration von Una Kravets.