Blog Alkis Blog #45 - Grundlagen des Videoencodings

Incredible Alk

Moderator
Teammitglied
Es wird mal wieder Zeit für einen neuen verlinkbaren Textberg. Thema dieses Mal ist ausnahmsweise nicht Hardware sondern einige grundlegende Dinge von Videokompression, sprich Software das Thema. Im Zeitalter von Twitch, YouTube und zahllosen anderen Plattformen auf denen Privatnutzer Videos hochladen oder streamen können werden immer häufiger Fragen gestellt, die sich mit der Technik hinter Videoformaten, Codecs, Container, Bitraten, Einstellungen und haste nicht gesehen befassen. Eins vorneweg: Es geht hier nicht darum zu erklären, wie man am besten streamt, es geht darum die Basics von Videokompressionen, Formaten und Einstellungen zu verstehen da sich dann die allermeisten Fragen bereits von selbst klären. Fangen wir mal ganz vorne an.


Was ist Videokompression und warum braucht man sowas überhaupt?
Wie denke ich auch unbedarfteren Personenkreisen sicherlich bekannt ist, bestehen Videos aus einer schnell aufeinander folgenden Serie von Einzelbildern (und einer/mehreren synchronen Tonspur(en) darüber die wir hier mal außen vor lassen). Was liegt also näher, als diese Daten einfach so wie sie sind abzuspeichern? Schauen wir mal was dabei so rauskommt. Nehmen wir mal an, der geneigte YouTube-Einsteiger hat mit seiner neuen Kamera ein kleines Filmchen gedreht. Auf dem aktuellen Stand der Qualität, sprich UHD und 60 fps. Lassen wir das Filmchen mal eine Minute lang sein. Da hätten wir dann 3840x2160 Pixel als Auflösung, was rechnerisch 8294400 einzelne Pixel pro Bild („Frame“) bedeutet. Jeder Pixel hat nun eine Farbe die sich aus einer Mischung von rot, grün und blau (RGB) zusammensetzt und jeder Farbkanal wird mit 10 bit Genauigkeit gespeichert. Also 30 Bit pro Pixel – macht 248832000 Bit die pro Frame gespeichert werden müssen. Bei 60 fps dann 60 mal pro Sekunde und das nochmal 60 mal um auf eine Minute zu kommen. Dann sind es entsprechend 895795200000 Bits – oder – um mal in vernünftige Einheiten zu kommen umgerechnet etwas über 100 GB.

Zumindest die Frage nach dem „warum“ sollte also schnell beantwortet sein, denn etwa 100 GB pro Minute Video sind nicht unbedingt das, was man als praxisnah bezeichnen könnte (nicht nur weil die Datenmenge riesig ist sondern auch weil man für ein Echtzeitvideo hier ~1,6 GB/s Bandbreite übertragen müsste – das schaffen nur die wenigsten Datenträger geschweige denn Internetverbindungen) – das ist aber tatsächlich die Menge an Rohdaten, die ohne Kompression, also im RAW-Betrieb, anfällt!


Codecs und Container
Wie ist es nun möglich, all diese Datenberge auf die schöne handliche Größe zu quetschen die man als Endanwender so kennt? Naja, es gibt viele Eigenschaften von Videos und auch von den Beobachtern der Videos die man sich zu Nutze machen kann, um die Datenmenge extrem zu reduzieren. Die Programme, die solche Techniken anwenden heißen „Codecs“ was eine etwas gekünzelte Abkürzung von „Kodierer und Decodierer“ ist. Bedeutet es gibt Programme, die die Datenberge in eine komprimierte Form bringen (Kodieren) zum Ablegen auf Speichermedien und wenn man sie wieder abspielen möchte die ursprünglichen Daten wiederherstellen (Decodieren) zur Ausgabe an den Bildschirm. Diese Codecs sind das, was man unter DivX, XVid, AVC, HEVC, VP9, AV1 und so weiter vielleicht schon mal gehört hat. All diese Bezeichnungen stehen für verschiedene Codecs, die unterschiedliche Ansätze und Komplexitäten verfolgen, um aus den 100 GB beispielsweise nur noch 200 MB zu machen und später wieder die 100 GB zurückzuholen.

WICHTIG: All das hat NICHTS mit Dateiendungen oder Containern oder ähnlichem zu tun! Ein Video, das im Codec „AVC“ encodiert wurde, kann Video.MP4 oder Video.MKV oder Video.MPG oder Video.AVI usw. heißen – denn das sind nur verschiedene Container („Verpackungen“). Diese Container sind dazu da, mehrere Datenspuren in eine Datei zu bekommen – denn ein Video besteht ja nicht nur aus dem Bild. Auch Tonspuren, vielleicht noch mehrere für mehrere Sprachen oder auch Untertitelspuren – man bastelt hier also ein „Paket“ das alle Daten in einer Form enthält die es einem Abspielgerät erlaubt Bild, Ton, Untertitel usw. schön gleichzeitig und synchron wiederzugeben. Wer alles bis hierhin verstanden hat erkennt nun auch, warum häufige Fragen wie „Kann Gerät/Player/Grafikkarte eine MP4-Datei abspielen“ oder vergleichbares unsinnig sind da es beispielsweise darauf ankommt, ob der MP4-Container eine AVC oder eine HEVC-codierte Videospur enthält – und was davon das gerät kann und was nicht.


