Wichtige technische Details zu x264/H.264

Bevor wir richtig in die x264-Konfiguration einsteigen, werfen wir in diesem Kapitel zunächst einen Blick auf die zentralen Fähigkeiten des H.264-Formats – allerdings schon mit dem im Hinterkopf, was auch für x264 wichtig ist. H.264 weist einige deutliche Unterschiede und Neuerungen dem älteren MPEG-4 ASP gegenüber auf, die für eine gesteigerte Effizienz des Encodings verantwortlich sind. Im Klartext heißt das, wir können in einer bestimmten Dateigröße bessere Qualität unterbringen oder ein bestimmtes Qualitätsniveau mit einer kleineren Datei erreichen.

Mehrfache Referenzen und IDR-Frames

Das ältere MPEG-4 ASP definiert für jedes P-Frame genau ein Bild, das als Referenz für die Suche nach Bewegung benutzt werden darf, und zwar das direkt vorangehende I/P-Frame. H.264 hat diese Beschränkung nicht mehr. Ein P-Frame darf auf beliebig viele Referenzframes verweisen. x264 beschränkt das Maximum auf sechzehn. Dadurch steigt das Potenzial enorm, eine gute Übereinstimmung in der Bewegungssuche zu finden, und je besser die Übereinstimmung, desto höher kann das Bild komprimiert werden, ohne die Qualität nach unten zu ziehen. Also sind mehrere Referenzframes eine gute Sache. Allerdings bekommen wir diesen Vorteil nicht gratis. Die Anforderung an Speicher und CPU-Leistung steigt, und zwar sowohl beim Encoding als auch beim Abspielen.

Außerdem entsteht durch die Mehrfachreferenzen ein weiteres Phänomen. Es existieren in H.264 zwei verschiedene Arten von I-Frames: normale I-Frames und IDR-Frames (Kurzform für instantaneous decoding refresh). Sehen wir uns folgende Bildsequenz an:

P1 IDR P2 P3 I P4 P5

Beide I-Frame-Typen sind vollständige Einzelbilder, d.h. sie selbst enthalten keine Referenzen auf andere Frames. Referenzen über einfache I-Frames hinweg sind aber möglich. Es wäre also einwandfrei erlaubt, dass das Frame P4 über das I-Frame hinweg auf P2 referenziert. Die Konsequenz daraus ist die, dass ein einfaches I-Frame nicht als Punkt taugt, an dem wir den Film schneiden können, denn damit würden wir P4 zumindest einen Teil seiner Referenzen wegnehmen. Bildfehler am Anfang der zweiten Datei wären die Folge. Keyframes in dem Sinn, wie wir sie kennen, sind nur IDR-Frames, denn eine Referenz über ein IDR-Frame hinweg ist nicht erlaubt. P4 darf also niemals auf P1 oder noch frühere Frames verweisen. Das heißt auch, dass fürs Springen und Schneiden nur IDR-Frames relevant sind und wir einfache I-Frames genauso wie P- und B-Frames behandeln müssen.

Bei x264 sind für die Steuerung von Referenzen und Keyframes die Parameter --ref, --keyint und --min-keyint zuständig.

Partitionierung von Makroblocks

Der H.264-Standard erlaubt es, einen 16×16 Pixel großen Makroblock in kleinere Einheiten aufzuteilen, so genannte Partitionen. Diese werden dann getrennt voneinander betrachtet, d.h. sie erhalten eigene Bewegungsvektoren und können sogar unterschiedliche Frames als Referenz verwenden. Zwar benötigt die Partitionierung einigen Speicherplatz zu Verwaltung, doch der wird durch das große Potenzial zu Erhöhung der Kompression wieder aufgewogen. Besonders in den Teilen des Bilds, wo viel Bewegung stattfindet, lohnen sich kleine Partitionsgrößen. Statische Bildteile profitieren dagegen nur wenig. Deshalb entscheidet x264 dynamisch, für welchen Makroblock welche Partitionierung am nützlichsten ist.

