URL: https://linuxfr.org/users/purplepsycho/journaux/un-timelapse-avec-ffmpeg Title: Un timelapse avec ffmpeg Authors: purplepsycho Date: 2025年11月19日T14:57:40+01:00 License: CC By-SA Tags: timelapse, imagemagick, vidéo et ffmpeg Score: 24 J'ai eu besoin de faire un timelapse sur une longue période de vidéo (3 semaines). Pour ne pas trop me prendre la tête, j'ai utilisé `ffmpeg` et `bash` pour automatiser ce que je pouvais. Je laisse cela ici, en espérant que ça puisse en aider certains (dont moi dans le futur). Bonne lecture # Timelapse Pour faire un joli timelapse, j'ai divisé le travail en sous taches : 1. Acquérir des images, 2. Moyenner les images acquises, 3. Fusionner les moyennes en clips, 4. Fusionner les clips en video, 5. Accélérer la video, 6. Ajouter du son. # 1. Acquisition des images On a un script qui enregistre bêtement des images, aussi vite que possible, mais pas trop quand même, au mieux 1 image par seconde. C'est un script que je laisse tourner sur un serveur (enfin un PC jamais éteint) ``` #! /bin/bash # camera IP IP=172.22.10.34 # Errors and images counts ERRCNT=0 CNT=0 # Use another IP if asked if [ $# -eq 1 ] then IP=1ドル fi # Forever while true do # File to generate FILE="$(date "+%F_%H-%M-%S.jpg")" # File to store error OUT=$(mktemp) # increase counter CNT=$((CNT+1)) # get one image thanks to ffmpeg # ! warning, here I integrated the credential in the url, it's not necessary on all camera... ffmpeg -y -i "rtsp://login:password@$IP/axis-media/media.amp" -vframes 1 "$FILE" 2> "$OUT" # Test for error if grep --quiet "error" "$OUT"; then # increase error count ERRCNT=$((ERRCNT+1)) # Inform user echo -n -e "$(date +%T) Bad image, deleting. ($ERRCNT error(s) on $CNT)\r" remove image file rm "$FILE" fi # remove error file rm "$OUT" done ``` # 2. Génération des moyennes Ici, on va moyenner les images. On moyenne ensemble les images qui sont dans les 10 secondes. C'est à dire, les images * `2025年12月31日-12-00-01.jpg` * `2025年12月31日-12-00-02.jpg` * `2025年12月31日-12-00-05.jpg` * `2025年12月31日-12-00-07.jpg` * `2025年12月31日-12-00-09.jpg` Seront fusionnées dans le fichier `2025年12月31日-12-00-0x.jpg` Ce script tourne sur le même serveur que le précédent. ``` #!/bin/bash # Directory to stores averages mkdir -p averages # Forever while true do # Finding all jpg files in current directory FILES=$(find . -maxdepth 1 -name "*jpg" -mmin +1 ) # Wait 10 seconds to be sure that all interval will be complete sleep 10 # For each file... for i in $FILES; do # Ignore if file has already been processed if [ ! -e "$i" ] ; then continue fi # Select one file FILE=$(basename "$i") # Create a regexp to select all files in the same 10 seconds interval (like 2025年12月30日-12-5*.jpg) REGEXP=$(echo $FILE | sed 's/\(....-..-.._..-..-.\)./1円*/') # Destination file: (like 2025年12月30日-12-5x.jpg) DESTFILE=$(echo $FILE | sed 's/\(....-..-.._..-..-.\)./1円x/') # create empty image list and temporary files IMAGELIST= CMD=$(mktemp) LIST=$(mktemp) # Generate list of image matching the regexp find . -maxdepth 1 -name "$REGEXP"> "$LIST" # Convert these images names to a list while IFS= read -r j; do IMAGELIST="$j $IMAGELIST" done < "$LIST" # prepare a imagemagick command to average them echo "convert -average $IMAGELIST averages/$DESTFILE"> "$CMD" chmod +x "$CMD" #execute the imagemagick command sh -c "$CMD" # cleanup rm "$CMD" rm "$LIST" rm $IMAGELIST done # wait 30 seconds, no rush sleep 30 done ``` # 3. Génération des clips On a un paquet d'images, on peut les fusionner simplement dans un clip avec la commande `ffmpeg -y -pattern_type glob -i "averages/*.jpg" clip.mp4`, où, on peut générer un clip par heure, ce qui facilite grandement le montage derrière (dans mon cas, j'ai 3 semaines d'images) Ce script ne tourne pas tout seul. Je le lance quand j'en ai besoin, ça peut être un peu long si ça fait longtemps que je l'ai pas fait tourner. Je pourrais l'automatiser, mais la flemme est plus forte. ``` #! /bin/sh # Check user called that program correctly if [ $# -ne 2 ] ; then echo "usage $(basename "0ドル") date hour" echo "" echo " date: yyyy-mm-dd format" echo " hour: 24 hour format" exit fi # create destination directory mkdir -p by-hour # make sur that morning hour start with a 0, to simplify sorting HOUR=$(printf "%02d" 2ドル) # ask ffmpeg to do its magic ffmpeg -y -pattern_type glob -i "averages/1ドル_$HOUR*.jpg" "by-hour/1ドル_2ドル".mp4 ``` # 4. Concaténer les clips On a plein de petits clips qu'on va vouloir coller ensemble, pour cela, on les liste dans un fichier : ``` file 2025年11月18日_11.mp4 file 2025年11月18日_15.mp4 file 2025年11月19日_10.mp4 ``` Et on demande gentiement à `ffmpeg` de les coller entre eux ``` ffmpeg -y -f concat -i files.txt -c copy timelapse.mp4 ``` # 5. Accélérer la video À partir d'ici, j'ai rapatrier les clips qui m'intéressent sur mon poste. Pour que mon timelapse soit pas trop long, j'ai eu besoin de l'accélérer. Pour cela, on utilise des commandes barbares: ``` # Extract frames info ffmpeg -y -i timelapse.mp4 -map 0:v -c:v copy -bsf:v h264_mp4toannexb raw.h264 # Generate faster video (to match audio duration), here 62fps ffmpeg -y -fflags +genpts -r 62 -i raw.h264 -c:v copy timelapse-fast.mp4 ``` # 6. Ajouter du son Un dernier truc à savoir quand on veut faire un film avec du son sans se prendre la tête, c'est d'utiliser le format mkv. Les autres conteneurs que j'ai testé (au moins mp4 et mov) sont plus délicats à utiliser. ``` ffmpeg -i timelapse.mp4 -i bruit.mp3 -c:v copy -c:a copy timelapse.mkv ````