Wie FFmpeg tatsächlich funktioniert (und warum Ihr erster Befehl fehlgeschlagen ist)
FFmpeg funktioniert nach einem einfachen Prinzip, das jeder zunächst falsch versteht: Es liest Streams von Eingaben, verarbeitet sie durch Filter und schreibt sie auf Ausgaben. Die Verwirrung entsteht durch die Tatsache, dass eine einzelne Videodatei mehrere Streams enthält - normalerweise einen Video-Stream, einen oder mehrere Audio-Streams und manchmal Untertitel- oder Metadaten-Streams. Wenn Sie `ffmpeg -i input.mp4 output.mp4` ausführen, macht FFmpeg viele Annahmen darüber, was Sie wollen. Es wählt den "besten" Video-Stream, den "besten" Audio-Stream, kopiert sie durch Standard-Encoder und muxed sie in den Ausgabcontainer. Das funktioniert gut für einfache Konvertierungen, aber es zerfällt in dem Moment, in dem Sie Kontrolle benötigen. Der Grund, warum mein erster Befehl eine 0-Byte-Datei erzeugte, war, weil ich inkompatible Codec- und Containerkombinationen angegeben hatte. Ich versuchte, einen VP9-Video-Stream in einen MP4-Container zu packen, was nicht unterstützt wird. FFmpeg begann mit dem Encodieren, erkannte, dass es das Ausgabegerät nicht schreiben konnte, und gab auf. Die Fehlermeldung war in 200 Zeilen Ausgabe verborgen, die ich nicht lesen konnte. Hier ist das mentale Modell, das alles für mich geändert hat: Denken Sie an FFmpeg als eine Pipeline mit drei Stufen. Zuerst Demuxing - FFmpeg öffnet Ihre Eingabedatei und trennt sie in einzelne Streams. Zweitens Verarbeitung - jeder Stream geht durch einen Codec (Encoder/Dekoder) und optionale Filter. Drittens Muxing - die verarbeiteten Streams werden in einen Ausgabcontainer gepackt. Jeder FFmpeg-Befehl folgt diesem Muster: ``` ffmpeg [globale Optionen] [Eingabeoptionen] -i Eingabe [Ausgabeoptionen] Ausgabe ``` Die Reihenfolge ist enorm wichtig. Optionen vor `-i` gelten für die Eingabe. Optionen nach `-i` gelten für die Ausgabe. Wenn Sie `-c:v libx264` vor `-i` setzen, versucht FFmpeg, die Eingabe als H.264 zu dekodieren, was wahrscheinlich nicht das ist, was Sie wollen. Setzen Sie es nach `-i`, und es kodiert die Ausgabe als H.264. Das andere entscheidende Konzept sind Stream-Spezifizierer. Wenn Sie `-c:v` schreiben, sagen Sie: "Wenden Sie diesen Codec auf Video-Streams an." `-c:a` zielt auf Audio-Streams ab. `-c:s` zielt auf Untertitel ab. Sie können sogar spezifischer werden mit `-c:v:0` für den ersten Video-Stream oder `-c:a:1` für den zweiten Audio-Stream. Sobald ich diese Struktur verstanden hatte, hörte ich auf, 0-Byte-Dateien zu produzieren. Ich konnte die Ausgabe von FFmpeg lesen und verstehen, was es in jeder Phase tat. Ich konnte Probleme debuggen, indem ich isolierte, ob das Problem im Demuxing, der Verarbeitung oder dem Muxing lag.Der Tag, an dem ich 50.000 Videos transkodierte (und was ich lernte)
Vor drei Jahren erwarb unser Unternehmen einen Konkurrenten. Teil des Erwerbs war ihre gesamte Videosammlung - 50.000 Videos in einem Format, das wir nicht unterstützten. Sie hatten einen proprietären Codec verwendet, der einen bestimmten Player erforderte, und wir mussten alles in standard H.264 für unsere Plattform umwandeln. Der naive Ansatz wäre gewesen, eine einfache Schleife zu schreiben: Für jedes Video FFmpeg mit grundlegenden Einstellungen ausführen, auf das Ende warten, zum nächsten übergehen. Bei einer durchschnittlichen Bearbeitungszeit von 2 Minuten pro Video hätte das 69 Tage kontinuierliche Verarbeitung gedauert. Wir hatten zwei Wochen. Dieses Projekt hat mir mehr über FFmpeg beigebracht als die vorherigen drei Jahre zusammen. Ich lernte über Hardwarebeschleunigung, parallele Verarbeitung und die Dutzenden von Encoder-Einstellungen, die tatsächlich wichtig sind. Ich lernte, welche Qualitätsmetriken sinnvoll sind und welche Marketingunsinn sind. Am wichtigsten war, dass ich lernte, dass der "beste" FFmpeg-Befehl ganz von Ihren Einschränkungen abhängt. Wir haben ein verteiltes Transcoding-System gebaut, das 200 Videos gleichzeitig auf 40 Maschinen verarbeiten konnte. Jede Maschine führte 5 FFmpeg-Instanzen aus, die sorgfältig abgestimmt waren, um die CPU-Auslastung zu maximieren, ohne den Prozessor zu überlasten. Wir verwendeten hardwarebeschleunigtes Decodieren, wo immer es verfügbar war, aber Software-Encoding, da der Qualitätsunterschied für unseren Anwendungsfall signifikant war. Der Befehl, auf den wir uns einigten, sah so aus: ```bash ffmpeg -hwaccel auto -i input.mov \ -c:v libx264 -preset medium -crf 23 \ -c:a aac -b:a 128k \ -movflags +faststart \ -max_muxing_queue_size 1024 \ output.mp4 ``` Lassen Sie mich erklären, warum jede Option wichtig ist. `-hwaccel auto` sagt FFmpeg, dass es hardwaregestütztes Decodieren verwenden soll, wenn verfügbar - dies reduzierte unsere Decodierzeit um 60 % auf Maschinen mit kompatiblen GPUs. `-preset medium` balanciert Codierungsgeschwindigkeit mit Kompressionseffizienz. Wir haben alle Presets getestet; `medium` war der Sweet Spot, bei dem wir 95 % der Qualität von `slower` in der halben Zeit erhielten. Die Einstellung `-crf 23` steuert die Qualität mit dem Constant Rate Factor. Niedrigere Zahlen bedeuten höhere Qualität und größere Dateien. Wir haben CRF-Werte von 18 bis 28 an einer Stichprobe von 100 Videos getestet und unser Videoteam hat Blindqualitätsvergleiche durchgeführt. Niemand konnte CRF 23 zuverlässig von CRF 20 unterscheiden, aber die Dateigrößen waren 30 % kleiner. `-movflags +faststart` verschiebt das moov-Atom an den Anfang der Datei, wodurch progressives Abspielen über HTTP ermöglicht wird. Ohne dieses Flag müssen Browser die gesamte Datei herunterladen, bevor sie mit dem Abspielen beginnen können. Diese einzelne Option verbesserte unsere Benutzererfahrungsmetriken um 15 %. Die Option `-max_muxing_queue_size 1024` löste ein Problem, das uns drei Tage Debugging kostete. Einige der Quellvideos hatten variable Bildraten, die dazu führten, dass die internen Puffer von FFmpeg überliefen. Die Standardwarteschlangengröße beträgt 8 Pakete, was für VFR-Inhalte nicht ausreicht. Die Erhöhung auf 1024 beseitigte die Fehlermeldungen "Zu viele Pakete für den Ausgabestream gepuffert", die 5 % unserer Konvertierungen fehlschlugen. Wir beendeten das Projekt in 11 Tagen. Das verteilte System verarbeitete 4.545 Videos pro Tag mit einer Erfolgsquote von 99,2 %. Die Misserfolge waren alles Quell-Dateien, die beschädigt oder mit Codecs verwendet wurden, die wir nicht dekodieren konnten. Ich verwende auch heute noch Variationen dieses Befehls - es ist das Fundament unserer gesamten Videoverarbeitungs-Pipeline.Matrix der Codec- und Containerkompatibilität
Einer der frustrierendsten Aspekte von FFmpeg für Anfänger ist das Verständnis, welche Codecs mit welchen Containern funktionieren. Sie können eine Stunde damit verbringen, den perfekten Befehl zu erstellen, nur um festzustellen, dass er fehl schlägt, weil Sie versuchen, einen inkompatiblen Codec in einen Container zu packen, der ihn nicht unterstützt. Hier ist die Kompatibilitätstabelle, auf die ich ständig verweise:| Container | Video-Codecs | Audio-Codecs | Am besten für |
|---|---|---|---|
| MP4 | H.264, H.265, AV1 | AAC, MP3, Opus | Web-Wiedergabe, mobile Geräte, universelle Kompatibilität |
| WebM | VP8, VP9, AV1 | Vorbis, Opus | Web-Streaming, Open-Source-Projekte, YouTube |
| MKV | Alles | Alles | Archivierung, mehrere Audio-Streams, Untertitel |
| MOV | H.264, ProRes, DNxHD | AAC, PCM | Professionelle Bearbeitung, Apple-Ökosystem |
| AVI | MPEG-4, H.264 (eingeschränkt) | MP3, PCM | Veraltete Systeme (vermeiden für neue Projekte) |
| TS | H.264, H.265, MPEG-2 | AAC, MP3, AC-3 | Broadcasting, HLS-Streaming |
Die Qualitätseinstellungen, die niemand richtig erklärt
Jedes FFmpeg-Tutorial sagt Ihnen, dass Sie `-crf 23` für "gute Qualität" oder `-b:v 5M` für "5 Megabit pro Sekunde" verwenden sollen. Aber niemand erklärt, was diese Einstellungen tatsächlich tun oder wie man die richtigen Werte für seinen Inhalt auswählt. Ich habe Hunderte von Stunden damit verbracht, Qualitätseinstellungen für verschiedene Arten von Inhalten zu testen. Hier ist, was ich gelernt habe: Es gibt keine universelle "beste" Einstellung. Die optimalen Qualitätsparameter hängen von Ihrem Inhaltstyp, Ihrer Zielgruppe und Ihrer Verteilungsmethode ab."Constant Rate Factor (CRF) ist ein qualitätsbasierter Codierungsmodus, bei dem Sie ein Qualitätsniveau angeben und den Encoder so viele Bits verwenden lassen, wie nötig sind, um diese Qualität zu erreichen. Niedrigere CRF-Werte bedeuten höhere Qualität und größere Dateien. Der Bereich liegt bei 0-51 für H.264, wobei 0 verlustfrei und 51 die schlechteste mögliche Qualität ist. Der Standardwert ist 23, der für die meisten Inhalte als 'visuell transparent' gilt - was bedeutet, dass die meisten Menschen ihn nicht vom Original unterscheiden können."Das Problem mit CRF ist, dass es Ausgaben mit variabler Bitrate produziert. Eine hochgradig bewegte Action-Szene könnte 10 Mbps verwenden, während eine statische Plauderecke 2 Mbps verwendet. Dies ist effizient für die Dateigröße, kann jedoch Probleme beim Streaming verursachen, bei dem eine vorhersehbare Bandbandbreitennutzung erforderlich ist. Für das Streaming wünschen Sie sich eine konstante Bitrate (CBR) oder variable Bitrate mit Einschränkungen (VBR). Hier ist der Befehl, den ich für das Streaming verwende: ```bash ffmpeg -i input.mp4 \ -c:v libx264 -preset medium \ -b:v 5M -maxrate 5M -bufsize 10M \ -c:a aac -b:a 128k \ output.mp4 ``` Die Option `-b:v 5M` setzt die Zielbitrate auf 5 Megabit pro Sekunde. `-maxrate 5M` stellt sicher, dass es diese Rate niemals überschreitet. `-bufsize 10M` setzt die Puffergröße des Dekoders auf das Doppelte der Bitrate, was die Standardempfehlung ist. Dies produziert Ausgaben, die reibungslos gestreamt werden, ohne zu puffern. Aber hier ist, was die meisten Leute falsch machen: Die Bitrate-Anforderungen skalieren mit der Auflösung und Bewegung, nicht linear. Ein 1080p-Video benötigt nicht doppelt so viel Bitrate wie ein 720p-Video - es benötigt etwa 1,5-mal so viel. Ein 4K-Video benötigt nicht viermal so viel Bitrate wie 1080p - es benötigt etwa 2,5-mal so viel.
"Das menschliche visuelle System ist logarithmisch, nicht linear. Das Verdoppeln der Bitrate bringt keine..."