Partitionsgrößen. Erste Reihe: 8×8, 8×16, 16×8. Zweite Reihe: 4×4, 4×8, 8×4

In der Konfiguration können wir einstellen, welche Partitionsgrößen x264 überhaupt berücksichtigt. Die erste Reihe im Bild mit den 8er-Größen ist für P- und B-Frames möglich. Dazu kommen im H.264 High Profile die I-Frames, falls wir zusätzlich die 8×8-DCT-Transformation einschalten. Die zweite Reihe mit den 4er-Größen funktioniert für I- und P-Frames (unabhängig vom H.264-Profil), nicht aber für B-Frames.

Je kleiner die Partitionierung, desto mehr Speicherplatz benötigt die Verwaltung. Für einen unpartitionierten 16×16-Makroblock fällt etwas vereinfacht die Speicherung des Bewegungsvektors und des verwendeten Referenzframes als Overhead an. Wird der Block nun aufgeteilt, müssen diese beiden Daten für jede Partition gespeichert werden. Für die 8×8-Partitionierung bedeutet das eine Vervierfachung des Overheads. Ein vollständig in 4×4-Partitionen unterteilter Block benötigt schon 16 mal so viel Verwaltungsspeicher. Deshalb ist ein H.264-Encoder praktisch gezwungen, die Partitionsgrößen je nach Bildinhalt zu variieren. Ansonsten wäre der Kompressionsvorteil durch den enormen Anstieg des Overheads schnell wieder zunichte gemacht.

x264 verwendet für die Partitionierung die Parameter --partitions und --no-8x8dct.

Konfiguration von B-Frames

Das Konzept der B-Frames haben wir im Kapitel über die Interframe-Kompression schon angesprochen. Ein B-Frame darf nicht nur wie P-Frames Referenzen auf frühere Bilder enthalten, sondern auch Referenzen auf nachfolgende Frames. Hier beleuchten wir nun die bidirektionalen Bilder aus der Sicht von H.264 etwas genauer.

Der wichtigste Unterschied zu älteren Videoformaten besteht darin, dass ein H.264-B-Frame nicht nur I- und P-Frames als Referenz verwenden darf, sondern auch andere B-Frames. Diese Fähigkeit heißt B-Frame-Pyramide. Ist die Funktion abgeschaltet, sieht die Suche nach Referenzen wie in dieser Abbildung aus:

I P1 B1 B2 B3 P2 P3

Ein B-Frame darf kein anderes B-Frame als Referenz verwenden, sondern immer nur die vorangehenden oder folgenden I/P-Frames. B2 darf also auf P1 und P2 verweisen, nicht aber auf B1 oder B3. Das ist der klassische Modus, wie ihn auch Xvid und alle anderen ASP-Codecs verwenden. Allerdings lässt sich mit der B-Pyramide die Effizienz noch steigern. Das sieht dann so aus:

I P1 B1 B2 B3 P2 P3

B-Frames dürfen jetzt sowohl die umliegenden I/P-Frames als auch schon vorhandene B-Frames als Referenz nutzen. B2 kann also weiterhin auf P1 und P2 verweisen, aber auch auf B1. Eine Referenz auf zukünftige B-Frames (B3) ist nicht möglich, da B3 noch gar nicht existiert, wenn B2 encodiert wird. x264-Option: --b-pyramid.

