Welcome, Guest. Please login or register.
Did you miss your activation email?

Author Topic: [DE] Mehrere Videos mit melt zusammenschneiden (Ein-, Aus- u. Überblendeffekte)  (Read 9208 times)

Offline pit

  • User
  • Posts: 241
Habe 5 Videos in einem Verzeichnis:
01.mp4, 02.mp4 ... 05.mp4

Ich will die via melt in der Konsole zu einem Video zusammenmontieren.
01.mp4 soll von schwarz eingeblendet u. mit 02 überblendet werden. 02 soll mit 3, 3 mit 4 u. 4 mit 5 überblendet werden. 05.mp4 soll nach schwarz ausgeblendet werden.

Programmaufruf ist:
melt colour:black out=20 01.mp4 -mix 20 -mixer luma 02.mp4 -mix 20 -mixer luma 03.mp4 -mix 20 -mixer luma 04.mp4 -mix 20 -mixer luma 05.mp4 -mix 20 -mixer luma colour:black out=20 -mix 20 -mixer luma

Im Ergebnis dann vom Prinzip her so:
https://imgur.com/KST2gXT

Ich würde das gerne in ein Script oder in einen alias packen.
Challenge: Das soll auch bei einer unbekannten Anzahl von Videos funktionieren.

Ansatz:
Alle Dateinamen in ein array schreiben:

files=($(\ls *.mp4))

Den ersten und letzten Dateinamen (für das Ein-/Ausblenden von/nach schwarz) kann ich referenzieren
Erster: echo ${files[0]}
Letzter: echo  ${files[-1]}

Wie realisiere ich den Mittelteil, also Überblendung von 1 nach 2, 2 nach 2, ... vorletztes zu letztem?

Irgendwas mit Schleifen vermutlich, wobei beim Abrufen der Werte aus dem Array der Index um jeweils 1 hochgezählt werden müsste, bis der letzte Wert erreicht ist.

Fängt also an mit
melt colour:black out=20 ${files[0]} -mix 20 -mixer luma

dann die Schleife die so was erzeugt:
${files[1]} -mix 20 -mixer luma ${files[2]} -mix 20 -mixer luma ${files[2]} -mix 20 -mixer luma usw.

Endet mit colour:black out=20 -mix 20 -mixer luma

Wer kann mir bezüglich der gesuchten Schleife helfen?

Offline edlin

  • User
  • Posts: 669
Quick & Dirty meine schnelle Lösung. Nicht elegant, sollte aber funktionieren. Bei mir habe ich die Dateien v01.mp4 ... v06.mp4 genutzt. Im Prinzip setze ich die Befehlszeile (clip.melt) Stück für Stück zusammen und führe sie dann aus.

Code: [Select]
#!/bin/bash

# Alle Dateien entsprechend Suchmuster sortiert in Dump.txt schreiben
# Suchmuster evtl. anpassen

find . | grep mp4 | sort > Dump.txt

# Die erste Zeile wieder entfernen

sed -i 1D Dump.txt

# Den ersten Teil der Befehlszeile in die Datei clip.melt schreiben
# Setzt den fixen Dateinamen v01.mp4 voraus, evtl. anpassen

echo -n "melt colour:black out=20 v01.mp4 -mix 20 -mixer luma " > clip.melt

# Für alle Zeilen in Dump.txt die Befehlsteile an clip.melt anhängen
while read line
do
  echo -n $line >> clip.melt
  echo -n " -mix 20 -mixer luma " >> clip.melt
done < Dump.txt

# Abschluss der Befehlszeile für melt
echo -n "colour:black out=20 -mix 20 -mixer luma" >> clip.melt

# Ausführen und freuen
exec bash ./clip.melt

Es gibt sicher unzählige Wege das Problem zu lösen, nimms als Anregung.

edlin
„Erfahrung heißt gar nichts. Man kann eine Sache auch 35 Jahre falsch machen.“

Kurt Tucholsky

Offline pit

  • User
  • Posts: 241
