Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to scroll an image vertically using ffmpeg and detect the end-of-image (EOI) at same time?

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.

like image 501
Roel Van de Paar Avatar asked Jan 27 '23 06:01

Roel Van de Paar


2 Answers

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.

like image 146
Gyan Avatar answered Apr 08 '23 13:04

Gyan


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
like image 21
Roel Van de Paar Avatar answered Apr 08 '23 14:04

Roel Van de Paar