Neben der Pyramide gibt es noch einige andere B-Frame-Funktionen, die wir uns ansehen sollten. Da sie sich in der Praxis hauptsächlich auf die Geschwindigkeit und weniger auf die Qualität/Dateigröße auswirken, können wir das aber kurz halten.

  • B-Blocks im Direct-Modus speichern keinen eigenen Bewegungsvektor, sondern berechnen ihn entweder aus den räumlichen Unterschieden innerhalb eines Frames (spatial) oder aus den zeitlichen Unterschieden zwischen verschiedenen Frames (temporal). x264 kann darüber hinaus in einem automatischen Modus selbst entscheiden, in welcher Situation welche Methode sinnvoller ist. x264-Option: --direct.
  • Die bidirektionale Bewegungssuche erlaubt anstatt nur einem zwei Bewegungsvektoren pro Makroblock bzw. Blockpartition. Damit steigt die Anzahl möglicher Referenzblocks deutlich an, und das bedeutet eine höhere Wahrscheinlichkeit dafür, eine richtig gute Referenz zu finden. Bei x264 integriert in die Option --subme.
  • Bei aktivierter gewichteter Bewegungskompensierung können die gefundenen Referenzen in einer beliebigen Gewichtung verwendet werden, was v.a. dazu beiträgt, Ein-, Aus- und Überblendungen effizienter zu speichern. x264-Option: --no-weightb.

Der Inloop-Deblocking-Filter

Deblocker dienen dazu, um Blockartefakte im Bild zu übertünchen. Bisher waren das eigenständige Filter, die unabhängig vom Format des Videos beim Abspielen angewendet werden konnten. H.264 geht auch hier einen Schritt weiter und definiert einen Deblocker, der schon während des Encodings zum Einsatz kommt. Damit ist er keine beliebig zuschaltbare Extrafunktion mehr, sondern ein fester Bestandteil der Encoding-Konfiguration.

Entsprechend dem Standard setzt x264 den Deblocking-Filter ein nachdem ein Bild codiert wurde, aber bevor es als Referenz für das nächste Bild dient. Dadurch kann dieses nächste Bild mit einer Referenz arbeiten, die weniger Artefakte enthält. Das tut der Qualität gut. Der Nachteil ist die sinkende Geschwindigkeit, und zwar sowohl beim Encoding als auch beim Decoding. Denn damit das zweite Bild korrekt decodiert werden kann, muss das vorangehende Bild in gefilterter Form vorliegen.

Sehen wir uns den folgenden (zweifach vergrößerten) Bildausschnitt an, der extrem stark komprimiert wurde.

Das linke Bild ist die Version ohne Deblocker und weist deutliche Makroblock-Artefakte auf. Rechts sehen wir genau das gleiche Bild, diesmal aber mit aktivem Deblocking-Filter. Die Artefakte sind übertüncht, was i.d.R. optisch besser aussieht und sich außerdem besser als Referenzbild eignet.

Die Stärke des Filters wird über zwei Stellschrauben geregelt, Strength und Threshold, oder entsprechend den offiziellen technischen Bezeichnungen Alpha- und Beta-Deblocking. Der Wert 0 steht jeweils für die Standardeinstellung des Filters. Negative Werte führen zu schwächerem Deblocking, positive zu stärkerem.

Das Thema wird im Doom9.org-Thread How To Use Mpeg4 AVC Deblocking Effectively etwas näher beleuchtet. Kurz zusammengefasst: Der Alpha-Wert legt insgesamt die Stärke des Deblockings fest; Beta regelt, wie aggressiv Bildstrukturen als Detail oder Artefakt eingeordnet werden, und passt je nach »Artefaktanteil« die Filterstärke an. x264 verwendet zur Konfiguration die Option --deblock.

Quantisierungsmatrizen

H.264 unterstützt genauso wie MPEG-4 ASP Quantisierungsmatrizen, einschließlich Custom-Matrizen. Im Wesentlichen treffen alle Erklärungen aus dem Xvid-Kapitel auch hier zu. Der technische Hauptunterschied besteht darin, dass eine »Matrix« nicht wie bei den ASP-Encodern aus zwei Matrizen, sondern gleich aus acht Stück besteht. Die beiden Standardmatrizen sind

  • Flat, bei der alle Positionen mit dem gleichen Wert belegt sind, und
  • JVT, die vom Joint Video Team im H.264-Standard vorgeschlagen wird.

