Manche Digitalkameras können Fotos in einem bestimmten Zeitintervall auslösen. Nach ein paar Stunden sammeln sich viele Fotos in einem Ordner an, welche man mit ffmpeg in ein Video umwandeln kann. Ich habe einige Zeit gebraucht, bis alles endlich funktioniert hat. Hier seht ihr, wie man das mit ffmpeg machen kann.
Schritt für Schritt
Ausgangslage
Als Ausgangslage habe ich viele Fotos in einem Verzeichnis:
2011-07-08_13-59-58.jpg 2011-07-08_15-01-27.jpg 2011-07-08_16-02-57.jpg
2011-07-08_14-00-07.jpg 2011-07-08_15-01-38.jpg 2011-07-08_16-03-08.jpg
2011-07-08_14-00-17.jpg 2011-07-08_15-01-47.jpg 2011-07-08_16-03-17.jpg
[...]
In meinem Fall sind das 1104 Fotos:
1104
Diese Fotos haben zusammen eine Grösse von 2.4 GB:
1.6M 2011-07-08_13-59-58.jpg
1.6M 2011-07-08_14-00-07.jpg
[...]
2.0M 2011-07-15_14-48-28.jpg
2.4G insgesamt
Ich möchte von diesen Fotos ein HD-Video umwandeln. Die Fotos haben eine Auflösung von 2592 x 1944 Pixel:
Resolution : 2592 x 1944
Fotos verkleinern
Da die Fotos zu gross sind, verkleinert man die Fotos auf zuerst auf 1080 Pixel in der Höhe:
do
convert -resize x1080 -quality 50 "$datei" "small_$datei"
done
Fotos umbenennen
Damit ffmpeg die Fotos in ein Video umwandeln kann, müssen die Fotos im Format wie 0001.jpg vorliegen. Die führenden Nullen sind für ffmpeg wichtig. Die Fotos können mit convert (aus dem Paket imagemagick) konvertiert werden:
NUMBER="1"
find *.jpg | while read foto
do
mv $foto "`printf %0${LENGTH}d $NUMBER`".jpg
NUMBER=$((NUMBER + 1))
done
Fotos in ein Video konvertieren
Jetzt kann man mit ffmpeg die Fotos in ein Video umwandeln:
Fertig: Video abspielen
Das Video ist nach dem Konvertieren 28 MB gross:
28M output.mpg
Das Video kann jetz abgespielt werden
Automatisch mit einem Skript
Um diese Schritte zu vereinfachen, habe ich ein kleines Bash-Skript pic2vid geschrieben, welches all diese Schritte schön ausführt:
########################################################################
#
# pic2vid
# Konvertiert mehrere Fotos zu einem Video (Zeitraffer)
#
# GNU General Public License
# 2012 by Emanuel Duss
#
########################################################################
########################################################################
# Variabeln
DIR="$1"
PICDIR="pic2vid"
SMALLDIR="$DIR/$PICDIR"
SIZE="x1080"
QUALITY="90"
OUTPUTFILE="output.mpg"
CODEC="libx264"
FRAMESPERSECOND="25"
########################################################################
# Funktionen
Printusage () {
echo "Usage:
$0 directory"
}
########################################################################
# Main
# Prüfe Fehler
if [ -z "$1" ]
then
Printusage
exit 1
fi
if [ ! -d "$DIR" ]
then
echo "$DIR ist kein Verzeichnis"
Printusage
exit 1
fi
if [ -d "$SMALLDIR" ]
then
echo "Verzeichnis für aufzubereitende Fotos bereits vorhanden."
else
mkdir "$SMALLDIR"
fi
if [ ! -d "$SMALLDIR" ]
then
echo "Kann $SMALLDIR nicht anlegen. Bitte Berechtigungen prüfen."
exit 1
fi
cd $DIR
# Fotos verkleinern (nur, wenn noch nicht verkleinert)
TOTAL="`ls *.[Jj][Pp][Gg] | wc -l`"
COUNT="1"
for file in *.[Jj][Pp][Gg]
do
if [ -f "${PICDIR}/$file" ]
then
echo "Überspringe $file, da bereits konvertiert (${PICDIR}/$file)"
else
echo "$file: Foto $COUNT von $TOTAL ($((100 * $COUNT / $TOTAL))%)"
convert -resize $SIZE -quality $QUALITY "$file" "${PICDIR}/$file"
fi
((COUNT++))
done
# Fotos umbenennen (in Form wie 0001.jpg bis 2342.jpg)
cd $PICDIR
LENGTH="`ls *.[Jj][Pp][Gg] | wc -l | wc -L`"
NUMBER="1"
for file in *.[Jj][Pp][Gg]
do
NEWNAME="`printf %0${LENGTH}d $NUMBER`.jpg"
if [ -f "$NEWNAME" ]
then
echo "Datei $file bereits umbenannt. OK."
else
# Symlink statt umbenennen, damit die Prüfung ob schon konvertiert auch funktioniert
ln -s "$file" "`printf %0${LENGTH}d $NUMBER`".jpg
fi
((NUMBER++))
done
# Bilder mit ffmpeg zu Video zusammenfügen
ffmpeg -f image2 -i %0${LENGTH}d.jpg -r $FRAMESPERSECOND -vcodec $CODEC ../$OUTPUTFILE
# EOF
Das Skript sagt einem, wie man es anwenden muss:
Usage:
pic2vid directory
So erstelle ich z. B. im aktuellen Verzeichnis mit allen Bildern ein Video:
Und schon hat man sein Zeitraffervideo.
Links und weitere Informationen
- ffmpeg: https://ffmpeg.org
- ffmpeg Manpage: https://ffmpeg.org/ffmpeg.html
LENGTH=`ls | wc -l | wc -L`
NR=”1″
find *.jpg | while read foto
do
mv $foto “`printf %0${LENGTH}d $NR`”.jpg
NUMMER=$((NUMMER + 1)) <<<—– muss es nicht NR=$((NR+1)) heißen,
sonst bleibt genau 1 Bild über
done
Hey
Oh ja, das stimmt. Im kompletten Skript wars richtig, aber im kleinen Abschnitt oberhalb nicht. Ich habs korrigiert.
Merci!
GRZ
Emanuel
Eine super Anleitung. Vielen Dank an dieser Stelle. Soweit ist alles kein Problem. Bis auf die Umwandlung per ffmpeg. Mit dem Codec libx264 bekomme ich zwar ein File das sich aber entweder nicht abspielen lässt, oder aber ohne Bild abgespielt wird (Windows VLC Player). Kodiere ich ohne libx264, also als mpeg1 bekomme ich ein Video, aber halt mit schlechter Qualität.
Die Umwandlung läuft sauber und ohne Fehlermeldung, aber irgendwas stimmt mit dem mpeg File dann nicht. Hab jetzt schon Stunden mit div. Einstellungen rumprobiert und komme nicht weiter.
Eine Idee?
Gruß
Alex
Hallo Alex
Bitte.
Hast du die `x264` Library installiert? Unter ArchLinux ist sie im Paket `x264`. Mit `ffmpeg -codecs` siehst du, welche Codecs installiert sind. Vielleicht fehlt diese.
Du kannst auch ein anderer Codec aus der Liste von `ffmpeg -codecs` ausprobieren.
Wie sieht es mit anderen Mediaplayern aus? Was sagt `mplayer` oder `mpv`?
Gruss
Emanuel
Hi Alex,
hast Du es beim Kodieren mit libx264 einmal versucht das Pixelformat anzugeben. Was für ein Format haben Deine Ausgangsbilder?
Die Option für das Pixelformat ist -pix_fmt yuv420p und wird bei PNGs empfohlen.
Außerdem kann ffmpeg auch ohne das strenge Format 00001.jpg mit fortlaufender Nummer arbeiten, nämlich mit der Option -pattern_type glob
ffmpeg -pattern_type glob -i ‘Bild*.jpg’ …
Hallo Jan
Die Option -pattern_type glob gefällt mir 🙂
Danke und Gruss
Emanuel
Hallo Emanuel,
vielen Dank für deine Hilfe. Gerade die Umwandlung der Dateinamen hatte mir zuerst etwas Mühe bereitet. Allerdings ist in deinem “Mini-Skript” ganz oben noch ein Fehler:
mv $foto “`printf %0${LENGTH}d $NR`”.jpg
Hier muss natürlich $NR durch $NUMMER ersetzt werden, ansonsten hast du nach der Konvertierung nur eine Datei mit 000.jpg.
Kannst du bei Gelegenheit ja mal ändern.
Gruß, Olli
Hallo Olli
Oh, vielen Dank, ich habe es korrigiert.
Gruss
Emanuel
Besser bei “ls | wc -l | wc -L” schreiben: “ls -1 | ……”.
Sonst kriegst du womöglich mehrere Files pro Zeile und zählst falsch.
Hallo Thomas
Wenn “ls” an die Standardausgabe schreibt, wird nur ein File pro Zeile ausgegeben, sprich das “-1” ist überflüssig.
Gruss
Emanuel
Ich habe das Problem, das ffmpeg einfach abbricht, wenn ein Bild mit 0 Byte in meinem Verzeichnis mit den Bildern ist.
Ich hole mit wget per cronjob alle 2 Minuten ein Bild meiner Webcam und speichere es auf meinem Raspberry.
Dabei kommt es scheinbar vor, das die Webcam das Bild noch gar nicht zu Ende geschrieben hat, aber per wget die unvollständige Datei trotzdem geholt wird…
Hallo Andre
Wenn es 0 Byte ist, ist es auch kein Bild mehr. So kannst du auf 0 Byte grosse Bilder testen:
Gruss
Emanuel
Hallo Zusammen,
habe das Scriptschnipsel zum umbenennen versucht, alles ist auch logisch.
Allerdings schmeist mir meine QNAP nur Mist aus.
Ich habe bspw. 12 Dateien und möchte diese umbenennen, das umbenennen funktioniert zwar, aber nicht wie gewünscht ;-(. Das kommt dabei raus’:
_4V5GK~E.JPG
_5552A~Z.JPG
…..
Kann mir einer erklären, wo der Fehler liegt?!?
Danke schön, …
Ich selber kenne QNAP nicht genau. Vielleicht läuft dort eine andere Shell, welche die Schreibweise NUMBER=$((NUMBER + 1)) nicht unterstützt. Diese könnte durch die Schreibweise NUMBER="`expr $NUMBER + 1`" ersetzt werden.
Habe es gerade ausprobiert, aber leider nein, geht dennoch nicht ;-(
Habe es etwas anders hinbekommen.
‘LENGTH=`ls | wc -l | wc -L`
LENGTH=”4″ …. da ich von nicht mehr als 9999 Dateien ausgehe.
NUMBER=”1″
find *.jpg | while read foto
do
mv $foto “`printf %0${LENGTH}d $NUMBER`”.jpg
NUMBER=$((NUMBER + 1))
done
Dennoch danke für die Antwort.
OK, falls die Maximallänge bekannt ist, ein passender Workaround 🙂
Hallo Emanuel
Vielen Dank für das Skript. Bei mir ist dasselbe Problem aufgetaucht wie bei Alex. VLC zeigt nichts an. Jedoch mit Kodi (XBMC) kann ich das Video anschauen.
lg
christoph
Hallo Christoph
Vielleicht kannst du mal ein anderes Ausgabeformat ausprobieren (mit -vcodec und -acodec).
LG
Emanuel
Hallo Emanuel,
das Script ist wirklich sehr hilfreich. Es hat alles gut geklappt. Nun beginne ich auch zu verstehen, was da abläuft.
Vielen Dank für diese Arbeit, die mich um Stunden nach vorn gebracht hat.
Viele Grüße
Jürgen
Hallo Jürgen
Das freut mich zu hören 🙂
Gruss,
Emanuel
Hallo Emanuel,
vielen Dank für die Anleitung. Ich bin ein Linux Anfänger und weiß nicht was die Fehlermeldung bedeutet…
Could find no file with path ‘%0d.JPG’ and index in the range 0-4
%0d.JPG: No such file or directory
Diese tritt beim letzten Schritt auf. Bei: ffmpeg -f image2 -i %0${LENGTH}d.jpg -r 25 -vcodec libx264 output.mpg
Kannst du mir helfen?
Grüße Viktor
Hoi Viktor
Gern geschehen 🙂
Sehe ich das richtig, dass du die Schritte manuell durchgeführt hast, ohne das Script zu verwenden?
Das sieht aus, als ob die Variable $LENGTH leer ist. Du musst die Befehle vom Schritt “Fotos umbenennen” und “Fotos in ein Video konvertieren” in der gleichen Shell (= im gleichen Konsolen-Fenster) ausführen, damit die Variable $LENGTH auf die nötige Länge gesetzt werden kann. Diese wird dann im zweiten Schritt verwendet.
Hast du schon probiert, alle Schritte in einem einzigen Schritt mittels dem Script durchzuführen? Das sollte eigentlich auf anhieb klappen.
Gruss,
Emanuel
Hi Emanuel,
vielen Dank für die super Anleitung!
Ich nutze das für eine IP Cam, die ich im Garten installiert habe. Die macht alle 5 Minuten ein Bild, so möchte ich den Wechsel vom Winter in den Sommer dokumentieren. Dein Skript funktioniert dafür super!
FFMPEG gibt zwar einige Fehlermeldungen bzw. Warnungen aus, das Resultat ist aber einwandfrei!
Viele Grüße
Sebastian