Das quelloffene ffmpeg ist ein Schweizer Taschenmesser unter den Werkzeugen für Videobearbeitung: Schneiden, Drehen, Bildschirmfotos generieren, Herunterskalieren, Umwandeln sind nur die Spitze des Eisbergs. In diesem Beitrag habe ich über mehrere Jahre die Befehle für verschiedene Anwendungsfälle gesammelt.
Gerade aufgrund der vielen Funktionen erschließt sich die Bedienung vor allem für Einsteiger jedoch oft nicht. Zum Einstieg wird daher die grundsätzliche Nutzung von ffmpeg mit einfachen Umwandlungen gezeigt. Später folgen weitere, komplexere Beispiele mit Bildschirmfotos oder Gifs zur Demonstration. Das Programm kann noch weitaus mehr und werkelt im Hintergrund vieler Systeme. Die Liste ist keineswegs vollständig, sondern fasst nur jene Szenarien zusammen, die mir bisher weitergeholfen haben und sicher auch andere gebrauchen können.
Einstieg: So nutzt du ffmpeg
Einige GNU/Linux Distributionen haben es im Lieferumfang. Ob das bei dir der Fall ist, kannst du mit folgendem Befehl auf der Konsole prüfen. Liefert er keine Fehler, ist es bei dir bereits installiert.
ffmpeg -version
ffmpeg version n7.0.1 Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 14.1.1 (GCC) 20240522
configuration: --prefix=/usr --disable-debug
...
Andernfalls kannst du es über die Paketverwaltung deines Betriebssystems nachinstallieren. Unter Debian und dessen Derivaten wie u.a. Ubuntu genügt das gleichnamige Paket:
sudo apt install ffmpeg
Zur Verwendung übergibst du ffmpeg mit dem -i
Parameter den Pfad zur Eingangsdatei. In manchen Szenarien sind mehrere vorhanden, etwa beim Einfügen von Logos (siehe unten). Nach den Quelldateien folgen Parameter, die bestimmen, was die Software mit dem Video machen soll: Umwandeln des Formats, Schneiden usw. Abschließend der Name oder Pfad zur Zieldatei, die ffmpeg produziert – hierfür ist kein benannter Parameter vorgesehen.
Speicherbedarf eines Videos reduzieren
ffmpeg -i input.mp4 output.mp4
Dies ist der einfachste Aufruf ohne Parameter und lädt input.mp4
, um daraus output.mp4
zu erzeugen. Gibt man keinen Codec explizit an, werden automatisch Standards anhand der Dateiendung ermittelt. Bei MP4 ist dies beispielsweise der klassische H264 Codec mit einem Kompromiss zwischen Dateigröße sowie Qualität. Viele Kameras setzen weniger Optimierungen ein und erzeugen damit größere Dateien. Daher kann man oft bereits ohne weitere Optionen eine deutliche Reduzierung der Größe erreichen – das Handyvideo im Beispiel ist nur noch halb so groß.
Weitere Optimierungen sind auf zwei Wegen möglich: Im selben Codec durch Reduzierung der Qualität, also verlustbehaftet. Dafür wird der Constant Rate Factor (CRF) genutzt. Die Skala reicht bei H264 von 0 (Verlustfrei) bis 51 (geringste Qualität), ffmpeg setzt standardmäßig 23.1 Dadurch wird die Ausgabedatei im obigen Beispiel bereits verkleinert. Noch kleinere Dateien lassen sich beispielsweise mit 30 erreichen:
ffmpeg -i 20230722_135205.mp4 -crf 30 output_crf30.mp
l | grep crf
.rw-r--r-- 12M daniel daniel 4 Sep 21:37 output_crf30.mp4
Für z.B. Mobilgeräte mag das akzeptabel sein. Generell würde ich nach Möglichkeit einen effizienteren Codec bevorzugen. H.265 (auch bekannt als HEVC) erreicht mit 15 MB mehr als eine weitere Halbierung gegenüber H264 mit Standard-Parametern. Zwar ist die Skala identisch mit H264 (0 – 51, Verlustfrei bis geringste Qualität), aber nicht 1:1 übertragbar. So entspricht CRF 28 bei H265 (Standard von ffmpeg) dem CRF 23 von H264.2
ffmpeg -i 20230722_135205.mp4 -vcodec libx265 output_x265.mp4
Die Ausgabedatei kann allerdings nur dort genutzt werden, wo H265 unterstützt wird. Obwohl HEVC seit 2013 standardisiert ist, hat er sich bis heute nicht überall verbreitet – ähnlich wie bei den neuen, effizienteren Bildformaten. Auch hier gibt es eine Patentschlacht: Zahlreiche Unternehmen haben Patente und verlangten Jahrelang Lizenzgebühren. Jedoch erkennen europäische Gesetze reine Softwarepatente nicht an.3 Die Mehrheit der Patente ist inzwischen ausgelaufen.4 2018 hat sich der Lizenzverwalter für die Streichung der Gebühren bei der Inhaltsverbreitung entschieden,5 die wenige Jahre zuvor noch erhöht wurden.6
Eine weniger umstrittene Alternative kann AV1 sein.7 Unter Verwendung von libaom-av1
ist dies allerdings derzeit extrem langsam. Deutlich performanter ist libsvtav1
. Damit ist das im Original 74 MB große Video nur noch 20M klein und damit 5 MB größer, als bei H265.
ffmpeg -i 20230722_135205.mp4 -vcodec libsvtav1 output_libsvtav1.mkv
Film schneiden
Man kann ffmpeg einen Zeitstempel für die Startzeit und die Dauer übergeben:
ffmpeg -i input.mp4 -ss 0 -t 5 output.mp4
Im Beispiel starten wir vom Beginn (0) und erhalten die ersten 5 Sekunden. Dies ist nicht nur für das Aufteilen von großen Filmen oder kurzen Vorschau-Trailern sinnvoll. Auch zum Testen macht dies bei längeren Filmen oft Sinn. Wer beispielsweise ein Wasserzeichen setzen will, muss einen 5 Minuten Film nicht komplett rendern. Hierzu reichen ein paar Sekunden, die dementsprechend auch deutlich schneller fertiggestellt werden können.
Videos drehen – Ausrichtung ändern
Ab Commit 1630224 vom 02.05.2020 kann ffmpeg Videos automatisch drehen. Voraussetzung hierfür ist, dass die Videodatei entsprechende Metadaten für die Ausrichtung enthalten. Dies sollte bei vielen modernen Digitalkameras und Smartphones der Fall sein. Hierfür genügt ein simpler Aufruf mit Input/Output Angabe. Der Audiostream kann in diesem Falle einfach kopiert werden:
ffmpeg -i input.mp4 -c:a copy output.mp4
Dies funktioniert jedoch nicht immer. Beispielsweise wenn die Metadaten entfernt wurden. Oder man die Kamera gedreht hat, etwa ein Smartphone. In solchen Fällen lässt sich das Video händisch drehen:
ffmpeg -i input.mp4 -vf "transpose=1" output.mp4
Für transpose sind folgende Werte möglich:
- 0 – Um 90 Grad gegen den Uhrzeigersinn drehen und vertikal spiegeln. Dies ist die Standardeinstellung.
- 1 – Um 90 Grad im Uhrzeigersinn drehen.
- 2 – Um 90 Grad gegen den Uhrzeigersinn drehen.
- 3 – Um 90 Grad im Uhrzeigersinn drehen und vertikal spiegeln.
Möchte man ein Video um mehr als 90 Grad drehen, lassen sich mehrere transpose-Anweisungen kombinieren. Für eine Drehung um 180 Grad im Uhrzeigersinn gibt man also einfach transpose=1,transpose=1 an.
Bei Videos, die ich mit dem Handy aufnehme, kommt es immer wieder zu Problemen. Über ein kleines Tischstativ ist das Smartphone oft leicht geneigt, was bei Aufnahmen im Hochformat vom Gerät häufig nicht korrekt erkannt wird.
Sie werden Horizontal aufgenommen, sodass man den Blick von der Seite im aufgenommenem Material bekommt:
Mit ffmpeg lässt sich das Video korrekt drehen und dabei gleich vom alten H264 Codec der Kamera in H265 umwandeln:
ffmpeg -i 20240902_164721.mp4 -vf "transpose=1,transpose=1,transpose=1" -vcodec libx265 20240902_164721_rotated.mp4
Metadaten ebenfalls kopieren
Standardmäßig gehen einige Metadaten bei der Verwendung von ffmpeg verloren. Darunter zählen beispielsweise Hersteller und Modell der Kamera oder der originale Aufnahmezeitpunkt.
Zunächst muss zwischen den bekannten Metadaten und den Herstellerspezifischen unterschieden werden. Der Schalter -map_metadata 0 schreibt alle bekannten Metadaten von Stream 0 (also der ersten Eingangsdatei) in die Ausgabedatei. Darüber hinaus sorgt -movflags use_metadata_tags dafür, dass die herstellereigenen Metadaten ebenfalls in die Ausgabedatei geschrieben werden.
ffmpeg -i input.mp4 -map_metadata 0 -movflags use_metadata_tags output.mp4
Alternativ lassen sich die Metadaten in eine Textdatei exportieren. Im Gegensatz zum Kommandozeilenwerkzeug exiftool bietet ffmpeg eine Möglichkeit, diese Daten auch wieder zu importieren:
# Export
ffmpeg -i input.mp4 -f ffmetadata meta.txt
# Import
ffmpeg -hide_banner -i input.mp4 -f ffmetadata -i meta.txt output.mp4
Thumbnails/Screenshots generieren
Screenshots einzelner Filmsequenzen sind beispielsweise als Vorschaubilder nützlich. Hierfür bietet ffmpeg zwei Varianten.
Zu einer festgelegten Zeit
ffmpeg -i -hide_banner input.mp4 -ss 00:00:12.000 -vframes 1 thumbnail.png
Im Beispiel wird bei Sekunde 12 ein Screenshot erstellt. Dies bietet sich an, wenn man das Filmmaterial kennt und weiß, wann ein Bild Sinn macht.
Intervall: Alle X Sekunden ein Screenshot
ffmpeg -hide_banner -i input.mp4 -vf fps=1/5 "thumbnail_%03d.jpg"
Alle 5 Sekunden (1/5: 1 Screenshot pro 5 Sekunden) wird hierbei ein Screenshot erstellt. Er heißt thumbnail_XX wobei XX eine fortlaufende Nummer darstellt. Würde man beispielsweise 1/60 angeben, wird pro Minute ein Bild erzeugt.
Herunterskalieren der Auflösung, z.B. 4k zu FullHD
Modernere Kameras können problemlos in 4k aufnehmen. Als Rohmaterial ist dies auch durchaus sinnvoll. Doch dabei entstehen entsprechend auch größere Dateien, die teils Probleme verursachen können. Beispielsweise wenn eine schlechte Internetverbindung besteht oder die maximale Dateigröße für einen Upload limitiert ist.
In solch einem Fall kann man das Video auf 1080p (Full-HD) herunterskalieren. Die Qualität ist dabei immer noch ordentlich und für viele Geräte ausreichend. Doch der Speicherbedarf sinkt ungefähr um den Faktor 6-10.
ffmpeg -i input.mp4 -vf "scale=1920x1080" output.mp4
Gifs erstellen
Gifs sind praktisch, um kurze Filmsequenzen ohne Medienplayer einbetten zu können. Sie lassen sich daher überall nutzen, wo Bilder eingefügt werden können. Beispielsweise auch in Foren oder Blogs, die zwar Bilder erlauben, aber keine Videos.
Standardmäßig erstellt ffmpeg mit der passenden Erweiterung automatisch ein gif. Dies stellt die Farben aber nur mit 256Bit dar und ist daher qualitativ wenig überzeugend. Allerdings können auch gifs mit höherer Qualität erstellt werden:
ffmpeg -hide_banner -i input.mp4 \
-vf "fps=10,scale=300:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop 1 \
/tmp/output.gif
Zu beachten ist allerdings, dass die erstellten Gifs schnell sehr groß werden können. Daher habe ich die Bildwiederholrate auf 10 Bilder pro Sekunde begrenzt (fps=10). Außerdem wurde mit scale=300:-1 die Auflösung auf 300px in der Breite reduziert. -1 generiert automatisch eine entsprechend proportionale Höhe. Ein 20 Sekunden MP4-Video kommt damit auf 4,5 MB.
-loop gibt an, ob sich das Gif in einer Endlosschleife wiederholen soll. Bei 0 wird es nur einmal abgespielt.
Statische Overlays: Text/Bilder über das Video legen
Die Filter von ffmpeg sind sehr mächtig. Sie beginnen bei statischem Text, beispielsweise einem Wasserzeichen. Diese können frei positioniert werden. Über die eingebauten Funktionen ist aber auch komplexeres möglich: Fließtext im TV-Stil, Hinweistexte die zu einer bestimmten Position eingeblendet werden und sogar Animationen können realisiert werden. Im Folgenden ist daher nur ein Auszug des machbaren zu finden, der die umfangreichen Möglichen demonstriert.
Einfache Textzeile (z.B. Copyright)
Ideal für ein Copyright, Wasserzeichen, die Angabe einer Homepage und ähnliche Anwendungsfälle. Der Text wird statisch an einer bestimmten Stelle positioniert. Man kann diesen entweder mit den x/y Koordinaten absolut angeben. Oder dynamisch berechnen. In diesem Beispiel wird die Variable w (= width = Breite des Filmes) sowie text_w (= Breite des Textes) genutzt, um den benötigten Platz zu berechnen. Durch das anschließende Halbieren lässt er sich mittig platzieren.
fontFile=$(pwd)/Roboto-Black.ttf
ffmpeg -hide_banner -i input.mp4 \
-vf drawtext="text='Großer Text' \
:x=(w-text_w)/2 :y=h-th-30 \
:fontfile=$fontFile \ :fontsize=120 :fontcolor=#cee3f8" \
/tmp/output.mp4
Abgesehen von oben Links (wegen dem Textfluss) dürfen wir nicht 0 angeben, um den Text in eine Ecke zu platzieren. Sonst ist dieser selbst nicht korrekt sichtbar. Die Maße des Textes müssen immer berücksichtigt werden.
Zu den Seiten empfiehlt sich immer etwas Abstand. Ansonsten sieht das Ergebnis unnatürlich aus. Daher werden im obigen Beispiel für die y-Achse weitere 30px abgezogen. Beim zentrieren erübrigt sich das zu den Seiten.
Ein paar weitere gängige Positionen:
- Oben links: x=0:y=0
- Oben zentriert: x=(w-text_w)/2:y=0
- Oben rechts: x=w-tw:y=0
- Zentriert in der Mitte des Bildes: x=(w-text_w)/2:y=(h-text_h)/2
- Unten links: x=0:y=h-th
- Unten rechts: x=w-tw:y=h-th
Die Schrift Rotobo Black wurde aus dem Internet geladen. Unter /usr/share/fonts/ findet man auf dem System installierte Schriften. Benötigt man keine spezielle, kann man diese nutzen. Verschiedene Varianten der Ubuntu-Schrift finden sich beispielsweise im Ordner /usr/share/fonts/truetype/ubuntu.
Das Angaben der Größe ist selbsterklärend. Je nach Filmmaterial und Wirkung möchte man ggf. noch die Farbe anpassen. Dies kann ein sprechender Name wie z.B. Blau sein. Oder ein Hex-Code, sodass jede Farbe gewählt werden kann.
Weitere Informationen findet man in der ffmpeg Dokuentation zum drawtext Filter.
Mehrere Textzeilen
Die obige Lösung reicht für einfache Texte aus. Aber wie fügt man mehrere Texte ein? Beispielsweise der Name des Authors mit Verweis auf seine Internetseite. Wenn beide nicht exakt gleich hinsichtlich Position und Formatierungen sein sollen, reicht eine drawtext Direktive nicht aus. Vorstellbar ist z.B. der Name des Authors in einer Ecke, während die Homepage unten am Rand steht. Oder beides übereinander, während der Name größer dargestellt wird.
In diesem Falle muss der Film nicht mehrmals enkodiert werden, um zwei Filter übereinander zu legen. Denn ffmpeg unterstützt die parallele Verwendung mehrerer Filter, wie folgendes Beispiel zeigt:
fontFile=$(pwd)/Roboto-Black.ttf
ffmpeg -hide_banner -i input.mp4 \
-vf drawtext="text='Großer Text' \
:x=(w-text_w)/2 :y=h-th-110 \
:fontfile=$fontFile \ :fontsize=120 :fontcolor=#cee3f8,
drawtext=text='Mit kleinerem Untertitel darunter' \
:x=(w-text_w)/2 :y=h-th-${offsetY}-40 \
:fontfile=$fontFile \
:fontsize=80 :fontcolor=#6eec6e" \
/tmp/output.mp4
Text mit Schatten
Zur Hervorhebung kann der Text auch mit einem Schatten versehen werden. Hierzu geben die Variableb shadowx und shadowy die Verschiebung des Schattens auf der X- bzw. Y-Achse an. Zusätzlich kann mit shadowcolor die Farbe angegeben werden. Wieder als sprechender Name oder Hex-Wert. Standardmäßig ist schwarz vorgesehen, die X- und Y-Variablen sind jedoch nicht gesetzt. Folgendes Beispiel erzeugt einen Extremschatten mit jeweils 20px Verschiebung auf jeder Achse in der Farbe schwarz:
fontFile=$(pwd)/Roboto-Black.ttf
ffmpeg -hide_banner -i input.mp4 \
-vf drawtext="text='Großer Text' \
:x=(w-text_w)/2 :y=h-th-110 \
:fontfile=$fontFile \
:fontsize=120 :fontcolor=#cee3f8 :shadowy=20 :shadowx=20,
drawtext=text='Mit kleinerem Untertitel darunter' \
:x=(w-text_w)/2 :y=h-th-${offsetY}-40 \
:fontfile=$fontFile \
:fontsize=80 :fontcolor=#6eec6e" \
/tmp/output.mp4
Bilder über das Video legen (z.B. Logo einfügen) via Overlay
Man kann mit ffmpeg relativ einfach ein Bild über das Video legen. Es sollte transparent sein (PNG mit entsprechendem Hintergrund) oder eben farblich zum Video passen.
ffmpeg -hide_banner -i input.mp4 \
-i "$(echo ~)/Downloads/tick-128px.png" \
-filter_complex "[0:v] [1:v] overlay=main_w-overlay_w-30:30" \
-pix_fmt yuv420p -c:a copy \
-c:a copy -map 0:a? \
/tmp/output.mp4
Das Overlay nutzt ein Icon von Flaticons (Author: Kiranshastry) und positioniert es mit dem Filter über dem Video. Zum Rand beider Seiten halten wir 30 Pixel Abstand, damit es optisch ansprechender wirkt. Wie an anderer Stelle auch handelt es sich hier um x:y Koordinaten.
Praktisch sind hier die angebotenen Variablen wie im Beispiel main_w für die Höhe des Videos. Folgende stehen zur Verfügung:
main_h : Die Höhe des Videos
main_w : Die Breite des Videos
overlay_h : Die Höhe des Overlays
overlay_w : Die Breite des Overlays
So lässt sich das Ganze flexibel auf verschiedene Videos anwenden, ohne Anpassungen vornehmen zu müssen.
Bild am Ende des Videos für XX Sekunden anzeigen (Endcard)
Möchte man als Abspann ein bestimmtes Bild ins Video einbetten, kann dies
ffmpeg -hide_banner -i input.mp4 \
-i "$(echo ~)/Downloads/tick-128px.png" \
-filter_complex "[0:v] [1:v] overlay=main_w-overlay_w-30:30" \
-pix_fmt yuv420p -c:a copy \
-c:a copy -map 0:a? \
/tmp/output.mp4
ffmpeg -hide_banner -i input.mp4 -loop 1 -t 15 \
-i "/tmp/outro-image.png" -f lavfi -t 1 \
-i anullsrc \
-filter_complex "[0:v] [1:v] concat=n=2:v=1:a=0 [v]" -strict -2 \
-map "[v]" -c:a copy -map 0:a? output.mp4
-t 15 gibt die Länge in Sekunden an, die das Bild angezeigt werden soll. Falls das Video eine Audiospur besitzt, ist es an dieser Stelle wichtig, diese zu kopieren (-c:a copy sowie optionales Mapping mit -map 0:a?). Ansonsten besitzt das Ausgabevideo keine Audiospur!
Bild im Film zentrieren (Mittig)
-filter_complex "overlay=x=(main_w-overlay_w)/2:y=(main_h-overlay_h)/2"
Animation: Overlay bewegt sich unten von rechts nach links durchs Bild
-filter_complex "overlay='if(gte(t,1), -w+(t-1)*200, NAN)':(main_h-overlay_h)-40"
Laufender Text (News-Zeile von Nachrichtensendern)
Nachrichtensender blenden gerne eine kleine Fußzeile ein. Neben der Uhrzeit wiederholt sich dort auch ein Fließtext, der regelmäßig wechselt. Dies ist für längere Texte sinnvoll. Oder wenn man die Aufmerksamkeit des Zuschauers auf diesen Text lenken möchte. Er lässt sich zwar ebenfalls mit einem Filter realisieren. Allerdings benötigt man komplexere Mathematische Funktionen, um einen solchen Lauftext zu realisieren.
fontFile=$(pwd)/Roboto-Black.ttf
ffmpeg -hide_banner -i input.mp4 \
-vf "drawtext=text='Mit kleinerem Untertitel darunter' \
:y=h-line_h-10:x=w-mod(max(t-1\,0)*(w+tw)/15\,(w+tw))' \
:fontfile=$fontFile \
:fontsize=70 :fontcolor=#6eec6e :shadowy=2 :shadowx=2" \
/tmp/output.mp4
Bei t-1 steht 1 für die Zeit in Sekunden, die initial bis zum Erscheint des Lauftextes gewartet werden soll. Gibt man hier z.B. 10 an, ist bis Sekunde 10 kein Text sichtbar. Erst danach fließt er von rechts nach links ins Bild.
Die 15 bei (w+tw)/15 gibt die Geschwindigkeit an, mit der sich der Text durchs Bild bewegt. Je höher um so schneller.
Ohne Wiederholung
Im obigen Beispiel wird der Text bis zum Ende des Videos wiederholt: Sobald er links verschwunden ist, erscheint er auf der rechten Seite erneut. Soll der Text nur einmalig erscheinen und danach ohne Wiederholung verschwinden, kann folgende Formel für die x-Position genutzt werden:
:y=h-line_h-10:x=w-(t-1)*w/15
Quellen
- https://trac.ffmpeg.org/wiki/Encode/H.264 ↩︎
- http://trac.ffmpeg.org/wiki/Encode/H.265 ↩︎
- https://www.cnet.com/science/vlc-steps-into-next-gen-video-wars-with-vp9-hevc-support/ ↩︎
- https://www.mpegla.com/wp-content/uploads/hevc-att1.pdf ↩︎
- https://web.archive.org/web/20220405062843/https://www.presseportal.de/pm/120729/3890534 ↩︎
- https://www.zdnet.de/88255281/hevc-advance-senkt-codec-lizenzgebuehren/ ↩︎
- https://trac.ffmpeg.org/wiki/Encode/AV1 ↩︎