Methodiken
Aber zurück zur Frage, wie die Kompression eigentlich funktioniert. Wie bereits erwähnt gibt es da sehr viele Techniken die zumindest von der Logik her auch meist einleuchtend sind, programmiertechnisch aber durchaus sehr komplex sein können. Grundsätzlich unterscheiden wir wie üblich zwei Kategorien: Verlustfreie und verlustbehaftete Kompression. Im Videobereich ist nahezu alles was man so kennt (stark) verlustbehaftet. Das liegt weiterhin schlichtweg an den sonst viel zu hohen Datenmengen. Verlustfrei wird man die 100 GB von oben vielleicht auf 10-20 GB eindampfen können (was immer noch eine irre Leistung ist da 80-90% eingespart werden!) aber mit 20 GB pro Minute kann man noch immer keinen Blumentopf gewinnen. Erst durch gezielte Verluste kommt man nochmal um weitere 80-90% runter. Sehen wir uns mal an was genau passiert.

Zusammenfassen (verlustfrei möglich)
Verlustfreie Techniken basieren im Wesentlichen darauf, dass gleiche Informationen nicht mehrfach gespeichert werden müssen. Ist in einem Bild die Farbe eines Pixels genau die gleiche wie die seines Nachbarn, müssen keine zwei kompletten Informationsbausteine abgelegt werden sondern nur einer und ein Hinweis der bedeutet „der Nachbar ist gleich“. Dieses Prinzip funktioniert natürlich mit ganzen Bildbereichen – und zwar nicht nur örtlich sondern auch zeitlich. Hat ein ganzer Bereich in einem Video die gleiche Farbe oder ist ganz schwarz oder weiß so kann ich den Bereich abgrenzen und abspeichern „alles darin ist weiߓ was natürlich viel sparender ist als für jeden einzelnen Pixel „7239562348,#000000“ (Pixelnummer, Farbwerte) zu speichern. Und in Videos ist es prinzipbedingt so, dass ein nachfolgender Frame sich in aller Regel nur minimal von dem vorhergehenden unterscheidet. Ist der gleiche Bereich eine Sechzigstel Sekunde danach noch immer weiß sind keine weiteren Informationen notwendig um den Bereich so darzustellen.

Referenzieren (verlustfrei möglich)
Darauf beruht das wohl mächtigste Kompressionswerkzeug für Videos: Der Trick ist, nicht alle Bilder abzuspeichern sondern nur ein Bild (das erste) komplett zu speichern und für die danach folgenden nur die Änderungen zum jeweils vorherigen Bild zu speichern. Ein Video, das um den Extremfall zu nehmen ein Standbild darstellt hätte im optimalen Falle nur die Größe einer Bilddatei des Bildes da alle darauf folgenden Frames keine Informationen speichern müssten – es ändert sich ja nichts. In der Fachsprache nennt man diese Dinge I-Frames, B-Frames oder P-Frames, je nachdem welche Informationen für diese Einzelbilder wie abgelegt sind. Das führt hier sicherlich zu weit, mit den Begriffen kann jemand der tiefer einsteigen will aber Google zu viel Informationsherausgabe bewegen. Und dem mitdenkenden Leser ist an der Stelle vielleicht schon klar geworden, warum Videos mit sehr schnellen und wilden Szenen mehr Speicherplatz benötigen als ruhige Szenen von Dokumentationen oder Überwachungskameras.

Referenzen optimieren (verlustfrei möglich)
Wir haben nun also in den Einzelbildern unseres Videos gleiche Bereiche zusammengefasst und speichern statt ganzer Bilder nur noch die Veränderungen zum Bild davor. Nicht schlecht. Aber was würde nun passieren, wenn eine Datei einen kleinen Fehler enthält? Wenn alle Informationen auf denen davor aufbauen reicht ein kleiner Übertragungsfehler und das Video kann nicht mehr dargestellt werden da der Bezug zur abgespeicherten Veränderung fehlen würde oder falsch ist. Und in Videos springen würde auch nur dann gehen, wenn der Encoder sich dann bis zum Zielpunkt vorarbeitet (wenn ich nur das erste Bild speichere und dann nur noch Veränderungen muss ich zum Springen an Sekunde 50 alle Daten davor voll bearbeiten was natürlich elend langsam ist). Da das nicht sinnvoll ist muss man also ab und zu schon ein „Vollbild“ abspeichern auf das man sich wieder beziehen kann in den Nachfolgebildern. Dann zerstört ein kleiner Fehler nicht die ganze Datei sondern bildet nur ein „Artefakt“ bis zum nächsten Vollbild und man kann in der Datei springen, da man an jedem vollen Einzelbild wieder „anfangen“ kann. Weiterführende Techniken (nur ums zu erwähnen) beschäftigen sich nun beim encodieren im Voraus damit, wo man dieses Vollbild sinnvollerweise einsetzt – beispielsweise gezielt bei einem harten Szenenwechsel wo sich Bild n+1 völlig von Bild n unterscheidet statt einfach statisch alle 250 Frames. Und manchmal ist es sinnvoll, sich nicht immer nur auf das Bild davor zu beziehen sondern auf das 5 davor oder 3 danach – teilweise sogar innerhalb eines Frames kann es Bezüge zu anderen Frames davor oder danach geben („mixed references“ nennt sich das). Hier gibt’s also schon sehr ausgeklügelte Mechanismen – und wir sind noch immer im verlustfreien Bereich!

Bewegungssuche (verlustfrei möglich)
Bisher haben wir uns darauf beschränkt, gleiche Pixel oder Bereiche in umliegenden Frames zu suchen und darauf zu beziehen. Schön. Nun ist es aber in Videos meist so, dass ein nachfolgendes Bild genauso aussieht wie das vorherige – aber es etwas verschoben ist, etwa bei einem Kameraschwenk. Die Pixel sind alle übertrieben gesagt die gleichen - nur eben 10 Pixel weiter rechts. Die obige Methode hätte keine Chance und müsste alles neu abspeichern weil sich ja jeder Pixel verändert hat. Um das zu erfassen gibt es eine Bewegungssuche („motion estimation“). Diese Funktion schaut sich einen Bereich in Frame n an und dann den gleichen Bereich in den darauf folgenden Frames. Findet die Funktion ihren Bereich wieder nur ein paar Pixel verschoben wird nur der Bewegungsvektor für diesen Bereich gespeichert. Diese Analyse ist wie man sich vorstellen kann sehr rechenintensiv – aber auch sehr effektiv. Nach welchem Muster über wie viele Frames und wie „weit“ (räumlich) gesucht werden soll kann man in modernen Codecs einstellen, das sind Kodierparameter die zwischen effektiv und langsam oder ineffektiv und schnell entscheiden aber dazu weiter unten mehr.

