Audio & Video

Anleitung: Videos automatisch zerstückeln und zufällig verschmelzen

Video-Dateien mit ffmpeg schneiden und verschmelzen, gezeigt an einem konkreten Beispiel

Ein Mini-Projekt, das Ihr als Basis für eigene ffmpeg-Spielereien nehmen könnt: Ein Haufen Video-Dateien soll in jeweils 10 Sekunden lange Clips geteilt werden, die dann in zufälliger Reihenfolge wieder zu einem Video zusammengefügt werden. Dabei kann man erstaunlich einfach etwas falsch machen ;)

Überblick

Nochmal im Detail: Ausgangspunkt sollen ein paar Video-Dateien sein, mit unterschiedlichen Codecs und Bildraten und blöden Dateinamen mit Leerzeichen. Diese sollen in handliche 10-Sekunden-Schnipsel zerlegt werden. Und von denen sollen wiederum 10 in zufälliger Reihenfolge zu einem 100-Sekunden-Video verschmolzen werden.

Das Handwerkszeug: Bash (hier unter Windows), ffmpeg, for-Schleifen, tr und ein wenig obskures Bash-Parameter-Expansion-Foo.

Die Ordnerstruktur: Die finale Datei landet im Arbeitsverzeichnis, die Originaldateien liegen im Verzeichnis input und die 10-Sekunden-Schnipsel im Verzeichnis output.

Mein üblicher Disclaimer: Vermutlich geht das eleganter, mit Arrays, mit Python ... Aber ich entwickel hier kein Tool ;)

1. Videos vernünftig benennen

Leider gibt es Menschen und Tools (zum Beispiel der behämmerte Windows-Explorer), die gerne Leerzeichen in Dateinamen bauen. Wie sehr ich das verabscheue, habe ich auch mal laut und deutlich formuliert. Klar lassen sich auch solche Dateinamen programmatisch verarbeiten, aber erfahrungsgemäß ist es einfacher, Dateinamen erstmal aufzuhübschen - sprich Leerzeichen durch Unterstriche ersetzen.

