I'd like to apply a Zoompan effect but instead of zoom in or zoom out, I'd like to mix both of them: the zoom will start with zoom in, and, after some period of time, the zoom continue with zoom out, and so on, alternatively.

While I'm thinking how to archieve this, has someone some tips?

Thanks !

2 Answers 2


You need to use state e.g.

ffmpeg -i src.png
 -vf zoompan=d=300:z='if(gte(zoom,2)+eq(ld(1),1)*gt(zoom,1),zoom-0.04*st(1,1),zoom+0.04+0*st(1,0))'

This expression zooms from zoom=1 to zoom=2 in steps of 0.04. Remember, zoom is initialized to 1. The above will create 6 loops.

In st(store) and ld(load) functions, the first argument is variable id (0 to 9), and the second is the value.

  • good, it works, but I don't understand very well what does it do! What if I'd like to start with zoom out and then zoom in? Thanks!
    – GFCoder977
    Mar 27, 2018 at 13:32
  • 1
    Actually, I use pzoom for z evaluazion min(pzoom+0.0015,1.5), and before zoompan I scale the image with scale=iw*10:ih*10. I'm trying to apply your formula, but it does not work. How should I change to use pzoom?
    – GFCoder977
    Mar 28, 2018 at 9:21
  • Sorry, it works well; I have updated my ffmpeg version with 3.4.2. Thanks!!!
    – GFCoder977
    Mar 28, 2018 at 11:24
  • @Gyan How can this effect be done in videos, with it zooming into the center? Dec 14, 2020 at 22:41
  • 1
    d=1 and use pzoom in place of zoom
    – Gyan
    Dec 15, 2020 at 4:55

Based on Gyan's answer, here are more details.

The following creates a video from an image and an mp3 with an infinite zoom-in-out on the image:

ffmpeg -loop 1 -i img.png  -i adio.mp3 -vf "[0:v]scale=7680x4320,zoompan=z='if(gte(zoom,1.5)+eq(ld(1),1)*gt(zoom,1),zoom-0.00005*st(1,1),zoom+0.00005+st(1,0))':d=20000" -c:a copy -c:v libx264 -shortest out3.mp4

[0:v]scale=7680x4320 upscales 4 times the original 1920x1080 image for a smooth transition.

d=20000 specifies the duration of the zoom-in-out. In this case, I perform a zoom from 1 to 1.5 with increments or decrements of 0.00005. That's (1.5-1) / 0.00005 steps for the zoom, which means I need two times this for the zoom + dezoom, which is 10'000*2 = 20'000.

if(gte(zoom,1.5)+eq(ld(1),1)*gt(zoom,1),zoom-0.00005*st(1,1),zoom+0.00005+st(1,0)) can be translated to the following pseudo-code:

// '||' corresponds to a `+` and '&&' to a '*' 
if zoom >= 1.5 || (isDezooming && zoom > 1) {
  isDezooming = true // corresponds to '*st(1,1)'
} else {
  isDezooming = false // corresponds to '+st(1,0)'

where isDezooming corresponds to the variable 1 handled with the ld(1) and st(1,0) instructions. Here is the full list of instruction.

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.