FFMPEG zoom-pan multiple images - ffmpeg

I am trying to stitch multiple images with some zoom-pan happening on the images to create a video.
Command:-
ffmpeg -f lavfi -r 30 -t 10 -i \
color=#000000:1920x1080 \
-f lavfi \
-r 30 -t 10 \
-i aevalsrc=0 \
-i "image-1.png" \
-i "image-2.png" \
-y -filter_complex \
"[0:v]fifo[bg];\
[2:v]setpts=PTS-STARTPTS+0/TB,scale=4455:2506:force_original_aspect_ratio=decrease,zoompan=z='min(zoom+0.0015,2.5)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=150:fps='30':s='1920x1080'[v2];\
[bg][v2]overlay=0:0:enable='between(t,0, 5)'[bg];\
[3:v]setpts=PTS-STARTPTS+5.07/TB,scale=3840:2160:force_original_aspect_ratio=decrease,zoompan=z='min(zoom+0.0015,2.5)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=150:fps='30':s='1920x1080'[v3];\
[bg][v3]overlay=0:0:enable='between(t,5, 10)'[bg];\
[1:a]amix=inputs=1:duration=first:dropout_transition=0" \
-map "[bg]" -vcodec "libx264" -preset "veryfast" -crf "15" "output.mp4"
The output is not as expected, it only zooms only on the first image, the second image is just static.
FFMPEG version - 4.1

Use
ffmpeg -f lavfi -i color=#000000:1920x1080:r=30:d=10 \
-f lavfi -t 10 -i anullsrc \
-i "image-1.png" \
-i "image-2.png" \
-filter_complex \
"[2:v]scale=4455:2506:force_original_aspect_ratio=decrease,zoompan=z='min(zoom+0.0015,2.5)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=150:fps=30:s='1920x1080'[v2];\
[bg][v2]overlay=0:0:enable='between(t,0,5)'[bg];\
[3:v]scale=3840:2160:force_original_aspect_ratio=decrease,zoompan=z='min(zoom+0.0015,2.5)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=150:fps=30:s='1920x1080',setpts=PTS+5/TB[v3];\
[bg][v3]overlay=0:0:enable='between(t,5,10)'[bg];\
-map "[bg]" -map 1:a -vcodec libx264 -preset veryfast -crf 15 -y "output.mp4"
For lavfi sources, it's best to set frame rate and duration where applicable within the filter.
Since you're not looping the images, -t won't have any effect. Since zoompan will set fps in its output, you can skip input rate setting. And since it's a single image, setpts before zoompan has no relevance. It should be set only on the zoompan whose timestamps need to be shifted.
Since you've only one audio, no point sending it to amix - there's nothing to mix with! Just map it directly.

Related

Why does the mp4 from ffmpeg freeze during the last 3 seconds?

I'm trying to generate a perfectly looping mp4 from three inputs:
A background png image
An image sequence of transparent png images with the number of particles increasing
Another image sequence of transparent png images with the number of particles decreasing
I'm currently trying to achieve this with two commands (I have to use 'overlay' twice). The problem is that after the second command the video (test2.mp4) freezes for the last 3 seconds. Why does it happen? ARe there any other commands I could try to use?
First command:
ffmpeg -framerate 30 \
-pattern_type glob -i 'images/increase/*.png' \
-framerate 30 \
-i screens/Background.png \
-i audio/50-White-Noise-10min.mp3 \
-filter_complex "[1:v][0:v] overlay" \
-preset slow -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p test.mp4
Second command:
ffmpeg -framerate 30 \
-pattern_type glob -i 'images/decrease/*.png' \
-i test.mp4 \
-filter_complex "[1:v][0:v] overlay" \
-preset slow -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p test2.mp4
The solution was to do what Rajib commented: chain the overlay filters and do it all in one command:
ffmpeg -framerate 30 \
-i screens/Background.png \
-framerate 30 \
-pattern_type glob -i 'images/increase/*.png' \
-framerate 30 \
-pattern_type glob -i 'images/decrease/*.png' \
-i audio/50-White-Noise-10min.mp3 \
-filter_complex "[0][1] overlay[out],[out][2] overlay" \
-c:a copy -shortest -c:v libx264 -pix_fmt yuvj420p loop.mp4

How do I compose three overlapping videos w/audio in ffmpeg?