Mathematik (verlustfrei)
Nicht erschrecken, ich machs kurz: Die oben genannten Techniken waren ein grober Abriss über die wichtigsten verlustfreien Kompressionsmethoden: Referenzierung und Bewegungssuche. Die Dritte standardmäßige Methode ist das, was man von normalen Datenpackern (zip, rar, 7z,…) kennt: harte Datenkompression. Hier kommt eine auf Videodaten optimierte Packerversion zum Einsatz (wers genauer wissen will nach „CABAC“ googeln) – ein Packprogramm, das alle generierten Daten noch mal durch die Datenkompression (völlig unabhängig vom Videoinhalt) schickt um die Datei zu verkleinern. Da das standardmäßig genutzt wird können Videodateien auch nicht mit etwa WinRAR nennenswert verkleinert werden – eine solche Kompression hat schlichtweg bereits stattgefunden.

Seh- und Hirnschwächen (verlustbehaftet)
Nun haben wir die größten Potentiale verlustfreier Kompression eigentlich abgehakt – die Datei ist aber immer noch viel zu groß. Jetzt kommt der schwierigere Teil: Was kann ich im Video an Informationen wie weglassen, dass der (darauf untrainierte) Mensch es nicht bemerkt? Genau wie man es von MP3 in der Musik kennt gibt es auch in der Videokompression Techniken, die gezielt Dinge weglassen, die für uns Menschen nur sehr schwer oder gar nicht erkennbar sind. Und da sind wir von MP3 stellenweise sogar gar nicht so weit weg. Die Fourier-Transformation, die in MP3 Anwendung findet, wird auch in vielen Codecs genutzt – hier geht es darum, dass Wellenformen von Tönen und Farbverläufen statt sie exakt abzuspeichern mit Wellenfunktionen angenähert werden die sehr sehr nahe am Original sind (wie nahe hängt von der Bitrate ab, siehe unten…) und ein Mensch den Unterschied nicht erkennt – eine Funktionsgleichung zu speichern und beim decodieren Werte einzusetzen ist aber sehr viel platzsparender als die ganzen Einzelwerte im Klartext abzuspeichern. Fun-Fact am Rande: Speichert man neben der Funktion auch die Differenz des Funktionsergebnisses zum Original mit ab ist das Verfahren wieder verlustfrei – das ist die wesentliche Technik von FLAC.

Ähnlich dieser kurz angerissenen Funktion gibt es jetzt Hunderte Techniken, die ausnutzen, wie nachlässig unser Auge-/Hirnapparat eigentlich beim ansehen von Filmen ist und hören von Musik. Es ist beispielsweise möglich (und üblich!), nur bei jedem zweiten oder vierten Pixel überhaupt die Farbe abzuspeichern, bei allen anderen reicht die Helligkeit („Chroma Subsampling“), denn das Hirn baut automatisch und unbewusst fehlende Farben wieder ein. Bei Szenen, die schnelle Bewegungen enthalten werden dort, wo diese Bewegungen im Bild sind, viele Informationen weggelassen weil unser Gehirn sie ohnehin nicht gesehen hätte (niemand erkennt die einzelnen Bartstoppeln eines schnell vorbeilaufenden Menschen – hier reicht es eine hautfarbene Fläche anzuzeigen) – langsame Stellen im Video müssen dagegen genauer gespeichert werden da man da länger hinsehen kann und Fehler bemerken würde….bleibt der Läufer im Bild stehen würde man sehr wohl seine Bartstoppeln erkennen. Das geht soweit, dass es Funktionen in modernen Codecs gibt die auf menschliche Psychologie trainiert sind und sehr genau wissen wo man welches Detail wie weglassen kann ohne dass es dem gemeinen Menschen auffällt – beispielsweise sind harte Kontrastkanten immer gut zu erkennen, da das Hirn darauf trainiert ist sowas zu erkennen, weiche Farbverläufe müssen dagegen weniger genau sein.
Auch hier will ich nicht zu sehr ins Detail gehen damit der Eintrag hier nicht Bücher füllt, wer sich hier genauer belesen will kann sich die Dokumentation des h.265-Codecs („HEVC“) mit all seinen Einstellparametern ansehen. Diese Dokumentation ist öffentlich und enthält viele Informationen darüber welche Funktionen es hier gibt und was sie bewirken.


Bitraten
So lange wir nur verlustfrei komprimieren stellt sich die Frage nach einer einstellbaren Bitrate (also wie viele Daten pro Zeit generiert werden) nicht – denn sie wird durch das Material und den Codec vorgegeben. Sobald wir allerdings anfangen, verlustbehaftet zu komprimieren, stellt sich die Frage, wie viel Verluste wir denn erlauben wollen. An der Stelle gibt es zwei grundsätzliche Prinzipien zu verstehen: Erstens wie hoch die Menge der abgespeicherten Daten sein darf und zweitens welche Informationsdichte die gespeicherten Daten haben sollen/können.

