Interframe-Kompression

Bisher haben wir uns nur damit beschäftigt, wie ein einzelnes Bild des Videos encodiert wird, ohne gleichzeitig auf die restlichen Bilder zu achten. Das tun wir jetzt bei der Interframe-Kompression, die identischen Inhalt über mehrere Bilder hinweg sucht und dadurch noch einmal massiv Dateigröße einspart. MPEG-Codecs kennen dafür drei verschiedene Arten von Bildern, die wir uns nacheinander ansehen.

I-Frames

Codieren wir ein Bild rein mit den Methoden aus dem letzten Abschnitt, handelt es sich um ein Intraframe (kurz I-Frame, auch Keyframe genannt), ein vollständiges Einzelbild. Wie ein JPEG-Foto kann ein Intraframe für sich alleine existieren, d.h. um es zu decodieren, werden keine Informationen aus anderen Bildern benötigt. Man kann also sagen, dass für I-Frames keine Interframe-Kompression stattfindet.

Entsprechend belegen sie von allen Frametypen am meisten Platz. Außerdem sind I-Frames zum Spulen und Schneiden des Films wichtig. Dazu aber mehr im Praxisteil des Encodingwissens.

P-Frames

Klassisches Beispiel für die Interframe-Kompression sind die Predicted Frames (kurz P-Frames). Stellen wir uns einen Nachrichtensprecher vor, der vor einem statischen Hintergrundbild seinen Text vorliest. Der Großteil dieser Szene bleibt über einen längeren Zeitraum unverändert. Die größte Bewegung geht von den Lippen des Sprechers aus.

Gäbe es nichts anderes als I-Frames, müssten wir in jedem einzelnen Bild immer wieder all die Informationen abspeichern, die sich überhaupt nicht ändern – eine riesige Platzverschwendung. Deswegen speichert ein P-Frame diese Infos nicht mehr, sondern verweist einfach auf das vorangehende Bild. Das war aber noch nicht alles. Schließlich könnte ein Teil des Bildes auch gleich bleiben, sich aber an eine andere Position bewegen. Stellen wir uns ein Auto vor, das von links nach rechts durchs Bild fährt. Auch solche »bewegten Gleichheiten« werden von P-Frames erfasst.

Der Codec arbeitet weiterhin auf der Basis von Makroblocks, die aber bei der Bewegungssuche in der Regel 16×16 Pixel groß sind, im Gegensatz zu den schon angesprochenen 8×8- oder 4×4-Blocks der Transformation und Quantisierung. Die Situation stellt sich demnach so dar: »Makroblock A ist sowohl in Bild 1 als auch Bild 2 vorhanden, nur wandert er von Position X in Bild 1 auf Position Y in Bild 2«. Wir vermeiden Verschwendung, indem wir den Block nicht ein zweites Mal in Bild 2 speichern. Was wir allerdings speichern müssen, ist der Bewegungsvektor, also die Wanderbewegung. Beim Abspielen kann der Decoder den Block aus dem alten Bild holen und mit Hilfe des Vektors an die richtige neue Position setzen.

»Gleichheit zweier Makroblocks« ist immer im Sinn von »möglichst ähnlich« gemeint. Um kleine Unterschiede auszugleichen, speichert der Codec die Differenz zwischen den Blocks. Das ist notwendig, weil in Filmen aus der realen Welt hundertprozentige Gleichheit selten vorkommt.

Ein auf diese Weise zusammengebautes P-Frame ist kein vollständiges Einzelbild mehr, sondern es speichert grob gesagt nur den Unterschied zum vorangehenden Bild. Welche Konsequenzen das besonders beim Abspielen des Films hat, sehen wir an einer kurzen Bildsequenz aus einem I-Frame und drei P-Frames.

Framesquenz aus 4 Bildern: IPPP

Wir laden den Film und möchten sofort Frame 4 am Bildschirm anzeigen. Kein Problem: Ein paar neue Makroblocks sind dort sowieso gespeichert und werden direkt aus Frame 4 decodiert. Makroblock A ist nur gewandert. Dessen Daten stehen also in Frame 3. Denkste! Nummer 3 ist auch ein P-Frame und enthält den lapidaren Hinweis: »Makroblock A ist aus Frame 2 übernommen«. Auch Frame 2 enthält einen analogen Hinweis, so dass wir den Makroblock A schließlich in Frame 1 finden. Beim Makroblock B haben wir mehr Glück, denn der findet sich schon in Frame 3.

Weiter als bis zu Frame 1 müssen wir mit Sicherheit nie zurückspringen, denn dabei handelt es sich um ein I-Frame, ein vollständiges Bild, das keine Verweise auf frühere Bilder enthält.

Damit wird klar: Wenn wir an einer beliebigen Stelle in den Film hineinspringen und P-Frame 4 erwischen, lässt sich das nur dann vollständig decodieren, wenn sämtliche Frames bis zum vorangehenden I-Frame vorhanden sind. Dem Codec bleibt dann nichts anderes übrig als zu Frame 1 zurückzugehen und von dort aus alle Frames zu decodieren, bis er beim gewünschten Bild angekommen ist. Das Splitting-Kapitel ist ein guter Ort, um sich an diese Tatsache wieder zu erinnern.