I have three videos: let's call them intro, recording and outro. My ultimate goal is to stitch them together like so:
Both intro and outro have alpha (prores 4444) and a "wipe" to transition, so when overlaying, they must be on top of the recording. The recording is h264, and ultimately I'm encoding out for youtube with these recommended settings.
I've figured out how to make the thing work correctly for intro + recording:
$ ffmpeg \
-i intro.mov \
-i recording.mp4 \
-filter_complex \
"[1:v]tpad=start_duration=10:start_mode=add:color=black[rv]; \
[1:a]adelay=delays=10s:all=1[ra]; \
[rv][0:v]overlay[v];[0:a][ra]amix[a]" \
-map "[a]" -map "[v]" \
-movflags faststart -c:v libx264 -profile:v high -bf 2 -g 30 -crf 18 -pix_fmt yuv420p \
out.mp4 -y
However I can't use the tpad trick for the outro because it would render black frames over everything.
I've tried various iterations with setpts/asetpts as well as passing -itsoffset for the input, but haven't come up with a solution that works correctly for both video and audio. This tries to start the outro at 16 seconds into the recording (10s start + 16s of recording is how I got to setpts=PTS+26/TB). del, but doesn't work correctly, I get both intro and outro audio from the first frame, and the recording audio cuts out when the outro overlay begins:
$ ffmpeg \
-i intro.mov \
-i recording.mp4 \
-i outro.mov \
-filter_complex \
"[1:v]tpad=start_duration=10:start_mode=add:color=black[rv]; \
[1:a]adelay=delays=10s:all=1[ra]; \
[2:v]setpts=PTS+26/TB[outv]; \
[2:a]asetpts=PTS+26/TB[outa]; \
[rv][0:v]overlay[v4]; \
[0:a][ra]amix[a4]; \
[v4][outv]overlay[v]; \
[a4][outa]amix[a]" \
-map "[a]" -map "[v]" \
-movflags faststart -c:v libx264 -profile:v high -bf 2 -g 30 -crf 18 -pix_fmt yuv420p \
out.mp4 -y
I think the right solution lies in the direction of using setpts correctly but I haven't been able to wrap my brain fully around it. Or, maybe I'm making life complicated and there's an easier approach?
In the nice-to-have realm, I'd love to be able to specify the start of the outro relative to the end of the recording. I will be doing this to a bunch of recordings of varying lengths. It would be nice to have one command to invoke on everything rather than figuring out a specific timestamp for each one.
Thank you!
Use adelay for all audio adjustments. Perform all mixing in a single amix.
Set the outro overlay to start only at the correct timestamps.
Use
$ ffmpeg \
-i intro.mov \
-i recording.mp4 \
-i outro.mov \
-filter_complex \
"[1:v]tpad=start_duration=10:start_mode=add:color=black[mainv]; \
[1:a]adelay=delays=10s:all=1[maina]; \
[2:v]setpts=PTS+26/TB[outv]; \
[2:a]adelay=delays=26s:all=1[outa]; \
[mainv][0:v]overlay=eof_action=pass[previd]; \
[previd][outv]overlay=enable='gte(t,26)'[v]; \
[maina][0:a][outa]amix=inputs=3[a]; \
-map "[v]" -map "[a]" \
-c:v libx264 -profile:v high -bf 2 -g 30 -crf 18 -pix_fmt yuv420p \
-movflags +faststart \
out.mp4 -y

FFmpeg add a text to last image only

I managed to create a video from set of non-sequential images and attached an audio to it. Also I added a "Copyright" text on top right hand corner so that the text appears throughout the video. However, I would like that text to appear only on the last image. How should I change my code below to address this?
ffmpeg \
-thread_queue_size 512 -f image2 -pattern_type glob -framerate 1/3 \
-i '*.jpg' \
-i 'audio.mp3' \
-c:a aac -c:v libx264 \
-vf scale=640:480, format=yuv420p, drawtext="text='Copyright':fontcolor=white:box=1:boxcolor=black#0.5:boxborderw=5:x=w-tw-5:y=5" \
-preset medium \
video.mp4
Isolate the last image from the glob and then concat it:
ffmpeg \
-pattern_type glob -framerate 1/3 -i '*.jpg' -framerate 1/3 -loop 1 -t 5 -i last/img.jpg -i audio.mp3 \
-filter_complex \
"[0:v]scale=640:480,setsar=1[v0]; \
[1:v]scale=640:480,setsar=1,drawtext=text='Copyright':fontcolor=white:box=1:boxcolor=black#0.5:boxborderw=5:x=w-tw-5:y=5[v1]; \
[v0][v1]concat=n=2:v=1:a=0,fps=25,format=yuv420p[v]" \
-map "[v]" -map 2:a -c:v libx264 -c:a aac -shortest -movflags +faststart video.mp4

Combining multiple image files into a video while using filter_complex to apply a watermark

I'm trying to combine two ffmpeg operations into a single one.
Currently I have two sets of ffmpeg commands that first generate a video from existing images, then runs that video through ffmpeg again to apply a watermark.
I'd like to see if its possible to combine these into a single operation.
# Create the source video
ffmpeg -y \
-framerate 1/1 \
-i layer-%d.png \
-r 30 -vcodec libx264 -preset ultrafast -crf 23 -pix_fmt yuv420p \
output.mp4
# Apply the watermark and render the final output
ffmpeg -y \
-i output.mp4 \
-i logo.png \
-filter_complex "[1:v][0:v]scale2ref=40:40[a][b];[b][a]overlay=(80):(main_h-200-80)" \
final.mp4
Use
ffmpeg -y \
-framerate 1/1 -i layer-%d.png \
-i logo.png \
-filter_complex "[0:v]fps=30[img];
[1:v][img]scale2ref=40:40[a][b];[b][a]overlay=(80):(main_h-200-80)" \
final.mp4
(The use of scale2ref doesn't make sense since you're scaling to a fixed size).

Add different filter parameters to multiple images

I have this command to generate a slideshow with zoompan from a list of images, but it applies the same zoompan to all pictures.
ffmpeg -r 1/5 -i img%03d.jpg -i 1.mp3 -c:a aac -c:v libx264 -r 25 -pix_fmt yuv420p -vf "zoompan=z='if(lte(zoom,1.0),1.2,max(1.001,zoom-0.0015))':d=100" out.mp4
How can I get it to have different zoompan parameters for each image?
Input each image individually and provide a separate zoompan per image. Then concatenate with the concat filter.
ffmpeg \
-i img001.jpg \
-i img002.jpg \
-i img003.jpg \
-i audio.mp3 \
-filter_complex \
"[0:v]zoompan[v0]; \
[1:v]zoompan[v1]; \
[2:v]zoompan[v2]; \
[v0][v1][v2]concat=n=3:v=1:a=0,format=yuv420p[v]" \
-map "[v]" -map 3:a -shortest out.mp4
You'll need to adapt this example to use whatever zoompan values you want.

Resources