Das erste Prinzip ist zunächst einfach: Je mehr Speicherplatz ich erlaube (je höher die Bitrate ist) desto besser wird das Ergebnis sein weil weniger weggelassen werden muss, ganz klar. Beim zweiten Punkt ist es etwas komplizierter, denn es gibt große Unterschiede in der „Informationsdichte“ gespeicherter Dateien. Es ist beispielsweise heute möglich, ein FullHD Video von einer Minute Länge in 10 MB abzuspeichern wo man vor 10 oder 20 Jahren noch 50 MB gebraucht hätte um die gleiche Qualität zu erreichen. Der Grund ist, dass die Informationsdichte/-qualität in der 10 MB-Datei wesentlich höher/besser ist, da der heute verwendete modernere Codec viel mehr Techniken anwendet und diese auch viel optimierter nutzt als es vor 20 Jahren möglich war (anders gesagt der Informationsgehalt pro gespeichertem Zeichen ist höher) – dafür aber auch deutlich mehr Rechenzeit verlangt.

Datenmenge
Aber der Reihe nach. Wie legt man eigentlich fest, wie viel Speicher ein Encoder verbrauchen darf bzw. welche Bitrate er verwenden soll? Die einfachste und primitivste Art ist die CBR-Methode – constant bitrate. Man sagt dem Encoder ganz simpel: „Benutze 10.000 kb/s Bitrate“ als Beispiel (Hinweis: Bitraten werden immer in KiloBIT angegeben, nicht KiloBYTE). Das hat sogar einen Vorteil: Der Nutzer weiß bereits im Voraus, wie groß die Enddatei werden wird, da mans ganz simpel berechnen kann: Wenn ich 10.000 kb/s an Bitrate habe und mein Video dauert eine Minute wird die Datei 73,2 MiB groß werden (ohne Ton). Besonders schlau ist das aber nicht…

Wie wir oben gelernt haben, unterscheiden sich die Anforderungen an einen Encoder und die Bitrate extrem, je nachdem was auf dem Bild gerade zu sehen ist: Für schnelle Szenen müssen mehr Informationen abgelegt werden als für langsame, für sehr detailreiche Bilder mehr als für große einfarbige Flächen. Ist die Bitrate nun konstant festgelegt ist es häufig so, dass für die „einfach“ komprimierbaren Stellen zu viel Bitrate da ist (es wird detailreicher gespeichert als der Mensch es erkennen könnte) und für die „schwierigen“ Szenen zu wenig Bitrate da ist (wenn die Szene schneller wird entstehen „Blöckchen“ / Artefakte weil die Bitrate nicht reicht, um alle Details vernünftig abzuspeichern). Es wäre doch super, wenn man die Bitrate variieren könnte, um weniger bei ruhigen Szenen zu verbrauchen und den gewonnenen Speicher für die schnellen Szenen zu verwenden die dann mehr verbrauchen dürften. Und genau das gibt es als ABR-Methode – average bitrate. Hier legt man zwar auch das Ziel von 10.000 kb/s fest, der Wert ist aber nur ein „Richtwert“. Der Encoder darf sich beispielsweise zwischen 2500 und 20.000 bewegen je nach Bildinhalt (die Grenzen müssen natürlich auch festgelegt werden um ein Abspielgerät nicht zu überfordern wenn etwa zwischen 2500 und 80.000 geschwankt werden dürfte, das Gerät aber nur 50.000 maximal packt).
Woher „weiߓ der Encoder aber nun, wo er viel und wo er wenig Bitrate benötigt und was er wo verbrauchen darf damit er am Ende bei durchschnittlich 10.000 rauskommt? Er weiß es eben nicht – und das ist ein Problem. Abhilfe schafft hier das sogenannte 2pass-Verfahren: Der Encoder muss zwei Mal durch das ganze Video laufen. Der erste Durchgang erstellt keine komprimierte Datei sondern ist nur ein Analysevorgang bei dem der Encoder herausfindet, an welcher Stelle des Videos er viel oder wenig Bitrate brauchen wird um die Bildqualität einigermaßen konstant zu halten und am Ende auf den gewünschten Mittelwert zu kommen. Das merkt er sich als Parameterdaten und im zweiten Durchlauf findet dann die eigentliche Kompression statt die dann auch in etwa (nicht genau da der Analysevorgang grob ist) die Zielmarken trifft. Die Ergebnisse dieser Methode sind bereits sehr viel besser als die der CBR-Methode, hat aber auch den Nachteil, dass ein zweiter Durchlauf nötig ist. Das ist nicht nur langsamer sondern auch prinzipbedingt für Streaminganwendungen unbrauchbar. Ein „Live“-Encoding ist damit nicht möglich – aber selbstredend gibt’s auch hierfür eine Technik.

Modere Codecs sind in der Lage, über komplexe Quantisierungsverfahren sogenannte Ratings zu erfüllen was die Bildqualität angeht. Das bedeutet, der Benutzer legt keinerlei Bitraten mehr fest sondern sagt dem Encoder nur noch, wie gut das Ergebnis denn aussehen muss und der Encoder wählt dynamisch die passenden Bitraten aus, da Encoder ja mittlerweile verstehen, wie ein menschliches Hirn die Qualität eines Videos beurteilt. Diese Methode nennt sich CRF – constant rate factor. Man sagt dem Encoder beispielsweise nur noch man wünscht einen CRF von 20. Der CRF-Wert bewegt sich sich normalerweise zwischen 0 und 64, wobei kleinere Werte eine bessere Bildqualität bedeuten – „0“ ist dabei verlustfrei (kann man mal probieren um zu sehen wie riesig Videodateien da werden…). Werte zwischen 15 und 30 sind gängig für „sehr hohe Qualität“ (15-18) bis „für YouTube geht’s noch“ (26-30) sozusagen. 20-23 sind gängige ich nenns mal „Preis-Leistungs-Einstellungen“, also ordentliche Qualität bei vernünftig kleiner Dateigröße. Was nun bei "CRF20“ am Ende genau für eine Datenmenge rauskommt weiß man aber im Voraus nicht – denn es kommt nunmal auf die Bildinhalte an. Die Minute Dokumentation kommt vielleicht auf 5 MB raus während die Actionszene gleicher Länge bei gleicher Bildqualität 25 MB belegt. Aber der Riesenvorteil der Methode ist: Die Bildqualität ist immer gleich gut/schlecht. Das „Rating“ braucht dabei keinen 2pass: Der Encoder macht das vorausschauend im Flug sozusagen, es ist kein extra-Durchgang nötig da ja kein durchschnittliches Bitratenziel eingehalten werden muss (entsprechend muss der Encoder nicht wissen ob das Ende eines Videos eher schnell oder eher ruhig ist). Damit kann man also wunderbar streamen mit einer Verzögerung von nur einer handvoll Frames (die der Encoder sich im Voraus ansehen muss um die benötigte Bitrate zu bestimmen oder zu wissen wo man sinnvollerweise das nächste Vollbild einfügt) – die hochwertigste Streamingmethode was das betrifft ist ein CRF kombiniert mit einer max-bitrate. Bedeutet wenn der Streamer beispielsweise 16.000 kb/s Upload hat stellt er CRF23; maxrate 12.000 (etwas Puffer sollte man schon lassen) ein und hat immer die gleiche Bildqualität es sei denn der Encoder würde mehr Daten erzeugen wollen als die Leitung packt, da wird dann begrenzt - der Encoder hebt in dem Falle temporär selbstständig den CRF an.