Moin edlin & ganz herzlichen Dank!

Ich probier's heute Abend aus (noch sitze ich vor dem Dienst Notebook) und werde berichten.

Herzlichst
pit

Offline scholle1

  • Global Moderator
  • User
  • *****
  • Posts: 133
Noch ein Vorschlag:

Code: [Select]
#!/bin/sh
#
# Name: multifilm.sh
#
# Voraussetzung:
#  Eindeutige Dateinamen, die die Reihenfolge in der die Dateien
#  zusammengesetzt werden sollen widerspiegelt. Am besten Nummerierung
#  mit führenden Nullen. Die Nummerierung muss nicht durchgehend sein.
#
# Ausführen:
#  Dieses Skript im Ordner mit den .mp4 Dateien ablegen und ausführbar machen.
#  In den Ordner mit den .mp4 Dateien wechseln und das Skript aufrufen.
#

FIRST=$(ls *.mp4 | head -n 1)
LAST=$(ls *.mp4 | tail -n 1)
#echo "First is: $FIRST"       # Nur zum prüfen
#echo "Last is: $LAST"         # Nur zum prüfen

for i in *.mp4; do
  if [ "$i" = "$FIRST" ]       # Sonderbehandlung für die erste Datei
  then
    OUTPUT="melt colour:black out=20 $i -mix 20 -mixer luma";
    continue                   # Zur nächsten Iteration springen
   
  elif [ "$i" = "$LAST" ]      # Sonderbehandlung für die letzte Datei
  then
    OUTPUT="$OUTPUT $i -mix 20 -mixer luma colour:black out=20 -mix 20 -mixer luma";
   
  else
    OUTPUT="$OUTPUT $i -mix 20 -mixer luma ";
  fi
done

exec $OUTPUT       # Befehl ausführen

Der Befehl führt bei mir zum Fehler
Code: [Select]
[libprotobuf ERROR google/protobuf/descriptor_database.cc:120] File already exists in database: opencv-caffe.proto
[libprotobuf FATAL google/protobuf/descriptor.cc:1382] CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):
terminate called after throwing an instance of 'google::protobuf::FatalException'
  what():  CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):
Abgebrochen

Ich kenne mich mit melt nicht aus.

Da müsstest du noch einmal genauere Informationen posten.

Wichtig für das Skript ist eine posix konforme Bezeichnung der Dateien.
Die Shell sortiert die Dateinamen beim Befehl "ls" und in der "for" Schleife entsprechend.
Am besten mit Ziffern und führenden Nullen (005-film.mp4 oder 034-irgendetwas.mp4).
Buchstaben gehen auch und werden nach den Ziffern eingereiht.
Lücken in der Nummerierung sind unschädlich. Du kannst jeder Zeit einzelne Filme
aus dem Ordner entfernen, ohne dass es Probleme gibt; oder in Nummerierungslücken
hinzufügen.
« Last Edit: 2022/07/05, 18:41:37 by scholle1 »
"pax in terra" - Das ist mein großer, mein einzigster, von Herzen kommender Wunsch.
"Frieden auf der Erde" und alles Weitere erscheint einfach.

Offline pit

  • User
  • Posts: 241
Moin scholle1

Sehr cool, dein Script funktioniert auf Anhieb. Ich übergebe jetzt noch die Anzahl der Frames für die Überblendung via Variable $1, habe auch Audio-Überblendung ergänzt (... -mixer mix:-1) und melt schreibt jetzt in eine Datei, statt das Video sofort abzuspielen (letzte Zeile ergänzt um =>  -consumer avformat:$(date +%y%m%d-%H%M%S)-videomix.mp4 vcodec=libx264 b=2M acodec=aac ab=96k). Hier in Gänze:

