kind: reference

ffmpeg: Ton und Video

ffmpeg wandelt fast jede Ton- und Videodatei in fast jede andere um, komprimiert sie mit einem Codec deiner Wahl, schneidet, verkleinert und misst. Im Workspace ist es installiert, zusammen mit ffprobe, das zeigt, was in einer Datei steckt. Hier stehen die Befehle aus Audio komprimieren und Video komprimieren zum Nachschlagen.

1. Grundform

Ein Befehl

Jeder Befehl hat dieselbe Form: erst die Eingabe hinter -i, dann die Einstellungen für die Ausgabe, zuletzt die Ausgabedatei. Ihre Endung entscheidet, was ffmpeg schreibt.

ffmpeg -i musik.wav musik.flac
Schalter Was er tut
-i datei die Eingabe; mehrere -i für mehrere Eingaben
-y überschreibt die Ausgabe, ohne zu fragen
-v error schreibt nur Fehler, nicht die vielen Zeilen über jede Datei (auch -loglevel error)
-hide_banner lässt nur die Zeilen am Anfang über die Version und den Bau weg

Die Reihenfolge zählt: Ein Schalter vor -i gilt für die Eingabe, einer danach für die Ausgabe.

Was in einer Datei steckt

ffprobe liest eine Datei und sagt, was darin ist: Codec, Abtastrate, Kanäle, Größe der Bilder, Länge.

ffprobe -v error -show_entries format=duration -of csv=p=0 musik.mp3
ffprobe -v error -show_entries stream=codec_name,sample_rate,channels -of default=noprint_wrappers=1 musik.opus
ffprobe -v error -select_streams v -show_entries frame=pict_type,pkt_size -of json video.mp4

Der erste Befehl gibt nur die Länge in Sekunden, der zweite Codec, Abtastrate und Kanäle, der dritte für jedes Bild eines Videos seine Art (I, P oder B) und wie viele Bytes es braucht. -of json gibt die Antwort als JSON, das ein Programm leicht lesen kann.

Was ffmpeg kann

ffmpeg zeigt selbst, was es kann. Jede Liste erklärt am Anfang ihre Buchstaben; mit grep findest du darin, was du suchst.

Befehl Was er zeigt
ffmpeg -hide_banner -codecs alle Codecs, die ffmpeg kennt, über 500, und welche Encoder und Decoder es für jeden hat
ffmpeg -hide_banner -encoders womit ffmpeg schreiben kann: die Namen für -c:a und -c:v
ffmpeg -hide_banner -decoders womit ffmpeg lesen kann
ffmpeg -hide_banner -formats die Dateiformate, etwa mp4, wav, matroska; D heißt lesen, E schreiben
ffmpeg -hide_banner -filters alle Filter für -vf (Bild) und -af (Ton)
ffmpeg -hide_banner -pix_fmts die Pixelformate, etwa rgb24 und yuv420p
ffmpeg -hide_banner -h encoder=libx264 alle Einstellungen eines Encoders; -h filter=scale die eines Filters
ffmpeg -hide_banner -codecs | grep -E ' h264 | opus '
 DEV.LS h264    H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 …) (encoders: libx264 …)
 DEAIL. opus    Opus (Opus Interactive Audio Codec) (decoders: opus libopus) (encoders: opus libopus)

Die sechs Zeichen vorn: D, ffmpeg kann ihn lesen; E, schreiben; V oder A, Video oder Ton; I, jedes Bild für sich; L, mit Verlust; S, ohne Verlust. Ein Codec ist die Art, die Daten zu codieren, etwa H.264; ein Encoder ist ein Programm, das sie so schreibt. Für H.264 gibt es mehrere, libx264 ist das bekannteste, und sein Name ist es, der hinter -c:v steht.

2. Ton

Umwandeln und komprimieren

Befehl Was er macht
ffmpeg -i musik.wav musik.flac FLAC: verlustfrei kleiner, die Samples kommen genau zurück
ffmpeg -i musik.wav -b:a 128k musik.mp3 MP3 mit 128 kbit/s; die Endung wählt den Codec
ffmpeg -i musik.wav -c:a aac -b:a 64k musik.m4a AAC mit 64 kbit/s
ffmpeg -i musik.wav -c:a libopus -b:a 32k musik.opus Opus mit 32 kbit/s
ffmpeg -i musik.mp3 musik.wav zurück in Samples, zum Anhören oder Rechnen

-c:a wählt den Codec für den Ton (a für audio), -b:a die Bitrate. Ohne -c:a nimmt ffmpeg den üblichen Codec der Endung. Opus rechnet immer mit 48.000 Samples in der Sekunde: Aus einer Datei mit 44.100 Hz wird beim Zurückwandeln eine mit 48.000 Hz. Eine MP3-Datei ist am Ende etwas länger als das Original, weil der Encoder am Anfang und am Ende Stille dazulegt.

Schneiden, Kanäle, Abtastrate

Schalter Was er tut
-ss 1.5 beginnt bei 1,5 Sekunden (vor -i: springt dorthin, ohne alles davor zu lesen)
-t 2 nimmt 2 Sekunden
-ac 1 ein Kanal, mono; -ac 2 stereo
-ar 8000 8.000 Samples in der Sekunde, wie im Telefon
ffmpeg -ss 1 -t 2 -i stimme.wav -ac 1 -ar 8000 stueck.wav

