Combining images with a fade in ffmpeg
Posted: | Tags: ffmpeg tilThe following post outlines how to use ffmpeg to take a number of images and create a video with each image present for a set duration with cross fades. The images are centered in the video with a black background. There are some instances when a previous image may be visible if it’s too large, it’s been a while since I tested this thoroughly so it could use some tweaking.
This ffmpeg command takes in 3 images displaying each for 6 seconds. The filter complex adds a 1 second fade between the first and second, and second and third images. It also ensures that none of the images are stretched and the video stream has a width 1280 and a height of 720, any empty space around the images will be padded with black. The resulting video will be 25 frames per second with the name output.mp4
.
ffmpeg \
-loop 1 -t 6 -i 01.jpg \
-loop 1 -t 6 -i 02.jpg \
-loop 1 -t 6 -i 03.jpg \
-filter_complex "[1]fade=d=1:t=in:alpha=1,setpts=PTS-STARTPTS+2/TB[f1]; \
[2]fade=d=1:t=in:alpha=1,setpts=PTS-STARTPTS+4/TB[f2]; \
[0][f1]overlay[bg1];[bg1][f2]overlay,format=yuv420p[v]; \
[v]scale=w=1280:h=720:force_original_aspect_ratio=1,pad=1280:720:(ow-iw)/2:(oh-ih)/2[v0]" \
-map [v0] -r 25 output.mp4
Doing this for a large number of images is tedious so this bash script will automate the process of writing the ffmpeg for you. Set img_dir
to the directory of your images, image_duration
for how long you’d like each image to be on screen, and fade_duration
to how long each fade will last.
#!/bin/bash
# This script takes image files from a directory and uses ffmpeg to concatenate, center and add crossfades between each image. It returns an .mp4 file with the video.
# Set variables
img_dir=./imgs
image_duration=6
fade_duration=1
# Creates input files with loop and image duration
# Creates fade filter with filter duration and trims the last iteration with sed
input_files=''
filter=''
iteration=1
for entry in "$img_dir"/*
do
input_files+=" -loop 1 -t $image_duration -i $entry"
filter+=" [$iteration]fade=d=$fade_duration:t=in:alpha=1,setpts=PTS-STARTPTS+$(($iteration*2))/TB[f$iteration];"
iteration=$(($iteration+1))
done
filter=$(echo $filter | sed 's/;[^;]*$//' | sed 's/;[^;]*$//')
# Creates overlay filter and sets scale for video centering images
overlay_str='[0][f1]overlay[bg1];'
iteration=$(($iteration-5))
for (( i=0; i<=$iteration; i++))
do
overlay_str+=" [bg$(($i+1))][f$(($i+2))]overlay[bg$(($i+2))];"
done
overlay_str+="[bg$(($iteration+2))][f$(($iteration+3))]overlay,format=yuv420p[v]; [v]scale=w=1280:h=720:force_original_aspect_ratio=1,pad=1280:720:(ow-iw)/2:(oh-ih)/2[v0]"
# Combines strings created above and runs ffmpeg command
ffmpeg $input_files \
-filter_complex "${filter}; ${overlay_str}" \
-map "[v0]" -r 25 output.mp4