Benutzerdefinierte Matrizen sind nicht so zahlreich verfügbar wie für Xvid und DivX. Im Wesentlichen haben sich Sharktooth und *.mp4 guy als H.264-Matrizenbauer hervorgetan, und zwar in den Doom9.org-Threads EQM AVC Series und Custom Matrices. Die dort geposteten Matrizen können wir einfach in einen Texteditor kopieren und so wie sie sind als reinen Text abspeichern. Meistens wird .cfg als Dateiendung verwendet.

Die Bedeutung der Matrizen für x264 ist beschränkt. Ausgefeiltere Methoden existieren, um geschickt die Quantisierung anzupassen. Dabei geht es v.a. um die drei psychovisuellen Funktionen Adaptive Quantization (AQ), PsyRD und PsyTrellis. Klare Matrixempfehlung ist deshalb Flat. Alle anderen sind eher Kandidaten für den gezielten Einsatz unter ganz speziellen Umständen.

Quantizer und Constant Rate Factor (CRF)

Vereinfacht ausgedrückt ist der Quantizer ein Faktor, der die Stärke der Kompression regelt. Hochoffiziell heißt er auch quantiser scale parameter, abgekürzt QP. Er darf je nach Konfiguration für jedes Frame oder jede Makroblockpartition verschieden sein und liegt bei MPEG-4 AVC (H.264) zwischen 1 und 51, wobei nur ganze Zahlen erlaubt sind. Je kleiner der Wert, desto sanfter die Kompression und desto besser die Qualität. Übliche QPs liegen etwa zwischen 18 und 25. Für hochqualitative Encodings ist der Bereich zwischen QP 18 und 20 am interessantesten.

Beim 2-Pass-Encoding haben wir mit dem Quantizer nur indirekt zu tun, da x264 die Verteilung selbst in die Hand nimmt, um die Zielgröße zu treffen. Beim 1-Pass-Encoding setzen wir den QP dagegen selbst. x264 unterstützt zwei Verfahren: das schon von Xvid und DivX bekannte CQ-Encoding mit festem Quantizer sowie das CRF-Verfahren (constant rate factor). Etwas genauer haben wir uns damit schon im Kapitel Encodingmethoden beschäftigt.

Interessant für die 1-Pass-Praxis ist hauptsächlich CRF. Dabei wählen wir einen nominalen Quantizer als Maßgabe für die tatsächlich sichtbare Qualität. Dieser stellt grob den durchschnittlichen Quantizer dar, den die Datei am Ende haben wird. x264 rechnet diesen Wert intern in den eigentlich benötigten rate factor um. Der nominale Quantizer ist also nur eine Hilfestellung zur einfacheren Bedienung. Deshalb sind auch Kommawerte wie 20.4 erlaubt, obwohl QPs nur ganze Zahlen sein dürfen.

Während des Encodings ermittelt x264 anhand des rate factors und je nach Eigenschaften der aktuellen Szene den günstigsten QP für jeden Makroblock. Die Logik dahinter folgt diesem Schema:

  • Schnelle Szenen (d.h. mit hohem Anteil schneller Bewegung) erhalten einen etwas höheren Quantizer, also eine stärkere Kompression. Das funktioniert, weil wir in schnellen Szenen weniger Details wahrnehmen und deshalb mehr Informationen aus dem Bild herauskomprimiert werden können, ohne das das zu spüren wäre.
  • Langsame Szenen (d.h. mit geringem Anteil schneller Bewegung) erhalten dagegen einen etwas niedrigeren Quantizer, also eine geringere Kompression. Da das Auge in solchen Szenen viel Zeit hat, auch winzige Details aufzunehmen, darf dort nicht gespart werden.

CRF berücksichtigt also zu einem gewissen Grad, wie das menschliche Auge arbeitet, und hat deshalb dem CQ-Verfahren gegenüber einen Qualitätsvorteil. Die Dateigröße eines CRF-Encodings bewegt sich normalerweise in derselben Region wie die eines CQ-Encodings mit demselben Quantizer, nutzt aber den Platz effizienter.

Kommentare