3. Video

Codec und Qualität

ffmpeg -i video.mp4 -c:v libx264 -crf 23 -pix_fmt yuv420p klein.mp4
Schalter Was er tut
-c:v libx264 H.264 als Codec für das Bild (v für video); libaom-av1 für AV1
-crf 23 eine feste Qualität: kleiner ist besser und größer, bei H.264 von 0 bis 51, üblich ist 23
-b:v 1500k statt einer Qualität eine Bitrate
-preset slow sucht länger und spart dafür Bytes; von ultrafast bis veryslow
-g 24 höchstens 24 Bilder bis zum nächsten I-Frame; -g 1: nur I-Frames
-bf 0 keine B-Frames
-pix_fmt yuv420p Farbe in 4:2:0, wie fast jedes Video; ohne das spielen manche Programme die Datei nicht ab

Bilder heraus und hinein

mkdir -p bilder
ffmpeg -i video.mp4 -vf fps=2 bilder/%04d.png
ffmpeg -framerate 24 -i bilder/%04d.png -c:v libx264 -pix_fmt yuv420p neu.mp4
ffmpeg -i video.mp4 -vf "select=eq(n\,10)" -frames:v 1 bild-10.png

Die erste Zeile schreibt zwei Bilder je Sekunde, 0001.png, 0002.png und so weiter: %04d steht für eine Zahl mit vier Stellen. Die zweite macht aus Bildern wieder ein Video mit 24 Bildern in der Sekunde. Die dritte holt genau ein Bild heraus, das mit dem Index 10, das elfte.

Filter

-vf bekommt eine Kette von Filtern, durch Kommas getrennt; jeder bekommt das Bild des vorigen.

Filter Was er tut
scale=640:-2 640 Pixel breit, die Höhe passend und gerade
crop=320:180:0:0 schneidet 320 × 180 Pixel aus, links oben beginnend
fps=2 zwei Bilder in der Sekunde
select=eq(n\,10) nur das Bild mit dem Index 10
noise=alls=14:allf=t Rauschen, das sich von Bild zu Bild ändert, wie Filmkorn
ffmpeg -i video.mp4 -vf "crop=320:180:0:0,scale=640:-2" ausschnitt.mp4

Ohne neu zu codieren

ffmpeg -ss 1 -t 5 -i video.mp4 -c copy stueck.mp4

-c copy kopiert die komprimierten Daten, wie sie sind: schnell und ohne Verlust, aber ein Schnitt kann nur an einem I-Frame beginnen, und Filter gehen so nicht.

4. Mit Python

Pixel und Samples durch eine Pipe

ffmpeg kann statt einer Datei rohe Zahlen schreiben, in eine Pipe, aus der ein Python-Programm liest, und umgekehrt. -f rawvideo -pix_fmt rgb24 heißt: nur Pixel, drei Bytes je Pixel; - heißt: in die Pipe statt in eine Datei.

import subprocess

import numpy as np

WIDTH, HEIGHT = 640, 360


def read_frames(path):
    command = ['ffmpeg', '-v', 'error', '-i', path, '-f', 'rawvideo', '-pix_fmt', 'rgb24', '-']
    data = subprocess.run(command, capture_output=True, check=True).stdout
    return np.frombuffer(data, dtype=np.uint8).reshape(-1, HEIGHT, WIDTH, 3)


def write_video(path, frames, fps=24):
    command = ['ffmpeg', '-v', 'error', '-y', '-f', 'rawvideo', '-pix_fmt', 'rgb24',
               '-s', f'{WIDTH}x{HEIGHT}', '-r', str(fps), '-i', '-',
               '-c:v', 'libx264', '-crf', '18', '-pix_fmt', 'yuv420p', path]
    subprocess.run(command, input=frames.astype(np.uint8).tobytes(), check=True)

Beim Lesen weiß ffmpeg die Größe aus der Datei, beim Schreiben nicht: Darum bekommt es -s und -r vor dem -i -. Für Ton geht es genauso: -f s16le -ac 1 -ar 44100 - gibt die Samples als Zahlen mit 16 Bit, Little Endian, wie in einer WAV-Datei; -f f32le als Kommazahlen.

5. Messen

Wie nah ist das Ergebnis am Original?

ffmpeg -hide_banner -i klein.mp4 -i video.mp4 -lavfi psnr -f null - 2>&1 | grep -o "PSNR.*"

Das PSNR vergleicht die beiden Videos Bild für Bild, in dB: je höher, desto näher. -f null - schreibt keine Datei; ffmpeg rechnet nur. Weil ffmpeg seine Meldungen auf stderr schreibt, leitet 2>&1 sie in die Pipe zu grep.

6. Zum Nachschlagen

  • ffmpeg: alle Schalter, mit den Regeln für ihre Reihenfolge, auf Englisch.
  • ffmpeg-filters: jeder Filter für Bild und Ton mit seinen Einstellungen.
  • ffprobe: was ffprobe zeigen kann und in welchen Formaten.
  • H.264, AV1, MP3 und AAC: Anleitungen im Wiki von ffmpeg, welche Einstellungen für welchen Zweck taugen.