I want to generate a slideshow video that is composed of 1–n input images. Each input image is rendered in the foreground and simultaneously as a blurred background, for a few seconds. The next image will be placed on top of the previous image, and the background changes. Each image should fade in. The background should crossfade.
I've got this working, and the script looks like this:
#!/usr/bin/env bash
ffmpeg \
-y \
-hide_banner \
-f lavfi -i color=black:r=10:s=894x494:d=24 \
-loop 1 -framerate 10 -i images/trees.jpg \
-loop 1 -framerate 10 -i images/bridge.jpg \
-loop 1 -framerate 10 -i images/river.jpg \
-loop 1 -framerate 10 -i images/woman.jpg \
-filter_complex "
[1:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,boxblur=luma_radius=25:chroma_radius=25:luma_power=1[imageBg1];
[2:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,boxblur=luma_radius=25:chroma_radius=25:luma_power=1[imageBg2];
[3:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,boxblur=luma_radius=25:chroma_radius=25:luma_power=1[imageBg3];
[4:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,boxblur=luma_radius=25:chroma_radius=25:luma_power=1[imageBg4];
[imageBg1][imageBg2]xfade=transition=fade:duration=1:offset=6[imageBgFade1];
[imageBgFade1][imageBg3]xfade=transition=fade:duration=1:offset=12[imageBgFade2];
[imageBgFade2][imageBg4]xfade=transition=fade:duration=1:offset=18[imageBgFade3];
[1:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=670.5:370.5:force_original_aspect_ratio=decrease,pad=width=894:height=494:x=(ow-iw)/2:y=(oh-ih)/2:color=#00000000,fade=in:st=0:d=1:alpha=1,rotate=0.03490658503988659:c=none[image1];
[2:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=670.5:370.5:force_original_aspect_ratio=decrease,pad=width=894:height=494:x=(ow-iw)/2:y=(oh-ih)/2:color=#00000000,fade=in:st=6:d=1:alpha=1,rotate=-0.017453292519943295:c=none[image2];
[3:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=670.5:370.5:force_original_aspect_ratio=decrease,pad=width=894:height=494:x=(ow-iw)/2:y=(oh-ih)/2:color=#00000000,fade=in:st=12:d=1:alpha=1,rotate=0.017453292519943295:c=none[image3];
[4:v]setpts=PTS-STARTPTS,trim=duration=24,settb=AVTB,format=yuva444p,scale=670.5:370.5:force_original_aspect_ratio=decrease,pad=width=894:height=494:x=(ow-iw)/2:y=(oh-ih)/2:color=#00000000,fade=in:st=18:d=1:alpha=1,rotate=0:c=none[image4];
[imageBgFade3][image1]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2:shortest=1:enable='between(t,0,24)'[imageFg1];
[imageFg1][image2]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2:shortest=1:enable='between(t,6,24)'[imageFg2];
[imageFg2][image3]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2:shortest=1:enable='between(t,12,24)'[imageFg3];
[imageFg3][image4]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2:shortest=1:enable='between(t,18,24)'[imageFg4];
[imageFg4]fps=fps=30,format=yuv420p[finalVideo]" \
-map "[finalVideo]" \
-t 24 \
-c:v libx264 \
-preset ultrafast \
-crf 28 \
output.mp4
I am setting up a canvas of a predetermined size, and a rendering framerate of 10 FPS. Here I can achieve a speed of ~2.7⨉. With 30 FPS, the speed drops to 0.9⨉ (which is, understandably, 3⨉ less).
For testing, the images are here. The output video is here.
The problem is that the complexity of the script (i.e., the encoding speed) increases with the number of inputs. The background is not the problem; using xfade
means only one image is shown at a particular time. However, the foreground has to perform the overlay calculations for every image, with up to n overlays. Also, the blurring is done for each frame of the image.
I am aware of the fact that even the ffmpeg manual says:
You can chain together more overlays but you should test the efficiency of such approach.
I cannot think of any other way to improve the performance here. Reducing the FPS could work, since everything is static, except that the fades — they will not look smooth anymore.
Any ideas?