DJI Fade/In Fade/Out


DNS / DHCP / Nagios / Gammu / Asterisk / MusicPlayerDaemon / Arduino RaspberryPI / OpenVPN | Créer son image pour Raspberry PI | DJI Fade | Reolink Timelapse | K8S on Raspberry Pi


Enchainement de vidéos avec effet de fade in/out et ajout de musique par ffmpeg

L’objectif et de récupérer des vidéos muettes, de les enchainer avec un effet de fade-in / fade-out entre chaque vidéo et d’y ajouter une musique (de préférence en creative commons) pour pouvoir ensuite publier le résultat sur youtube par exemple.

Installation

Dans un répertoire placer les deux scripts fade.sh, fade-and-concat.sh, les rendre executables

$> chmod 755 fade.sh
$> chmod 755 fade-and-concat.sh

Créer un répertoire musics dans lequel on va placer les musiques ou le script ira en chercher une au hasard.

mkdir musics/
$ ls -l
total 63520
-rwxr-xr-x@ 1 ptro  staff      2335  7 aoû 16:43 fade-and-concat.sh
-rwxr-xr-x@ 1 ptro  staff      2116  7 aoû 16:42 fade.sh
drwxr-xr-x  7 ptro  staff       224  7 aoû 15:15 musics

$ ls -l musics/
total 58496
-rw-r--r--@ 1 ptro  staff  5393408  7 aoû 14:50 RENAE_-_Heart_of_a_Lion__Leo_.mp3
-rw-r--r--@ 1 ptro  staff  5176832  7 aoû 14:56 RENAE_-_Rebels_With_A_Cause__Aries_.mp3
-rw-r--r--@ 1 ptro  staff  7401984  7 aoû 14:56 RENAE_-_Roses__Taurus_.mp3
-rw-r--r--@ 1 ptro  staff  6154240  7 aoû 14:54 RENAE_-_Through_My_Eyes__Gemini_.mp3
-rw-r--r--@ 1 ptro  staff  5150720  7 aoû 14:56 RENAE_-_Waves__Cancer_.mp3

Créer un répertoire pour chaque projet, y placer les videos, se placer dans un répertoire projet et créer un lien symbolique vers ../musics, puis lancer le script ../fade.sh VIDEO.MP4 si il y a une seule video, ou ../fade-and-concat.sh VIDEO1.MP4 VIDEO2.MP4 … si il y a plusieurs videos.

Exemple d’utilisation

$ cd Falaise2/

$ ln -s ../musics

$ ls -l
total 2458064
-rwxrwxrwx@ 1 ptro  staff  701182405 25 jul 19:11 Pano.MP4
-rwxrwxrwx@ 1 ptro  staff  280512499 25 jul 19:41 Riviere.MP4
-rwxrwxrwx@ 1 ptro  staff  138970356 25 jul 19:44 SousPont.MP4
lrwxr-xr-x  1 ptro  staff         10  7 aoû 16:45 musics -> ../musics/

Lancement du script

$ ../fade-and-concat.sh Riviere.MP4 Pano.MP4 SousPont.MP4
calculate fade:in/fade:out for file Riviere.MP4 31.532000
calculate fade:in/fade:out for file Pano.MP4 78.779000
calculate fade:in/fade:out for file SousPont.MP4 15.566000
concat all intermediates videos with demuxer
select random free music
select musics/RENAE_-_Heart_of_a_Lion__Leo_.mp3 with duration 232 for fullVideoDuration 125
calculate fade:out musics/RENAE_-_Heart_of_a_Lion__Leo_.mp3

Résultats

La vidéo résultat est le fichier project.mp4, c’est lui qu’il faut publier.

$ ls -l
total 2458064
-rwxrwxrwx@ 1 ptro  staff  701182405 25 jul 19:11 Pano.MP4
-rwxrwxrwx@ 1 ptro  staff  280512499 25 jul 19:41 Riviere.MP4
-rwxrwxrwx@ 1 ptro  staff  138970356 25 jul 19:44 SousPont.MP4
drwxr-xr-x  8 ptro  staff        256  7 aoû 16:49 logs
lrwxr-xr-x  1 ptro  staff         10  7 aoû 16:45 musics -> ../musics/
-rw-r--r--  1 ptro  staff  129504561  7 aoû 16:52 project.mp4

Script pour le calcul sur une seul video

#!/bin/bash

fadeDuration=0.2
audioFadeDuration=5
rm -rf fades logs fileslist.txt
mkdir fades logs
videoFile=$1
duration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 ${videoFile})
echo "calculate fade:in/fade:out for file ${videoFile} ${duration}"
offset=$(bc -l <<< "${duration}"-${fadeDuration})
ffmpeg -i ${videoFile} -filter_complex "[0:v]fade=type=in:duration=${fadeDuration},fade=type=out:duration=${fadeDuration}:start_time='$offset'[v]" -map "[v]" -y input.mp4 > logs/${videoFile}.out 2>&1

