Bewegte Differenzen

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.

Wie schon bei der DCT-Transformation arbeitet der Codec auch bei der Berechnung der bewegten Differenzen nicht mit einzelnen Pixeln, sondern mit größeren Blöcken, sogenannten Makroblocks. Bei MPEG-4 ASP und H.264 sind sie 16×16 Pixel groß. HEVC erlaubt zusätzlich auch 32×32 und 64×64. Wir konzentrieren uns in diesem Kapitel auf die klassischen 16×16-Makroblocks.

Encodierung von Differenzbildern

I-Frames

Codieren wir ein Bild rein mit den Methoden aus dem letzten Kapitel, 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.

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.

»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.

Sehen wir uns ein Beispiel an:

Der Encoder bearbeitet gerade P-Frame n. Frame n−1 und Frame n−2 sind die beiden Vorgängerbilder, die schon fertig encodiert wurden und jetzt als Referenzbilder zur Verfügung stehen.

Mehrere Referenzbilder – bis zu 16 Stück – gibt es erst seit H.264. MPEG-4 ASP und alle Vorgängerformate können nur im direkten Vorgängerbild nach passenden Blocks suchen.

Ein bewegungskompensierter Differenzblock entsteht in drei Schritten:

  1. Bewegungssuche: Für jeden Makroblock wird in den Referenzbildern nach einer möglichst guten Entsprechung gesucht. Ein Referenzblock passt umso besser, je ähnlicher er dem aktuellen Block ist.

    Für Block A in unserem Beispiel konnte der Encoder keine passende Referenz finden. Deswegen wird er ohne Differenzbildung in seiner ursprünglichen Form gespeichert, ganz so, aber befände er sich in einem I-Frame. Für Block B war die beste Referenz Block B′ in Frame n−1 und für Block C konnte noch ein Frame weiter in der Vergangenheit C′ gefunden werden.

  2. Bewegungskompensation: Der Encoder gleicht die stattgefundene Bewegung aus, indem er einen Bewegungsvektor bildet. Der sagt aus, wo sich der Referenzblock räumlich im Verhältnis zum aktuellen Block befindet.

    Für Block A gibt es keinen Referenzblock und damit auch keinen Bewegungsvektor. Für Block B zeigt der Vektor ein Stück vertikal nach oben zu Block B′. Der von Vektor Block C nach C′ zeigt ein Stück nach rechts und leicht nach oben.

  3. Differenzbildung: Ursprünglich sind wir mit dem Ziel gestartet, gleichbleibende Bildteile nicht mehrfach speichern zu müssen. Genau das passiert in diesem Schritt, indem der Encoder Referenblock und aktuellen Block voneinander abzieht. Die komplette Bewegungsberechnung vorab dient nur dazu, das Ergebnis dieser Subtraktion zu verbessern.

    Ein Differenzblock ist viel gleichmäßiger und hat weniger harte Kanten als der ursprüngliche Block. Das heißt, er ist deutlich besser komprimierbar. Und da wir nur Informationen entfernt haben, die schon in früheren Frames vorhanden sind, ist die Bewegungsberechnung und Differenzbildung insgesamt verlustlos.

B-Frames

Wenden wir uns dem dritten Typ Frame zu, dem Bidirectional Frame (kurz B-Frame). Dabei handelt es sich 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.

Ähnlich wie bei P-Frames sind MPEG-4 ASP und älter auf das direkte Vorgänger- und Nachfolgerframe beschränkt, haben also insgesamt zwei Referenzen zur Verfügung. Ab H.264 dürfen es insgesamt bis zu 16 Stück sein.

Für Makroblock B liegt die beste Referenz nicht in der Vergangenheit, sondern ein Frame in der Zukunft. Besonders vorteilhaft ist diese Eigenschaft von B-Frames, wenn die Zukunft viele gute Referenzen zu bieten hat. Das kann z.B. am Ende eines Kameraschwenks der fall sein, wenn die Vergangenheit hauptsächlich Bewegungsunschärfe und damit tendenziell schlechte Referenzen enthält.

Ein Problem bleibt zu lösen: B-Frame n kann sich schlecht auf Frame n+1 beziehen, wenn Frame n+1 noch überhaupt nicht vorhanden ist. Ein Film mit B-Frames kann also nicht strikt sequenziell bearbeitet werden. Unsere kleine Bildfolge muss der Codec in der Reihenfolge n−1, n+1, n encodieren. Da sich mit der anderen Reihenfolge auch die Referenzen ändern, die Frame n+1 zur Verfügung hat, muss gut überlegt sein, wo im Film B-Frames platziert werden. Denn im ungünstigen Fall erleidet Frame n+1 einen so hohen Nachteil durch schlechtere Referenzen, dass der Vorteil wieder verloren geht, den Frame n durch seine besseren Referenzen aus der Zukunft herausholen kann.

Beispielvideo

Ein Video mehr sagt als tausend Worte. Sehen wir uns deshalb eine kurze Sequenz aus Sintel an. Die vier Panels zeigen neben dem Originalvideo die Bewegungsvektoren und zwei verschiedene Differenzbilder, einmal mit und einmal ohne Bewegungskompensation.

Direktdownload ohne Youtube

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. 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.

Wiedergabe von Differenzbildern

Dass der Großteil eines Films aus Differenzbildern besteht, hat Konsequenzen fürs Abspielen. Das 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 mitten 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.

zuletzt aktualisiert: 29.05.2016

Kommentare