Nun sollte schon mal klar sein, wie die Datenmenge generiert wird und woher das Programm weiß, wie hoch die Bitrate zu sein hat.

Datenqualität
Aber was hat es nun mit der Datenqualität auf sich? Wie oben schon erwähnt gibt es Hunderte von Techniken, um immer bessere und optimalere Kompressionsgrade zu erreichen, also mehr Bildqualität bei weniger Bitrate/Speicherverbrauch. Nun ist es naturgemäß so, dass besonders gute/optimierte Verfahren natürlich auch besonders rechenintensiv sind. Wenn ich jeden einzelnen Pixel daraufhin untersuchen möchte, ob in den 10 Frames davor und danach der Pixel vielleicht im Umkreis von 64x64 Pixeln nochmal auftaucht suche bzw. rechne ich mich zu Tode. Die Kunst ist es also an der Stelle, Techniken zu nutzen und Einstellungen zu wählen, die mit den vorhandenen Mitteln ein qualitativ ausreichend gutes Ergebnis bei vertretbarem Speicherverbrauch und vertretbarer Rechenzeit erzeugen. Wenn ich das eigene Hochzeitsvideo speichern möchte will ich eine sehr hohe Qualität erreichen – ob die Datei dabei 500 MB größer oder kleiner ausfällt ist hier genauso egal wie ob mein PC für die Berechnung 10 Minuten oder 10 Stunden benötigt. Will ich dagegen mein aktuelles Counterstrike-Spiel auf Twitch zeigen muss ich darauf achten dass erstens die Bitrate ausreichend klein bleibt um meine Internetverbindung nicht zu überlasten und die Einstellungen des Encoders so zahm sind dass meine CPU (oder GPU – kommt noch…) nicht einknickt. Die Bildqualität ist dabei zweitrangig.

Um dem Nutzer hier die Detailarbeit zu ersparen die unzähligen Funktionen moderner Encoder einzustellen, zu probieren, zu verstehen usw. haben die Entwickler hier sogenannte Presets erstellt, die aufeinander abgestimmte Encodiereinstellungen enthalten. Diese Presets reichen von „ultrafast“ (sehr geringe Rechenleistung nötig, das Ergebnis ist aber sehr ineffizient kodiert) bis hin zu „veryslow“ (sehr viel Rechenleistung nötig aber es werden alle Register des Kodierers genutzt um ein maximal effizientes Ergebnis zu erzielen). Man muss sich also nur noch überlegen welche Qualität man anstrebt (CRF) und wie viel Power die Mühle hat um sie umzusetzen bzw. wie lange der Komprimiervorgang dauern darf (Preset).
Nochmal zum Verständnis: Das Ergebnis der Bildqualität ist beim gleichen CRF (fast) gleich, nur wird ein „fast“-Preset nach 20 Sekunden eine Datei ausgeben die 30 MB groß ist und ein „slow“-Preset nach 5 Minuten eine Datei ausgeben die 10 MB groß ist als Beispiel.

Professionellere Nutzer stellen oftmals ihre eigenen Presets ein bzw. basteln sich ihre Kodiereinstellungen genau für ihre Bedürfnisse und das zu kodierende Material – teilweise sogar mit wechselnden Einstellungen für verschiedene Videobereiche (ein Abspann muss nicht mit dem gleichen CRF kodiert werden wie der Clip selbst). Das erfordert aber sehr viel Erfahrung und tiefgreifende Kenntnisse der einzelnen Settings, daher die Empfehlung an alle in dem Thema neueren: Wählt einen passenden CRF so dass die gewünschte Qualität erreicht wird und wählt ein Preset das so stark wie möglich aber so schwach wie nötig ausfällt dass die Rechenzeit in Ordnung geht. Die „Werkspresets“ sind bereits sehr ordentlich eingestellt.