rm -f fileslist.txt
rm -rf fades/

fullVideoDuration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 input.mp4 | awk -F'.' '{printf("%s\n",$1);}')
echo "select random free music"
music=$(ls musics/ | sort -R | tail -n 1)
fullMusicDuration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 musics/${music} | awk -F'.' '{printf("%s\n",$1);}')
while [ $fullMusicDuration -le  $fullVideoDuration ]
do
    echo "skip musics/${music} with duration ${fullMusicDuration} for fullVideoDuration ${fullVideoDuration}"   
    music=$(ls musics/ | sort -R | tail -n 1)
    fullMusicDuration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 musics/${music} | awk -F'.' '{printf("%s\n",$1);}')
done

echo "select musics/${music} with duration ${fullMusicDuration} for fullVideoDuration ${fullVideoDuration}"

ffmpeg -i input.mp4 -i musics/${music} -map 0 -map 1:a -codec copy -shortest -y output.mp4 > logs/merge-music.out 2>&1

echo "calculate fade:out musics/${music}"
duration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 output.mp4)
videoOffset=$(bc -l <<< "${duration}"-${fadeDuration})
audioOffset=$(bc -l <<< "${duration}"-${audioFadeDuration})
ffmpeg -i output.mp4 -filter_complex "[0:v]fade=type=in:duration=${fadeDuration},fade=type=out:duration=${fadeDuration}:start_time='$videoOffset'[v];[0:a]afade=type=in:duration=1,afade=type=out:duration=5:start_time='$audioOffset'[a]" -map "[v]" -map "[a]" -y project.mp4 > logs/project.out 2>&1

rm -f output.mp4 input.mp4 filelist.txt

Script pour enchainer plusieurs videos.

#!/bin/bash

fadeDuration=0.2
audioFadeDuration=5
rm -rf fades logs fileslist.txt
mkdir fades logs
for videoFile in "$@"
do
    duration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 ${videoFile})
    echo "calculate fade:in/fade:out for file ${videoFile} ${duration}"
    offset=$(bc -l <<< "${duration}"-${fadeDuration})
    ffmpeg -i ${videoFile} -filter_complex "[0:v]fade=type=in:duration=${fadeDuration},fade=type=out:duration=${fadeDuration}:start_time='$offset'[v]" -map "[v]" -y fades/${videoFile} > logs/${videoFile}.out 2>&1
    echo "file 'fades/${videoFile}'" >> fileslist.txt
done
echo "concat all intermediates videos with demuxer"
ffmpeg -f concat -safe 0 -i fileslist.txt -c copy -y input.mp4 > logs/concat.out 2>&1

rm -f fileslist.txt
rm -rf fades/

fullVideoDuration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 input.mp4 | awk -F'.' '{printf("%s\n",$1);}')
echo "select random free music"
music=$(ls musics/ | sort -R | tail -n 1)
fullMusicDuration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 musics/${music} | awk -F'.' '{printf("%s\n",$1);}')
while [ $fullMusicDuration -le  $fullVideoDuration ]
do
    echo "skip musics/${music} with duration ${fullMusicDuration} for fullVideoDuration ${fullVideoDuration}"   
    music=$(ls musics/ | sort -R | tail -n 1)
    fullMusicDuration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 musics/${music} | awk -F'.' '{printf("%s\n",$1);}')
done

echo "select musics/${music} with duration ${fullMusicDuration} for fullVideoDuration ${fullVideoDuration}"

ffmpeg -i input.mp4 -i musics/${music} -map 0 -map 1:a -codec copy -shortest -y output.mp4 > logs/merge-music.out 2>&1

echo "calculate fade:out musics/${music}"
duration=$(ffprobe -loglevel error -show_entries format=duration -of default=nk=1:nw=1 output.mp4)
videoOffset=$(bc -l <<< "${duration}"-${fadeDuration})
audioOffset=$(bc -l <<< "${duration}"-${audioFadeDuration})
ffmpeg -i output.mp4 -filter_complex "[0:v]fade=type=in:duration=${fadeDuration},fade=type=out:duration=${fadeDuration}:start_time='$videoOffset'[v];[0:a]afade=type=in:duration=1,afade=type=out:duration=5:start_time='$audioOffset'[a]" -map "[v]" -map "[a]" -y project.mp4 > logs/project.out 2>&1

rm -f output.mp4 input.mp4 filelist.txt

DNS / DHCP / Nagios / Gammu / Asterisk / MusicPlayerDaemon / Arduino RaspberryPI / OpenVPN | Créer son image pour Raspberry PI | DJI Fade | Reolink Timelapse | K8S on Raspberry Pi