Code: [Select]
#!/bin/sh
#
# Name: multifilm.sh
#
# Voraussetzung:
#  Eindeutige Dateinamen, die die Reihenfolge in der die Dateien
#  zusammengesetzt werden sollen widerspiegelt. Am besten Nummerierung
#  mit führenden Nullen. Die Nummerierung muss nicht durchgehend sein.
#
# Ausführen:
#  Dieses Skript im Ordner mit den .mp4 Dateien ablegen und ausführbar machen.
#  In den Ordner mit den .mp4 Dateien wechseln und das Skript aufrufen.
#

FIRST=$(ls *.mp4 | head -n 1)
LAST=$(ls *.mp4 | tail -n 1)
F=$1    # Anzahl der Frames für Überblendung
#echo "First is: $FIRST"       # Nur zum prüfen
#echo "Last is: $LAST"         # Nur zum prüfen

for i in *.mp4; do
  if [ "$i" = "$FIRST" ]       # Sonderbehandlung für die erste Datei
  then
    OUTPUT="melt colour:black out=$F $i -mix $F -mixer luma -mixer mix:-1";
    continue                   # Zur nächsten Iteration springen
   
  elif [ "$i" = "$LAST" ]      # Sonderbehandlung für die letzte Datei
  then
    OUTPUT="$OUTPUT $i -mix $F -mixer luma colour:black out=$F -mix 20 -mixer luma -mixer mix:-1";
   
  else
    OUTPUT="$OUTPUT $i -mix $F -mixer luma -mixer mix:-1 ";
  fi
done

exec $OUTPUT -profile hdv_720_30p -consumer avformat:$(date +%y%m%d-%H%M%S)-videomix.mp4 vcodec=libx264 b=2M acodec=aac ab=96k      # Befehl ausführen

Jetzt muss ich nochmal gucken, wie ich melt dazu bewege, die Videos nicht auf eine kleinere Auflösung runterzurechnen. Meine Test-Clips hatten 3840:2160, das Ergebnis 720x576. Nur ein Beispiel, normalerweise haben meine Clips nicht mehr als 1080p. Aber das alles hat mit deinem Script nichts mehr zu tun :-)

// edit
// Die Auflösung der Ausgabedatei steuert der melt Parameter profile
// Habe im Script (letzte Zeile) ergänzt:  -profile hdv_720_30p
// Eine Liste möglicher Auflösungen liefert:
// melt -query "profiles"

Also nochmal VIELEN Dank!
« Last Edit: 2022/07/05, 20:50:40 by pit »

Offline scholle1

  • Global Moderator
  • User
  • *****
  • Posts: 133
Hallo pit,
freut mich, dass ich dir helfen konnte.
;D
"pax in terra" - Das ist mein großer, mein einzigster, von Herzen kommender Wunsch.
"Frieden auf der Erde" und alles Weitere erscheint einfach.

Offline scholle1

  • Global Moderator
  • User
  • *****
  • Posts: 133
Habe das Skript noch einmal überarbeitet und vereinfacht.

Code: [Select]
#!/bin/sh
#
# Name: multifilm.sh
#
# Voraussetzung:
#  Eindeutige Dateinamen die die Reihenfolge, in der die Dateien
#  zusammengesetzt werden sollen, widerspiegelt. Am besten Nummerierung
#  mit führenden Nullen. Die Nummerierung muss nicht durchgehend sein.
#  Die Dateinamenerweiterung muss .mp4 lauten.
# Ausführen:
#  Dieses Skript z.B. in /usr/local/bin ablegen und ausführbar machen.
#  In den Ordner mit den .mp4 Dateien wechseln und das Skript aufrufen.
# Aufruf:
#  multifilm.sh 30
#  Der Parameter 30 gibt die Anzahl der Überblend-Frames an.
#  Er ist entsprechend den eigenen Wünschen anpassbar.