Hardwarebeschleunigungen
All die bisher genannten Zusammenhänge lassen eines erkennen: Videokompression ist nicht nur inhaltlich ein sehr komplexes Thema sondern auch hardwareseitig extrem anspruchsvoll. Algorithmen, die Milliarden von Pixeln in Sekundenbruchteilen erkennen, vergleichen, referenzieren, verschieben und so weiter verlangen natürlich nach brutaler Rechenleistung, uns zwar sowohl mein Encodieren als auch beim Decodieren. Dies bemerkt der normale Nutzer in aller Regel gar nicht – denn auf nahezu allen PCs, Tablets, Smartphones ist es heute gar kein Problem mehr, hochauflösende Inhalte etwa bei YouTube oder Twitch sofort ruckelfrei wiederzugeben. Das liegt daran, dass in moderneren Grafikeinheiten dedizierte Einheiten integriert sind, die genau diese Codecs in Hardware gegossen implementiert haben. Jede moderne GPU oder SoC hat einen Baustein drin, der etwa den HEVC-Codec beherrscht. Diese Schaltkreise können sonst nichts außer genau den einen Codec abarbeiten – das aber extrem schnell und effizient. Auf diese Art ist es möglich, dass ein Smartphone oder ein TV-Gerät bei 2 Watt Chipverbrauch ein UHD-Video ruckelfrei abspielen kann. Um den Unterschied zu zeigen: Ein Core i9 9980XE oder ein Threadripper 2990WX kann das mangels dafür nötiger Grafikeinheit NICHT! Ein UHD-HEVC Video mit voller Bitrate und Farbraum ist auf einer aktuellen High-End CPU ohne GPU-Beschleunigung eine Diashow (wer möchte kann das mit den „jellyfish“ Beispielvideos im Netz ausprobieren), aber bereits die kleinste iGPU hat damit kein Problem. Auf diese Weise hat man das Problem gelöst, der breiten Konsumentenmasse eine Lösung bereitzustellen, die derartige Videos abspielt. Schwieriger wird es aber für die Ersteller der Videos, denn da gibt es keine so einfache Möglichkeit.

Videocodecs sind sehr „einseitig“, was die nötige Rechenleistung zwischen encodieren und decodieren angeht. Zwar ist das decodieren bereits schwer genug (so dass man wie beschrieben dedizierte Chipeinheiten dafür benötigt wenn es hochauflösend ist), aber prinzipiell macht der Decodierer nur das, was als Anweisung in der komprimierten Datei hinterlegt ist um Bildmaterial zu rekonstruieren. Das Encoding, also das Erstellen der Anweisung sozusagen, ist nochmal um ein vielfaches rechenintensiver. Hier gibt es im Wesentlichen zwei Ansätze um dem Herr zu werden: Optimierung der Encoder auf bestehende Hardware – und umgekehrt Entwicklung von Hardware für bestehende Encoder. Wir wollen uns beides kurz anschauen um am Ende auf Vor- und Nachteile der verschiedenen Methoden einzugehen da gerade dieses Thema (CPU gegen GPU Encoding als Beispiel) häufig nicht verstanden wird.

Optimierungen auf vorhandene Chips
Um (bereits gut programmierte) Algorithmen auf modernen CPUs schneller/effizienter zu machen gibt es eigentlich nur zwei Chancen – Ausnutzung von Befehlssatzerweiterungen und Parallelisierung auf viele Threads. Beides wird im Falle moderner Videocodecs versucht möglichst auszureizen. Als wir weiter oben die gängigsten Techniken beleuchtet haben ist aufgefallen, dass es viel um Vergleiche, Verschiebungen, gleiche Bereiche und so weiter geht. Mathematisch gesehen sind sehr viele dieser Dinge eine Ansammlung von unzähligen, teilweise sich sehr stark ähnelnden Vektoroperationen. Dafür gibt es sehr mächtige Befehllsätze, bekannt unter „AVX“ – advanced vector extensions. Wer öfter mal in meine Blogs schaut wird AVX schon detaillierter kennen, daher spare ich mir den erneuten Ausflug – es geht nur darum zu erwähnen dass AVX (1/2/512) eine massive Erhöhung der Performance von Encodierern zur Folge hat da viele Funktionen von Videokompression sehr gut zur Funktionsweise von AVX passen und auch mittlerweile selbst in Freewaretools sehr gut ausgenutzt wird – was in manchen Systemen dazu führt, dass CPUs beim Videoencodieren auf einmal besonders heiß oder instabil werden wenn der Nutzer vorher nur auf Spiele oder mit uralten Prime95-Versionen getestet hat da AVX ja „nicht praxisnah“ ist – das ist es heutzutage sehr wohl, aber das ist ein anderes Thema.

Bei der Optimierung auf viele Threads wird’s schon schwieriger. Das gelingt nur dann, wenn man die Encodierarbeit in passende „Häppchen“ zerlegt mit denen man dann die Threads unabhängig voneinander füttern kann. Genau das wird auch getan – der h.264-Codec (AVC) beispielsweise zerlegt beim Encodieren jedes Bild erst mal in 16x16 Pixel große Kästchen („Tiles“) die dann weiter bearbeitet werden. Alles, was innerhalb des Kästchens analysiert/berechnet wird kann ein einzelner Thread/Kern der CPU für sich alleine erledigen – ist doch super parallelisierbar, oder? Leider nicht. Denn blöderweise ist es sehr ineffizient Kästchen einzeln zu encodieren und danach wieder zusammenzusetzen. Nicht nur, dass viele Encodiertechniken da nicht funktionieren (ich kann keinen Pixel von Kästchen 1 in Kästchen 2 verschieben wenn der Thread 1 von Kästchen 2 und dessen Inhalt gar nichts weiß), an den „Schnittstellen“ muss es auch eine Kommunikation geben um keine sichtbaren Ränder zu erzeugen – in älteren bzw. sehr schlecht encodierten Clips ist es nicht schwierig, die einzelnen Kästchen schön zu erkennen…

