Ich bin Dale Curtis, der leitende Entwickler für die Medienwiedergabe in Chromium. Mein Team ist für die webbasierten APIs für die Videowiedergabe wie MSE und WebCodecs sowie für die plattformspezifischen internen Funktionen zur Demultiplexierung, Dekodierung und Darstellung von Audio und Video verantwortlich.
In diesem Artikel stelle ich die Video-Rendering-Architektur von Chromium vor. Einige Details zur Erweiterung sind wahrscheinlich Chromium-spezifisch, die meisten hier beschriebenen Konzepte und Designs gelten jedoch auch für andere Rendering-Engines und sogar für native Wiedergabe-Apps.
Die Wiedergabearchitektur von Chromium hat sich im Laufe der Jahre erheblich verändert. Wir haben nicht mit der Idee einer Erfolgspyramide begonnen, wie im ersten Beitrag dieser Reihe beschrieben, sondern sind letztendlich ähnliche Schritte gegangen: Zuverlässigkeit, Leistung und dann Erweiterbarkeit.
Anfangs war das Video-Rendering recht einfach: Nur eine For-Schleife, mit der ausgewählt wurde, welche Software Videoframes decodieren und an den Compositor senden sollte. Das war jahrelang zuverlässig genug, aber mit zunehmender Komplexität des Webs stieg der Bedarf an mehr Leistung und Effizienz, was zu architektonischen Änderungen führte. Viele Verbesserungen erforderten betriebssystemspezifische Primitive. Daher musste unsere Architektur auch erweiterbar werden, um alle Chromium-Plattformen zu erreichen.
Das Video-Rendering kann in zwei Schritte unterteilt werden: die Auswahl der zu übertragenden Daten und die effiziente Übertragung dieser Daten. Aus Gründen der besseren Lesbarkeit werde ich zuerst die effiziente Bereitstellung behandeln, bevor ich darauf eingehe, wie Chromium auswählt, was bereitgestellt wird.
Einige Begriffe und das Layout
Da sich dieser Artikel auf das Rendern konzentriert, gehe ich nur kurz auf die Demultiplexierung und Dekodierung der Pipeline ein.
Dekodieren und Demultiplexen in unserer modernen, sicherheitsbewussten Welt erfordert einiges an Sorgfalt. Binäre Parser sind reichhaltige Zielumgebungen und die Medienwiedergabe ist voll von binärem Parsen. Daher sind Sicherheitsprobleme in Media-Parsern äußerst häufig.
Chromium setzt auf mehrere Sicherheitsebenen, um das Risiko von Sicherheitsproblemen für unsere Nutzer zu verringern. In der Praxis bedeutet das, dass die Demultiplexierung und die Softwaredekodierung immer in einem Prozess mit niedrigen Berechtigungen erfolgen, während die Hardwaredekodierung in einem Prozess mit gerade ausreichenden Berechtigungen erfolgt, um mit der GPU des Systems zu kommunizieren.
Der prozessübergreifende Kommunikationsmechanismus von Chromium wird Mojo genannt. In diesem Artikel gehen wir nicht auf die Details von Mojo ein. Als Abstraktionsschicht zwischen Prozessen ist es jedoch ein Eckpfeiler der erweiterbaren Medienpipeline von Chromium. Das ist wichtig, wenn wir uns die Wiedergabepipeline ansehen, da es die komplexe Orchestrierung von prozessübergreifenden Komponenten beeinflusst, die miteinander interagieren, um Medien zu empfangen, zu demuxen, zu decodieren und schließlich anzuzeigen.
So viele Bits
Um die heutigen Video-Rendering-Pipelines zu verstehen, müssen Sie wissen, was Video so besonders macht: die Bandbreite. Die Wiedergabe mit einer Auflösung von 3840 × 2160 (4K) bei 60 Bildern pro Sekunde benötigt zwischen 9 und 12 Gigabit/Sekunde Speicherbandbreite. Moderne Systeme können zwar eine Spitzenbandbreite von Hunderten von Gigabit pro Sekunde haben, die Videowiedergabe macht aber immer noch einen erheblichen Teil aus. Ohne Vorsicht kann sich die Gesamtbandbreite aufgrund von Kopien oder Übertragungen zwischen GPU- und CPU-Speicher leicht vervielfachen.
Das Ziel jeder modernen Videowiedergabe-Engine mit Blick auf die Effizienz besteht darin, die Bandbreite zwischen dem Decoder und dem letzten Rendering-Schritt zu minimieren. Aus diesem Grund ist das Video-Rendering weitgehend von der Haupt-Rendering-Pipeline von Chromium getrennt. Aus der Perspektive unserer Haupt-Rendering-Pipeline ist ein Video lediglich ein Loch mit fester Größe und Deckkraft. Chromium erreicht dies mit einem Konzept namens Oberflächen, bei dem jedes Video direkt mit Viz kommuniziert.
Aufgrund der Beliebtheit von Mobilgeräten haben Leistung und Effizienz bei der aktuellen Generation einen hohen Stellenwert. Das führt dazu, dass Dekodierung und Rendering auf Hardwareebene stärker denn je miteinander verbunden sind. Das Video sieht dann selbst für das Betriebssystem nur wie ein Loch mit Deckkraft aus. Decoder auf Plattformebene stellen häufig nur opake Puffer bereit, die Chromium in Form von Overlays an das Kompositionssystem auf Plattformebene weitergibt.
Jede Plattform hat ihre eigene Art von Overlays, mit denen die Dekodierungs-APIs der Plattform zusammenarbeiten. Windows bietet Direct Composition und Media Foundation Transforms, macOS CoreAnimation Layers und VideoToolbox, Android SurfaceView und MediaCodec und Linux VASurfaces und VA-API. Die Abstraktionen von Chromium für diese Konzepte werden jeweils von den Schnittstellen OverlayProcessor und mojo::VideoDecoder verwaltet.
In einigen Fällen können diese Puffer in den Systemspeicher zugeordnet werden. Sie müssen also nicht einmal undurchsichtig sein und verbrauchen erst beim Zugriff Bandbreite. In Chromium werden sie als GpuMemoryBuffers bezeichnet. Unter Windows werden sie von DXGI-Blöcken, unter macOS von IOSurfaces, unter Android von AHardwareBuffers und unter Linux von DMA-Blöcken unterstützt. Für die Videowiedergabe ist dieser Zugriff in der Regel nicht erforderlich. Diese Puffer sind jedoch für die Videoaufnahme wichtig, um eine minimale Bandbreite zwischen dem Aufnahmegerät und den eventuellen Encodern zu gewährleisten.
Da die GPU oft sowohl für die Dekodierung als auch für die Anzeige verantwortlich ist, sorgen diese (oft auch undurchsichtigen) Puffer dafür, dass Videodaten mit hoher Bandbreite die GPU nie verlassen. Wie bereits erwähnt, ist es für die Effizienz von entscheidender Bedeutung, Daten auf der GPU zu behalten, insbesondere bei hohen Auflösungen und Frameraten.
Je mehr wir von Betriebssystem-Primitiven wie Overlays und GPU-Buffern profitieren können, desto weniger Bandbreite wird für unnötiges Verschieben von Videobytes verbraucht. Wenn alles an einem Ort bleibt, von der Dekodierung bis zum Rendering, kann das zu einer unglaublichen Energieeffizienz führen. Beispielsweise wurde der Energieverbrauch bei der Videowiedergabe im Vollbildmodus unter macOS halbiert, als Chromium Overlays aktivierte. Auf anderen Plattformen wie Windows, Android und ChromeOS können wir Overlays auch bei nicht maximiertem Fenster verwenden und so fast überall bis zu 50% sparen.
Rendering
Nachdem wir die optimalen Bereitstellungsmechanismen besprochen haben, können wir uns damit befassen, wie Chromium auswählt, was bereitgestellt wird. Der Wiedergabe-Stack von Chromium verwendet eine Pull-basierte Architektur. Das bedeutet, dass jede Komponente im Stack ihre Eingaben in hierarchischer Reihenfolge von der darunter liegenden anfordert. Ganz oben im Stack steht das Rendern von Audio- und Videoframes, darunter die Dekodierung, gefolgt von der Demultiplexierung und schließlich der E/A. Bei jedem gerenderten Audioframe wird eine Uhr vorangestellt, die in Kombination mit einem Präsentationsintervall verwendet wird, um Videoframes für das Rendering auszuwählen.
Bei jedem Präsentationsintervall (bei jeder Aktualisierung des Displays) wird der Video-Renderer von einem CompositorFrameSink, der der bereits erwähnten SurfaceLayer zugeordnet ist, aufgefordert, einen Videoframe bereitzustellen. Bei Inhalten mit einer Framerate, die unter der Wiedergaberate liegt, wird derselbe Frame mehrmals angezeigt. Ist die Framerate höher als die Wiedergaberate, werden einige Frames nie angezeigt.
Die Synchronisierung von Audio und Video auf eine Weise, die Zuschauern gefällt, ist aber noch viel mehr. Unter Project Butter finden Sie weitere Informationen dazu, wie in Chromium eine optimale Videoflüssigkeit erreicht wird. 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 bei 60 Hz)“, „1 Frame pro 2 Intervalle ([2], 30 fps bei 60 Hz)“ oder komplexere Muster wie [2:3:2:3:2] (25 fps bei 60 Hz), die mehrere Frames und Anzeigeintervalle umfassen. Je näher ein Video-Renderer an diesem idealen Muster bleibt, desto wahrscheinlicher wird die Wiedergabe von Nutzern als flüssig wahrgenommen.
Die meisten Chromium-Plattformen rendern Frame für Frame, aber nicht alle. Unsere erweiterbare Architektur ermöglicht auch das Batch-Rendering. Das Batch-Rendering ist ein Effizienzverfahren, bei dem der Compositor auf Betriebssystemebene mehrere Frames im Voraus erhält und sie gemäß einem von der Anwendung bereitgestellten Zeitplan freigibt.
Die Zukunft ist jetzt?
Wir haben uns darauf konzentriert, wie Chromium die Betriebssystem-Primitive nutzt, um eine erstklassige Wiedergabe zu ermöglichen. Aber was ist mit Websites, die über die grundlegende Videowiedergabe hinausgehen möchten? Können wir ihnen dieselben leistungsstarken Primitives anbieten, die Chromium selbst verwendet, um die nächste Generation von Webinhalten einzuleiten?
Wir denken, dass die Antwort „Ja“ lautet. Erweiterbarkeit ist heute ein zentrales Thema für uns. Wir haben mit anderen Browsern und Entwicklern zusammengearbeitet, um neue Technologien wie WebGPU und WebCodecs zu entwickeln, damit Webentwickler dieselben Primitives wie Chromium verwenden können, wenn sie mit dem Betriebssystem kommunizieren. WebGPU unterstützt GPU-Buffer und WebCodecs bietet plattformspezifische Dekodierungs- und Codierungsprimitiven, die mit den oben genannten Overlay- und GPU-Buffersystemen kompatibel sind.
Ende des Streams
Vielen Dank, dass Sie sich die Zeit zum Lesen dieser E-Mail genommen haben. Ich hoffe, dass du jetzt ein besseres Verständnis für moderne Wiedergabesysteme hast und weißt, wie Chromium jeden Tag für mehrere hundert Millionen Stunden Wiedergabezeit sorgt. Weitere Informationen zu Codecs und modernen Webvideos findest du in den Artikeln H.264 is magic von Sid Bala, How Modern Video Players Work von Erica Beaves und Packaging award-winning shows with award-winning technology von Cyril Concolato.
Eine Illustration (die hübsche!) von Una Kravets.