# Prüfung auf Vorhandensein des Parameters für die Überblend-Frames.
if [ $# -ne 1 ]
then
  echo "Der Parameter für die Anzahl der Überblend-Frames fehlt."
  exit 1
fi

# Befehl zusammenstellen
# 1. Einblenden
OUTPUT="melt colour:black out=$1"

# 2. Überblenden
for i in *.mp4; do
    OUTPUT="$OUTPUT $i -mix $1 -mixer luma -mixer mix:-1";
done

# 3. Ausblenden 
OUTPUT="$OUTPUT colour:black out=$1 -mix $1 -mixer luma -mixer mix:-1"

# Befehl mit Angabe der Codecs und Ausgabedatei ausführen. (In einer Zeile!)
exec $OUTPUT -profile hdv_1080_25p -consumer avformat:$(date +%y%m%d-%H%M%S)-videomix.mp4 vcodec=libx264 b=2M acodec=aac ab=96k
« Last Edit: 2022/07/07, 22:56:50 by scholle1 »
"pax in terra" - Das ist mein großer, mein einzigster, von Herzen kommender Wunsch.
"Frieden auf der Erde" und alles Weitere erscheint einfach.

Offline pit

  • User
  • Posts: 241
@scholle1

Ich habe noch eine kleine Erweiterung eingebaut. Melt versteht sich auf alle möglichen Video Container (mp4, mov, mpg ... usw.). Folgende Script-Variante fragt verschiedene Video File Extensions ab, ignoriert solche, die im Verzeichnis nicht vorkommen (shopt -s nullglob), behandelt vorhandene unabhängig von Groß- und Kleinschreibung (shopt -s nocaseglob) und arbeitet ansonsten wie beschrieben.

Code: [Select]
#!/bin/bash
case $1 in
    ''|*[!0-9]*) FRAMES="30" ;;
    *) FRAMES="$1" ;;
esac
OUTPUT="melt colour:black out=$FRAMES"
shopt -s nullglob
for i in `shopt -s nocaseglob && \ls -1 *.mp4 *.mpg *.mov *.webm *.avi *.ogv *.mkv *.flv *.mpeg && shopt -u nocaseglob`
do
# for i in *.mp4; do
    OUTPUT="$OUTPUT $i -mix $FRAMES -mixer luma -mixer mix:-1";
done
    OUTPUT="$OUTPUT colour:black out=$FRAMES -mix $FRAMES -mixer luma -mixer mix:-1";
shopt -u nullglob
exec $OUTPUT -profile hdv_1080_25p -consumer avformat:$(date +%y%m%d-%H%M%S)-videomix.mp4 vcodec=libx264 b=2M acodec=aac ab=96k

Offline scholle1

  • Global Moderator
  • User
  • *****
  • Posts: 133
Hallo @pit,

wir denken beide viel zu sehr um drei Ecken, weil wir ursprünglich
von .mp4 Dateien ausgingen und das Skript dann auf andere Dateitypen
erweitern wollten.
Statt
Code: [Select]
shopt -s nullglob
for i in `shopt -s nocaseglob && \ls -1 *.mp4 *.mpg *.mov *.webm *.avi *.ogv *.mkv *.flv *.mpeg && shopt -u nocaseglob`, do
 . . .
shopt -u nullglob

reicht
Code: [Select]
for i in $(ls); do
 - weil wir für die Zusammenstellung der Videos einen separaten Ordner verwenden,
 - weil in diesem Ordner ausschließlich Videos landen,
 - weil wir die Videos mit führenden Ziffern entsprechend ihrer späteren Reihenfolge umbenennen,
 - weil melt mit nahezu allen erdenklichen AV Formaten umgehen kann,
 - weil `ls` alle Videos, gleichgültig welcher Formate, aufsteigend nach den Ziffern sortiert,
 - weil `ls` nur existierende Videos ausgibt und keine RegEx mit Metazeichen verarbeiten muss.

Manchmal ist die Lösung sooooo einfach dass man schier daran vorbei denkt.
"pax in terra" - Das ist mein großer, mein einzigster, von Herzen kommender Wunsch.
"Frieden auf der Erde" und alles Weitere erscheint einfach.

Offline pit

  • User
  • Posts: 241
Hallo @scholle1

Erneut vielen Dank!