Wenn der Film ganz gewöhnlich von vorne bis hinten durchläuft, existiert dieses Problem nicht. Bevor Frame 4 an die Reihe kommt, wurde schließlich Frame 3 am Bildschirm angezeigt und musste dafür vollständig decodiert werden. Auf diese vollständige Version kann der Codec jetzt zurückgreifen. Ein weiteres Zurückspringen wird dadurch unnötig.

B-Frames

Wenden wir uns dem dritten Typ Frame zu, dem Bidirectional Frame (kurz B-Frame). Dabei handelt es sich prinzipiell um ein erweitertes P-Frame, das nicht nur Verweise auf vorangehende Bilder enthalten kann, sondern auch Verweise auf nachfolgende. An der Bildsequenz unten wird das deutlicher.

Framesquenz aus 4 Bildern: IPBP

Wir wollen direkt Das B-Frame 3 decodieren und finden für Makroblock A den Eintrag: »Aus Frame 2 übernommen«. Das kennen wir. So machen das normale P-Frames auch. Der Eintrag für Makroblock B lautet: »Aus Frame 4 übernommen«. Das ist das bidirektionale am B-Frame. Die Bidirektionalität ist auch der Grund dafür, dass B-Frames in der Regel höher komprimiert werden können als einfache P-Frames. Gut für uns, denn so belegt die gleiche Bildqualität weniger Speicherplatz.

Das offensichtliche Problem ist für den Zuschauer unsichtbar: Frame 3 kann sich schlecht auf Frame 4 beziehen, wenn Frame 4 noch überhaupt nicht vorhanden ist. Ein Film mit B-Frames kann also nicht strikt sequenziell bearbeitet werden. Unsere kleine Bildfolge müsste der Codec in der Reihenfolge 1, 2, 4, 3 encodieren und in dieser Reihenfolge auch wieder decodieren. Für die Anzeige am Bildschirm wird diese Vertauschung rückgängig gemacht. Der Decoder bearbeitet dafür nach dem Anzeigen von Nummer 2 erst Frame 4 und dann mit dessen Hilfe Frame 3. Solange Frame 3 angezeigt wird, parkt Frame 4 im Arbeitsspeicher.

Beispielvideo

Sehen wir uns zum Schluss als Beispiel eine kurze Sequenz aus Sintel an. Die vier Panels zeigen neben dem Originalvideo die Bewegungsvektoren und zwei verschiedene Differenzbilder, einmal mit und einmal ohne Bewegungskompensierung.

Das Video zeigt eine relativ simple Encodierung, die komplett aus P-Frames mit 16×16-Makroblocks besteht. Als Referenzbild dient immer das direkt vorangehende Frame. An den Bewegungsvektoren oben rechts sehen wir, in welche Richtung und wie weit sich die Makroblocks zwischen vorherigem und aktuellem Bild bewegt haben. Die beiden Differenzbilder unten zeigen jeweils die Differenz zwischen dem aktuellen und dem vorangegangenen Frame. Dabei steht mittelgrau für keine Differenz. Je weißer oder schwärzer eine Stelle ist, desto größer ist der Unterschied.

Um effizent zu arbeiten, versucht der Encoder sozusagen, soviel Mittelgrau in großen, zusammenhängenden Flächen wie möglich zu erzeugen. Denn je gleichförmiger Mittelgrau ein Bild ist – je geringer die Differenz ausfällt –, desto besser lässt es sich komprimieren.

Dass die Bewegungskompensation das Ergebnis gewaltig verbessert, sehen wir am besten am Hintergrund. Schon leichte Bewegung reicht aus, dass im linken Differenzbild (nicht kompensiert) deutliche Kantenstrukturen entstehen. Das rechte Differenzbild dagegen »weiß«, welche Bewegung abgelaufen ist, und zeigt dadurch deutlich weniger solche Strukuren.

Falls ihr selbst spielen wollt: Für das Video habe ich mir dieses AviSynth-Skript gebastelt. Bewegungssuche und -kompensation erledigen die MVTools, die Differenzbilder erzeugen die MaskTools, und das Quellmaterial waren die 1080p-PNGs von Sintel.

Auswahl der Frametypen

Für welches Bild welcher Frametyp am günstigsten ist, müssen wir zum Glück nicht selbst entscheiden. Das erledigt der Codec automatisch und heutzutage auch zuverlässig. Einstellen müssen wir in der Regel nur, wie oft ein I-Frame erzwungen wird und ob überhaupt B-Frames verwendet werden sollen. Die Auswahl des Codecs richtet sich dann nach zwei Grundregeln:

  • I-Frames stehen – außer nach dem vom Benutzer festgelegten zwingenden Intervall – nur, wenn zwei hintereinander folgende Bilder extrem verschieden sind. Bestes Beispiel dafür ist ein Szenenwechsel.
  • B-Frames eignen sich besonders für ruhige Szenen mit wenig Bewegung, denn dann bestehen zwischen einer ganzen Reihe von Bildern kaum Unterschiede und die Vorteile der Bidirektionalität kommen besonders gut zum Tragen.

Und damit haben wir eine vollständig codierte Videospur. Wir können uns also dem Ton zuwenden. Aber keine Angst, der lässt sich schneller abhandeln als das Bild.