<p>The main cause of slowdown is using boxblur filter on static images that are animated.</p>
<p>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.</p>
<pre><code>    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 &quot;
    [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]&quot;   -map &quot;[finalVideo]&quot; -c:v rawvideo x.nut
</code></pre>

CC BY-SA 4.0
2022-04-25T06:52:22.270Z
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
CC BY-SA 4.0
2022-04-25T08:11:34.330Z
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
CC BY-SA 4.0
2022-04-25T09:48:41.240Z
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
CC BY-SA 4.0
2022-05-04T15:29:55.620Z
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
CC BY-SA 4.0
2022-04-22T16:29:23.450Z
2022-04-22T16:29:23.450Z
durandal
<p>I want to generate a slideshow video that is composed of 1–<em>n</em> 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.</p>
<p>I've got this working, and the script looks like this:</p>
<pre class="lang-bash prettyprint-override"><code>#!/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 &quot;
    [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]&quot; \
  -map &quot;[finalVideo]&quot; \
  -t 24 \
  -c:v libx264 \
  -preset ultrafast \
  -crf 28 \
  output.mp4
</code></pre>
<p>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).</p>
<p>For testing, the images are <a href="https://storage.googleapis.com/aveq-storage/examples/video.stackexchange.com-ffmpeg-slideshow-complex-filter/images.zip" rel="nofollow noreferrer">here</a>. The output video is <a href="https://storage.googleapis.com/aveq-storage/examples/video.stackexchange.com-ffmpeg-slideshow-complex-filter/output.mp4" rel="nofollow noreferrer">here</a>.</p>
<p>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 <code>xfade</code> 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 <em>n</em> overlays. Also, the blurring is done for each frame of the image.</p>
<p>I am aware of the fact that even the ffmpeg manual says:</p>
<blockquote>
<p>You can chain together more overlays but you should test the efficiency of such approach.</p>
</blockquote>
<p>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.</p>
<p>Any ideas?</p>

<ffmpeg>
Complex filter performance deteriorates with effects on images and multiple overlays
slhck
# Complex filter performance deteriorates with effects on images and multiple overlays

(Asked by: username_0 on 2022-04-21)

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?

**Tags:** ffmpeg


---

## 1 answers

### Answer by username_1 on 2022-04-22. Score: 1 | Accepted answer

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

> **Comments:**
> **username_0**: 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).  
> **username_1**: 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.  
> **username_0**: 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?  
> **username_0**: Accepted for now, thanks for your pointers regarding processing of static images. I would still be curious how the feedback filter could help here?  

---