Das soll natürlich nicht sein – es gibt also durchaus einen seriellen Programmieranteil der dafür sorgt, dass solche Effekte nicht auftreten – aber das ist nunmal nicht parallelisierbar (auch wenn man sich mit eigens dafür entwickelten weiteren Techniken wie etwa wavefront parallel processing etwas zu helfen versucht). Grundlegend ists so, dass die Parallelisierbarkeit umso besser ist, je größer die Kästchen gewählt werden und je mehr Arbeit pro Pixel ansteht. Hauptsächlich deswegen ist beispielsweise der neuere h.265-Codec (HEVC) besser auf CPUs mit zig Threads unterwegs als der ältere AVC, denn HEVC arbeitet mit bis zu 64x64 Pixeln großen Tiles und verfügt über weitaus aufwändigere Analysemethoden beispielsweise hinsichtlich genannter motion estimation. Und hier ist auch der Grund dafür, warum User gegensätzlich behaupten bei ihnen würde ihre neue 32-Thread-CPU kaum ausgelastet werden beim HEVC-Encode wo andere User eine 90+% Last auf allen Threads sehen: Der eine streamt mit schnellen Settings auf Twitch (kleine Kästchen, wenig Arbeit pro Pixel à schlecht parallelisierbar aber wenig Rechenaufwand), der andere konvertiert seine aufgenommenen Videos für YouTube (große Kästchen, viel Arbeit pro Pixel à gut parallelisierbar, viel Rechenaufwand). Da aber nur die allerwenigsten Nutzer diese ganzen Hintergründe verstehen ist es sehr schwierig an der Front zu diskutieren oder aufzuklären (vielleicht gibt’s ja den einen oder anderen Fall der jetzt klar wird wenn sich jemand wirklich den ganzen Text hier angetan hat ;-)).

Chipentwicklungen für Encoding
Der andere mögliche Weg effizient und schnell zu encodieren ist selbstverständlich, entsprechende Chips zu entwickeln, die für speziell dieses Gebiet optimiert sind. Diese gibt es natürlich bereits, in vollumfänglichem Funktionsumfang aber ausschließlich im professionellen Bereich und für horrende Geldsummen. Wir reden hier von Chips die in professionellen TV-Kameras und/oder Sendeequipment verbaut sind – der aktuelle Stand der Technik ist an der Stelle, 8K-Videos in Echtzeit in HEVC wandeln zu können. Diese Hardware ist natürlich für uns Normalkunden weder zu bekommen noch zu finanzieren (wir reden von fünf- bis sechsstelligen Summen). Also hat die Industrie einen gangbaren Zwischenweg gefunden und die Grafikeinheiten, die ohnehin schon die Videoausgabe beschleunigen konnten auch Richtung Encoding aufgeblasen. Alle neueren Grafikkarten von beiden großen Herstellern (in dem Falle sogar drei Hersteller, die Intel-iGPUs können das auch) bieten mittlerweile Möglichkeiten, in Echtzeit und mit vergleichsweise sehr geringer Hardwarebelastung Videos direkt in den HEVC aufzuzeichnen. Nun wird sich der geneigte Leser vielleicht fragen, wie AMD, Intel und NVidia hier so einfach Funktionen für kleines Geld im Massenmarkt bereitstellen können wo hochspezialisierte Firmen für Hunderttausende von Euro Spezialhardware anbieten müssen. Die Antwort liegt in den ganzen oberen Abschnitten begraben: Selbstverständlich kann beispielsweise CUDA in Form des „nvenc“ in Echtzeit HEVC-Videos erstellen – aber das technisch nur extrem rudimentär oder um es anders zu sagen es werden 90% der Möglichkeiten des Codecs ganz simpel nicht genutzt. Für die Anwendungsgebiete dieses sogenannten GPGPU (general purpose GPU) ist das auch nicht weiter tragisch, denn das Ziel mit möglichst wenig Hardwarelast fix einen Stream produzieren der sofort hochgeladen werden kann wird hervorragend erreicht. Man darf hier nur eben nicht den Fehler machen, diese Art von Videoencoding mit der CPU-Variante zu vergleichen die alle Funktionen des HEVC auf Wunsch ausführen kann. Unzählige Male wenn Leute sich über die Performance von Videokodierern streiten fällt der Satz „dann machs doch auf der GPU das ist viel schneller“. Ja, ist es – und viel schlechter. Dass viele so denken liegt natürlich auch an gewissen Marketingstrategien der GPU-Hersteller, die selbstredend damit werben wie extrem schnell ihre GPUs die HEVC-Encodierung beherrschen. Dass eine halbwegs flotte CPU das mindestens genauso schnell kann wenn man die Kodierparameter entsprechend vergleichbar setzt wird dabei nicht erwähnt. Es geht dabei gar nicht darum, Kodieren auf CPUs oder GPUs gut oder schlecht zu reden, es geht darum, dass man sein Einsatzgebiet und sein Ziel kennen sollte und die passende Methode und Einstellungen wählen muss, um ein sinnvolles Ergebnis zu erhalten. Ist das Ziel ein Qualitativ hochwertiges Bild und/oder eine möglichst kleine Dateigröße zu erreichen führt kein Weg am CPU-Encoding mit starken Einstellungen (hohen Presets und kleinem CRF) vorbei – eine GPU kann so etwas technisch einfach nicht. Will man dagegen in Echtzeit seine Spielerei streamen ohne dass die Hardware allzu sehr mit dem Video statt mit dem Spiel beschäftigt ist wäre man dumm, die Möglichkeiten der Grafikkarte nicht zu nutzen – auf Streamingportalen kommts auch weder darauf an das letzte MB an Speicher zu sparen noch muss die Bildqualität Hollywoodniveau erreichen.



An der Stelle würde ich sagen reicht es auch erstmal, auch vor dem Hintergrund, dass mein Textprogramm mir dezent anzeigt, dass ich bereits die 5000-Wörter-Grenze überschritten habe. Ich will mal versuchen es nicht völlig zu übertreiben, hoffe aber am Ende dass für alle, die sich das bis hierhin angetan haben die Thematik insgesamt klarer geworden ist und viele Fragen sich jetzt gar nicht mehr stellen. Für alle Fragen die dennoch übrig sind gibt’s wie immer die Kommentarfunktion da unten oder selbstredend auch den Rest des Forums.
 