Du hast ja recht - Keep it simple, stupid (letzteres bezieht sich auf mich selbst) ;-)

Da du augenblicklich im irc nicht erreichbar bist: Artikel ist redigiert u. liegt mit neuem Namen in der Cloud.


Offline scholle1

  • Global Moderator
  • User
  • *****
  • Posts: 133
Habe das Skript noch einmal überarbeitet, vereinfacht und zusätzliche
Informationen als Kommentar bereitgestellt.

 - Verarbeitung der Option für die Überblend-Frames verbessert.
   Besteht die Option nicht ausschließlich aus Dezimalziffern, wird sie verworfen.
 - Verarbeitung von Videodateien vereinfacht.
   melt kann in einem Aufruf nahezu alle AV Formate als Eingabe verarbeiten, die auch FFmpeg beherrscht.
   Deshalb ist eine Filterung nach Dateinamenserweiterungen nicht notwendig.
 - Kommentare angepasst.
   Hiweis auf einen separaten Ordner für die zusammen zu fügenden Videos.
   Erklärungen zu den Dateinamen.
   Link zur Dokumentation von melt und FFmpeg eingefügt.

pit und scholle1 hoffen, dass ihr eure Freude mit dem Skript habt.

Code: [Select]
#!/bin/bash
#
# Name: multifilm.sh
#
# Voraussetzung:
#  Ein separater Ordner nur für die zusammen zu fügenden Videos.
#  Eindeutige Dateinamen die die Reihenfolge, in der die Dateien
#  zusammengesetzt werden sollen, widerspiegelt. Am besten eignet sich
#  eine Nummerierung mit führenden Nullen am Anfang der Dateinamen.
#  Die Nummerierung muss nicht durchgehend sein.
#  Unterstützt werden für die Eingabe fast alle Audio- und Videoformate,
#  die FFmpeg auch verarbeiten kann. Siehe
#  https://www.mltframework.org/docs/melt/
#  https://www.ffmpeg.org/general.html#Supported-File-Formats_002c-Codecs-or-Features
#  Die Ausgabe erfolgt in eine .mp4 Datei.
#
# Ausführen:
#  Dieses Skript z.B. in /usr/local/bin ablegen und ausführbar machen.
#  In den Ordner mit den Video Dateien wechseln und das Skript aufrufen.
#
# Aufruf:
#  multifilm.sh nn
#  Die Option nn gibt die Anzahl der Überblend-Frames an. Ist sie nicht
#  vorhanden, wird der Wert 30 benutzt.
#


# Prüfung auf Existenz und Art der Option für die Überblend-Frames.
case $1 in
    ''|*[!0-9]*) FRAMES="30" ;;
    *) FRAMES="$1" ;;
esac


# Befehl zusammenstellen
# 1. Einblenden
OUTPUT="melt colour:black out=$1"

# 2. Überblenden
for i in $(ls); do
    OUTPUT="$OUTPUT $i -mix $FRAMES -mixer luma -mixer mix:-1";
done

# 3. Ausblenden 
OUTPUT="$OUTPUT colour:black out=$1 -mix $1 -mixer luma -mixer mix:-1"


# Befehl mit Angabe der Ausgabedatei und der Codecs ausführen. (In einer Zeile!)
exec $OUTPUT -profile hdv_1080_25p -consumer avformat:$(date +%y%m%d-%H%M%S)-videomix.mp4 vcodec=libx264 b=2M acodec=aac ab=96k
"pax in terra" - Das ist mein großer, mein einzigster, von Herzen kommender Wunsch.
"Frieden auf der Erde" und alles Weitere erscheint einfach.

Offline pit

  • User
  • Posts: 241
Auch an dieser Stelle der Hinweis auf einen gemeinsam (@scholle1 + @pit) verfassten Bericht zu diesem Thema:

Gastbeitrag auf linuxnews.de =>
https://linuxnews.de/2022/07/videos-zusammenschneiden-script-oder-gui/