for i in input/*; do mv "$i" $(tr ' ' _ <<< "$i"); done

Die for-Schleife packt sich alle Dateien im Input-Verzeichnis, die jeweils in der Variablen i landen. Dann verschiebt mv die Datei, sprich benennt sie um. Für den Zielnamen liest tr über <<< $i den Originalnamen und tauscht schlicht Leerzeichen gegen Unterstriche. Aus Hallo Welt.txt würde also Hallo_Welt.txt und so weiter.

Bash kann das auch nativ, ohne tr - allerdings ist Parameter Expansion vielleicht auch nicht verständlicher:

for i in input/*; do mv "$i" ${i/ /_}; done

Über ${i/suchwort/ersatz} lassen sich Parameter, hier also die Dateinamen, manipulieren. Das ist eleganter, aber da ich es mir vermutlich nicht werde merken können ...

2. Videos zerstückeln

Nun müssen die Videos im Input-Ordner in 10-Sekunden-Schnipsel geschnitten werden. Der Übersicht halber habe ich dafür ein Mini-Skript mycutter.sh angelegt:

workingfile=$1
start=1
for n in $(seq 1 10); do
    start=$((start+15))
    extension="${1##*.}"
    filename=$(basename "${1%.*}")
    ffmpeg.exe -i $workingfile -ss $start -c:a mp3 -c:v vp9 -r 30 -t 10 output/"$filename"_"$n"."$extension"
done

Zunächst wird der aktuelle Dateiname in workingfile gespeichert, einfach weil schöner. Und start wird initialisiert. Die for-Schleife soll hier 10 mal durchlaufen werden, weil ich 10 10-Sekunden-Clips haben will - das erledigt der seq-Befehl. Zunächst wird für jeden Schnipsel die Startzeit um jeweils 15 Sekunden erhöht.

Dann landen Dateiname und Dateinamenerweiterung in den Variablen filename und extension, jeweils durch oben erwähnte Parameter Expansion: ${1##*.} meint: Dateiname in $1 (inklusive Pfad) wird bis zum Punkt (wie in foobar.txt) abgeschnitten, übrig bleibt dann zum Beispiel .txt. ${1%.*} macht quasi das Gegenteil und übrig bleibt entsprechend der Dateiname samt Pfad - und Dank basename bleibt nur der Dateiname ohne Pfad übrig. Mal als Beispiel:

  • workingfile: input/foobar.txt
  • filename: foobar
  • extension: .txt

Und warum das Ganze? Weil am Ende Dateien wie foobar_1.txt heraus kommen sollen, oder allgemein Originalname_Durchlaufnummer.Erweiterung.

Der Kern des Ganzen ist aber die ffmpeg-Zeile:

  • -i gibt die Input-Datei an
  • -ss gibt die Startzeit für den Beginn des Clips an
  • -c:a mp3 setzt den Audio-Codec auf mp3
  • -c:v vp9 setzt den Video-Codec auf vp9
  • -r 30 sorgt für eine Framerate von 30 fps
  • -t 10 sorgt für 10-Sekunden-Schnipsel

ffmpeg setzt den allerersten Schnitt also bei Sekunde 16 an und schneidet bis Sekunde 26. Der nächste Schnitt fängt bei 31 an, geschnitten wird bis 41 und so weiter.

Die genauen Werte müsst Ihr freilich anpassen. Aber ein paar wichtige Infos zum ffmpeg-Befehl:

  • Enkodieren und festsetzen der Framerate muss sein, damit später alle Videos dasselbe Format haben - sonst meckert das Verschmelzen!
  • Haben alle Videos eh dasselbe Format: Ohne Angabe von Codecs wird einfach kopiert, was deutlich schneller geht (aber fehleranfälliger ist).
  • Die ss-Option nach der Input-Datei sorgt für mehr Präzision - davor für mehr Geschwindigkeit (Danke ffmpeg, sehr intuitiv ...; mehr dazu).

Fehlt noch der Aufruf des Skripts:

for i in input/*; do ./mycutter.sh $i; done

Schlicht und einfach: Das Skript wird für alle Dateien im Input-Ordner aufgerufen.

Das Ergebnis:

  • Ausgangsdateien beispielsweise foo.mp4 und bar.mp4
  • foo-Dateien: foo_1.mp4, foo_2.mp4 etc.
  • bar-Dateien: bar_1.mp4, bar_2.mp4 etc.

Und die Dateien sollen nun verschmolzen werden. Oder wie es bei ffmpeg so schön heißt: konkateniert werden.

3. Dateiliste erstellen

Bevor es ans Verschmelzen geht, muss eine Liste mit den zu verschmelzenden Dateien her, die ffmpeg verlangt:

for f in output/*.mp4; do echo "file '$f'"; done | shuf > mylist

Das erstellt eine Liste, die so aussieht:

file 'output/foo_2.mp4'
file 'output/bar_1.mp3'
...

Für die zufällige Reihenfolge sorgt shuf (für shuffle).

4. Dateien verschmelzen

Machen wir es kurz, hier die finale ffmpeg-Zeile:

ffmpeg.exe -f concat -safe 0 -i mylist myvideo.mp4

Mit concat werden die Dateien in mylist konkateniert, sprich aneinandergehängt, sprich verschmolzen. Die safe-Option erlaubt ffmpeg, Dateien im aktuellen Verzeichnis zu lesen, beziehungsweise generell alle Dateinamen (und ja, die Option ist beknackt, sollte per Default 0 sein und wird ständig in Foren erfragt).

TLDR - Befehle am Stück

Der Übersicht halber nochmal alles ohne Blabla ;)

Struktur:

Quelldateien: Beliebige Videos mit unterschiedlichen Formaten
Arbeitsverzeichnis: Skript und finales Ergebnis
Input-Verzeichnis: Quelldateien im Ganzen
OUtput-Verzeichnis: 10-Sekunden-Dateien aus den Quelldateien

Befehle:

## Umbenennen/Leerzeichen ersetzen 
for i in input/*; do mv "$i" $(tr ' ' _ <<< "$i"); done
## Zerstückeln 
for i in input/*; do ./mycutter.sh $i; done
## Liste für concat anfertigen
for f in output/*.mp4; do echo "file '$f'"; done | shuf > mylist
## Konkatenieren
ffmpeg.exe -f concat -safe 0 -i mylist myvideo.mp4

Das Skript mycutter.sh:

workingfile=$1
start=1
for n in $(seq 1 10); do
    start=$((start+15))
    extension="${1##*.}"
    filename=$(basename "${1%.*}")
    ffmpeg.exe -i $workingfile -ss $start -c:a mp3 -c:v vp9 -r 30 -t 10 output/"$filename"_"$n"."$extension"
done

Disclaimer:

Das geht bestimmt eleganter ;)
Das ganze Projekt wird vermutlich für sehr sehr wenige Menschen interessant sein, schon klar. Aber vielleicht ist ja ein Teil davon für Euch nützlich? Wenn nicht, hinterlasst gerne ein #Nerdquatsch in den Kommentaren.

Und natürlich: Man kann hier noch viel herumbasteln! Beispielsweise könnte man statt fixer 10-Sekunden-Schnipsel per Zufall dafür sorgen, dass die Schnipsel jeweils etwa zwischen 10 und 30 Sekunden lang sind. Man könnte mit etwas mehr Aufwand dafür sorgen, dass die Quelldateien jeweils in x gleich große Stücke zerhackt werden. Beim Konkatenieren könnte man für Videos einer bestimmten Länge sorgen, etwa die eines unterlegten Musikstücks. Apropos: Vermutlich wäre es ziemlich sinnvoll, die originalen Audiostreams komplett zu löschen und einen eigenen Track zu nutzen.

Wie gesagt, nehmt es als Anregung.

Mehr Nerdquatsch ;)

Mirco Lang

Freier Journalist, Exil-Sauerländer, (ziemlich alter) Skateboarder, Dipl.-Inf.-Wirt, Einzelhandelskaufmann, Open-Source-Nerd, Checkmk-Handbuchschreiber. Ex-Saturn'ler, Ex-Data-Becker'ler, Ex-BSI'ler. Computer-Erstkontakt: ca. 1982 - der C64 des großen Bruders eines Freunds. Wenn Ihr hier mehr über Open Source, Linux und Bastelkram lesen und Tutonaut unterstützen möchtet: Über Kaffeesponsoring via Paypal.freue ich mich immer. Schon mal im Voraus: Danke! Nicht verpassen: cli.help und VoltAmpereWatt.de. Neu: Mastodon

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Schaltfläche "Zurück zum Anfang"