Moin Alki, ich habe letztens einen Stapel von Videos archiviert und mir ist aufgefallen, dass sich keine von den Video-Dateien im Player abspielen ließen. Soweit ich weiß waren diese mit H264 als mp4 gespeichert.
Also hab ich die Dateien einmal durch Handbrake gejagt und mit praktisch gleichen Einstellungen wieder exportiert, und die Dateien konnten wiedergegeben werden.
Hast du eine genauere Ahnung, was da genau passiert ist?

PS: Anscheinend hat sich beim Umzug des Forums die Formatierung hier und da aufgelöst. Schade um deinen Blog, alle Texte noch mal zu überprüfen dürfte echt Arbeit sein.
 
Ja, der Import hat mit mancher Formatierung und manchen "Sonderzeichen" wie etwa einem "-" so seine probleme gehabt. Aber es ist ja nach wie vor lesbar deswegen hab ich mir nicht die Arbeit gemacht das manuell auszubessern.

Zur Frage: Nur wenn Codec und Container (H.264 und MP4) unterstützt werden vom Ausgabegerät/Software bedeutet das nicht automatisch, dass auch alle Funktionen des Codecs komplett unterstützt werden. Beispielsweise (gerne genommen) die Farbtiefe oder Farbunterabtastung - du kannst in H.264 die Farbtiefen 8 oder 10 oder 12 bit wählen. 8 bit sind Standard (da für fast alles ausreichend und weniger rechenintensiv), bei hochqualitativem Material sollte man eher 10 bit wählen (12 brauchts nur für professionelles editing). Da gefühlte 99,9% des h.264-Materials in 8 bit codiert sind haben viele Geräte und auch Software nur diesen Decoder drin und können mit 10bit nichts anfangen (oder sind unglaublich langsam).
Genauso verhält es sich auch mit manch anderen tieferen Einstellungen - wenn man Codecs wirklich ausreizt in ihnen Funktionen kanns passieren, dass manche Hard- und Software beim Decodierversuch dicke Backen macht.^^
Was da wo welche Funktionalität hat ist meist ziemlich schwer herauszufinden da viele Hersteller immer nur "unterstützt AVC, HEVC, VP9" schreiben als Beispiel aber selten dabeisteht obs vollumfänglich ist oderwie beschrieben etwa nur 8-bit Material.
NVidia hat eine große Tabelle welche Hardware was genau kann (als Positivbeispiel):
 
Ich hab es gestern das erste Mal gelesen und wollte dir mal meinen Dank und Applaus aussprechen. :daumen:
Ich werde mich nämlich selbst mit dem Thema auseinandersetzen müssen was für meine Filmbibliothek am ehesten einzustellen ist und da hat mir dein Blog hier schon sehr geholfen. Danke, dass du dir so viel Mühe machst und ganz viel Respekt dafür wie schön vereinfacht du das rüber bringst. Gerade dass dich dich selbst davon abhalten kannst ungewollt immer tiefer in die Materie zu sinken... ganz großes Kino.
Wenn ich in meinen Fachbereichen (Werkstoffkunde und thermisch unterstütze Fügetechniken) unterwegs bin und Vorträge halte, dann erwische ich mich immer wieder dabei über Dinge zu reden (die für mich selbsterklärend) sind, wo ich aber meinem Gegenüber ansehe dass er mir nicht mehr folgen konnte.

Sehr schön gemacht!
 
Vielen Dank fürs Lob :-)

So ganz oberflächlich ist das hier alles schon nicht mehr (bzw. dürften die Infos dieses Blogs schon tiefergehend sein als so ziemlich alles was man an How-Tos und Erklärungsseiten zu dem Thema so einfach findet und erst recht was der Normalo so darüber weiß) aber die wirklichen tieferen Sachen lasse ich natürlich raus. Erstens hilft es kaum jemandem weiter sehr in Details einzusteigen, zweitens kann jeder der Detailfragen hat die gerne hier drunterschreiben und ich versuche sie dann zumindest zu beantworden, denn drittens ist das Thema hier eigentlich nicht mein Fachbereich - ich bin hauptsächlich noch immer Maschinenbauingenieur, kein Videocutter oder Codeccoder oder sowas - so dass ich so manche wirklich tiefere Details ganz simpel erst selbst recherchieren müsste. :haha:

Das Ziel der ganzen technischen Blogs von mir ist auch nicht, dass man hier rausgeht und der Profi ist sondern einfach möglichst viele Leute von den Grundlagen her abzuholen und auch viele Standardfragen abzudecken die quasi täglich im Forum auftauchen (vor allem Temperatur, Spannung, Auslastung, Verschleiß,... von Chips).
 
Alki, so ein Gedanke nach einer langen Woche: Wenn du zwischendurch mal Artikel für uns schreiben möchtest, weil es förmlich aus dir sprudelt: Wir sind offen. :D

MfG
Raff
 
Wenn du zwischendurch mal Artikel für uns schreiben möchtest, weil es förmlich aus dir sprudelt: Wir sind offen.
Danke fürs Angebot - ist halt schwierig da mir nur gefühlt 2x im Jahr irgendwas auf-/einfällt was erstens im Forum stark nachgefragt wird und zweitens ich tiefergehend den Plan habe. Weite Teile davon dürften schon in den vorhandenen Blogs abgebildet sein. Die könnt ihr nebenbei inhaltlich gerne verwenden (ist auch schonmal geschehen in einer Print die sich mit Temperatursensoren von CPUs beschäftigte).
Wenn dir ein Thema über den Weg läuft wo du spontan denkst "Alki könnte das bestimmt erklären" (warum auch immer das passieren sollte :haha:) kannste mich ja anstupsen. :-D
 
Zurück