0

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?

1 Answer 1

1

The main cause of slowdown is using boxblur filter on static images that are animated.

Use gblur filter instead, it is generally faster. Also use loop filter to animate static images after heavy processing. About chaining bunch of overlays at end, that can become quite problematic for more images, perhaps using feedback filter from latest ffmpeg version could help, that is still open question.

    ffmpeg -f lavfi -i color=black:r=10:s=894x494:d=24 -framerate 30 -i images/trees.jpg -framerate 30 -i images/bridge.jpg  -framerate 30 -i images/river.jpg   -framerate 30 -i images/woman.jpg   -filter_complex "
    [1:v]format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,gblur=7,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB[imageBg1];
    [2:v]format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,gblur=7,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB[imageBg2];
    [3:v]format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,gblur=7,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB[imageBg3];
    [4:v]format=yuva444p,scale=894:494:force_original_aspect_ratio=increase,crop=894:494,gblur=7,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB[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]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,rotate=0.03490658503988659:c=none,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB,fade=in:st=0:d=1:alpha=1[image1];
    [2:v]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,rotate=-0.017453292519943295:c=none,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB,fade=in:st=6:d=1:alpha=1[image2];
    [3:v]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,rotate=0.017453292519943295:c=none,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB,fade=in:st=12:d=1:alpha=1[image3];
    [4:v]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,rotate=0:c=none,loop=800:1:0,trim=duration=24,setpts=PTS-STARTPTS,settb=AVTB,fade=in:st=18:d=1:alpha=1[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)'[finalVideo]"   -map "[finalVideo]" -c:v rawvideo x.nut
4
  • Thanks for the suggestions, but when I use the gblur filter and looping, the speed is significantly reduced (3.3 seconds vs 2.3 seconds for a short example). The biggest contributor seems to be the gblur filter (3.2 seconds).
    – slhck
    Commented Apr 25, 2022 at 6:52
  • Here, your script takes 41 seconds, and my script takes 7 seconds with gblur and 8 seconds with boxblur. fps for your script is 17 and its 89/86 for my script. So check your usage and logic of my script.
    – durandal
    Commented Apr 25, 2022 at 8:11
  • Indeed it works quite well, thanks. I was only referring to the boxblur/gblur difference in my earlier comment. I was able to achieve a 3x speedup now (there are other effects which limit the benefits of your method). What are you implying with the feedback filter?
    – slhck
    Commented Apr 25, 2022 at 9:48
  • Accepted for now, thanks for your pointers regarding processing of static images. I would still be curious how the feedback filter could help here?
    – slhck
    Commented May 4, 2022 at 15:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.