I need to scroll an image vertically, from the top of the image to the bottom of the image, and then stop creating the output video as soon as the last bottom bit of the image scrolls off the top of the screen.
To do this in one command, use
ffmpeg -f lavfi -i color=s=1920x1080 -loop 1 -t 0.08 -i "input.png" -filter_complex "[1:v]scale=1920:-2,setpts=if(eq(N,0),0,1+1/0.02/TB),fps=25[fg]; [0:v][fg]overlay=y=-'t*h*0.02':eof_action=endall[v]" -map "[v]" output.mp4
Note, that in some shells (e.g. Bash) commas need to be escaped:
ffmpeg -f lavfi -i color=s=1920x1080 -loop 1 -t 0.08 -i "input.png" -filter_complex "[1:v]scale=1920:-2,setpts=if(eq(N\,0)\,0\,1+1/0.02/TB),fps=25[fg]; [0:v][fg]overlay=y=-'t*h*0.02':eof_action=endall[v]" -map "[v]" output.mp4
The -t
is added for the image so that we have a stream with 2 frames. (25 fps x 0.08 = 2
). The setpts sets the timestamp for the 2nd frame to the inverse of the scroll rate, which represents a fraction of the height. The fps filter fiils in the timestamp gaps with cloned frames.
The overlay is told to stop when the image input has finished.
Here is a solution I found;
ffmpeg -f lavfi -i color=s=1920x1080 -loop 1 -i "input.png" -filter_complex "[1:v]scale=1920:-2[fg]; [0:v][fg]overlay=y=-'t*h*0.02'[v]" -map "[v]" -t 00:03:00 output.mp4
Note that the scroll rate is 0.02. Set it lower, for example 0.01 to scroll slower, or higher - for example 0.03, to scroll faster.
Note that I passed a maximum time of 3 minutes to the command. This time, regrettably, needs to be larger then any image scroll output could ever take in your particular setup.
For reference, a 1920x7043 pixels image takes 49.88 seconds. You can get the height of an image programmatically using;
file input.png | sed 's|.*1920 x \([0-9]\+\).*|\1|'
output: 7043
If someone has a better way of "detecting the end of the image scroll - i.e. the last line/bottom of the image scrolling off the top of the screen" and the ability to scale the time/duration based on that - then that would be very handy.
For the moment this is the best solution I have; scan the output of the last ffmpeg command above for something like;
[blackdetect @ 0x559298835480] black_start:49.88
For example, using this command;
ffmpeg -i output.mp4 -vf blackdetect=d=0.1:pix_th=.1 -f rawvideo -y /dev/null 2>&1 | grep -o "black_start:[\.0-9]\+ "
output: black_start:49.88
And crop accordingly;
ffmpeg -i output.mp4 -t 49.88 -c copy finaloutput.mp4
vlc finaloutput.mp4 # Assuming you have vlc installed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With