Presenting more than 2 videos using FFmpeg [duplicate] - ffmpeg

This question already has answers here:
Vertically or horizontally stack (mosaic) several videos using ffmpeg? [closed]
(3 answers)
Closed 5 years ago.
I found this answer for combining 2 videos using Ffmpeg
ffmpeg.exe -i LeftInput.mp4 -vf "[in] scale=iw/2:ih/2, pad=2*iw:ih [left];
movie=RightInput.mp4, scale=iw/3:ih/3, fade=out:300:30:alpha=1 [right];
[left][right] overlay=main_w/2:0 [out]" -b:v 768k Output.mp4
Is there a way to combine more than 2?
I tried adding [bottom] and [upper] but I'm failing to understand how the overlay works and where do I put more videos.

Use the FFmpeg hstack and vstack filters:
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex \
"[0:v][1:v]hstack[top]; \
[2:v][3:v]hstack[bottom]; \
[top][bottom]vstack" \
output
If you want to combine the audio add the amerge filter:
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex \
"[0:v][1:v]hstack[top]; \
[2:v][3:v]hstack[bottom]; \
[top][bottom]vstack[v]; \
[0:a][1:a][2:a][3:a]amerge=inputs=4[a]" \
-map "[v]" -map "[a]" -ac 2 output

Related

FFmpeg - Create Thumbnail Grid from Videos [duplicate]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 2 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I have two videos of the same exact length, and I would like to use ffmpeg to stack them into one video file.
How can I do this?
Use the vstack (vertical), hstack (horizontal), or xstack (custom layout) filters. It is easier and faster than other methods.
Combine/stack two videos or images
Vertical
Using the vstack filter.
ffmpeg -i input0 -i input1 -filter_complex vstack=inputs=2 output
Videos must have the same width.
Horizontal
Using the hstack filter.
ffmpeg -i input0 -i input1 -filter_complex hstack=inputs=2 output
Videos must have the same height.
With a border
Using the pad filter. This examples creates a 5px black border between the two sides.
ffmpeg -i input0 -i input1 -filter_complex "[0]pad=iw+5:color=black[left];[left][1]hstack=inputs=2" output
With audio
Downmix and use original channel placements
Add the amerge filter to combine the audio channels from both inputs:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output
This assumes each input contains a stereo audio stream.
-ac 2 is included to downmix to stereo in case both inputs contain multi-channel audio. For example, if both inputs are stereo, you would get a 4-channel output audio stream instead of stereo if you omit -ac 2.
Put all audio from each input into separate channels
Use amerge (or amix) and pan filters:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2,pan=stereo|c0<c0+c1|c1<c2+c3[a]" -map "[v]" -map "[a]" output
This assumes each input contains a stereo audio stream.
Using audio from one particular input
This example will use the audio from input1:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v]" -map "[v]" -map 1:a output
Adding silent audio / If one input does not have audio
If you mix inputs that have audio and inputs that do not have audio then amerge will fail because each input needs audio. You can add silent audio with the anullsrc filter to prevent this:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];anullsrc[silent];[0:a][silent]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output.mp4
3 videos or images
ffmpeg -i input0 -i input1 -i input2 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" output
If you want vertical use vstack instead of hstack.
2x2 grid
Using xstack
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v][2:v][3:v]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]" -map "[v]" output
Using hstack and vstack
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v]hstack=inputs=2[top];[2:v][3:v]hstack=inputs=2[bottom];[top][bottom]vstack=inputs=2[v]" -map "[v]" output
This syntax is easier to understand, but less efficient than using xstack as shown above.
2x2 grid with text
Using the drawtext filter:
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex
"[0]drawtext=text='vid0':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v0];
[1]drawtext=text='vid1':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v1];
[2]drawtext=text='vid2':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v2];
[3]drawtext=text='vid3':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v3];
[v0][v1][v2][v3]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]"
-map "[v]" output
4x4
Use the xstack filter. Example for a total of 16 videos:
ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v][1:v][2:v][3:v][4:v][5:v][6:v][7:v][8:v][9:v][10:v][11:v][12:v][13:v][14:v][15:v]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4
If you need to scale the inputs first:
ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v]scale=iw/4:-1[v0];[1:v]scale=iw/4:-1[v1];[2:v]scale=iw/4:-1[v2];[3:v]scale=iw/4:-1[v3];[4:v]scale=iw/4:-1[v4];[5:v]scale=iw/4:-1[v5];[6:v]scale=iw/4:-1[v6];[7:v]scale=iw/4:-1[v7];[8:v]scale=iw/4:-1[v8];[9:v]scale=iw/4:-1[v9];[10:v]scale=iw/4:-1[v10];[11:v]scale=iw/4:-1[v11];[12:v]scale=iw/4:-1[v12];[13:v]scale=iw/4:-1[v13];[14:v]scale=iw/4:-1[v14];[15:v]scale=iw/4:-1[v15];[v0][v1][v2][v3][v4][v5][v6][v7][v8][v9][v10][v11][v12][v13][v14][v15]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4
Resize/scale an input
Since both videos need to have the same with for vstack, and the same height for hstack, you may need to scale one of the other videos to match the other:
Simple scale filter example to set width of input0 to 640 and automatically set height while preserving the aspect ratio:
ffmpeg -i input0 -i input2 -filter_complex "[0:v]scale=640:-1[v0];[v0][1:v]vstack=inputs=2" output
For a more advanced method to fit any size video into a specific size while preserving aspect ratio see Resizing videos with ffmpeg to fit into static sized player.
You can also use the scale2ref filter to automatically resize one video to match the dimensions of the other.
Delaying/pausing videos
This example will play the top left video while pausing the others. Once the top left video ends the top right video will play and so on.
Use the tpad, adelay, xstack, and amix filters:
ffmpeg -i top-left.mp4 -i top-right.mp4 -i bottom-left.mp4 -i bottom-right.mp4 -filter_complex "[1]tpad=start_mode=clone:start_duration=5[tr];[2]tpad=start_mode=clone:start_duration=10[bl];[3]tpad=start_mode=clone:start_duration=15[br];[0][tr][bl][br]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v];[1:a]adelay=5s:all=true[a1];[2:a]adelay=10s:all=true[a2];[3:a]adelay=15s:all=true[a3];[0:a][a1][a2][a3]amix=inputs=4[a]" -map "[v]" -map "[a]" output.mp4
This example assumes each input is 5 seconds duration. Adjust start_duration and adelay values as needed.
This command requires FFmpeg 4.3 or newer.
If you don't like the complexity of xstack you can use several hstack/vstack instead as shown in Example 4: 2x2 grid.
See this answer to this question for a newer, simpler way to do this.
Old version:
You should be able to do this using the pad, movie and overlay filters in FFmpeg. The command will look something like this:
ffmpeg -i top.mov -vf 'pad=iw:2*ih [top]; movie=bottom.mov [bottom]; \
[top][bottom] overlay=0:main_h/2' stacked.mov
First the movie that should be on top is padded to twice its height. Then the bottom movie is loaded. Then the bottom movie is overlaid on the padded top movie at an offset of half the padded movie's height.
For 2 videos:
ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex hstack out.mp4
For more videos(3 in this example):
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex hstack=3 out.mp4

How to combine multiple images horizontally and vertically using ffmpeg [duplicate]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 2 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I have two videos of the same exact length, and I would like to use ffmpeg to stack them into one video file.
How can I do this?
Use the vstack (vertical), hstack (horizontal), or xstack (custom layout) filters. It is easier and faster than other methods.
Combine/stack two videos or images
Vertical
Using the vstack filter.
ffmpeg -i input0 -i input1 -filter_complex vstack=inputs=2 output
Videos must have the same width.
Horizontal
Using the hstack filter.
ffmpeg -i input0 -i input1 -filter_complex hstack=inputs=2 output
Videos must have the same height.
With a border
Using the pad filter. This examples creates a 5px black border between the two sides.
ffmpeg -i input0 -i input1 -filter_complex "[0]pad=iw+5:color=black[left];[left][1]hstack=inputs=2" output
With audio
Downmix and use original channel placements
Add the amerge filter to combine the audio channels from both inputs:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output
This assumes each input contains a stereo audio stream.
-ac 2 is included to downmix to stereo in case both inputs contain multi-channel audio. For example, if both inputs are stereo, you would get a 4-channel output audio stream instead of stereo if you omit -ac 2.
Put all audio from each input into separate channels
Use amerge (or amix) and pan filters:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2,pan=stereo|c0<c0+c1|c1<c2+c3[a]" -map "[v]" -map "[a]" output
This assumes each input contains a stereo audio stream.
Using audio from one particular input
This example will use the audio from input1:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v]" -map "[v]" -map 1:a output
Adding silent audio / If one input does not have audio
If you mix inputs that have audio and inputs that do not have audio then amerge will fail because each input needs audio. You can add silent audio with the anullsrc filter to prevent this:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];anullsrc[silent];[0:a][silent]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output.mp4
3 videos or images
ffmpeg -i input0 -i input1 -i input2 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" output
If you want vertical use vstack instead of hstack.
2x2 grid
Using xstack
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v][2:v][3:v]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]" -map "[v]" output
Using hstack and vstack
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v]hstack=inputs=2[top];[2:v][3:v]hstack=inputs=2[bottom];[top][bottom]vstack=inputs=2[v]" -map "[v]" output
This syntax is easier to understand, but less efficient than using xstack as shown above.
2x2 grid with text
Using the drawtext filter:
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex
"[0]drawtext=text='vid0':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v0];
[1]drawtext=text='vid1':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v1];
[2]drawtext=text='vid2':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v2];
[3]drawtext=text='vid3':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v3];
[v0][v1][v2][v3]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]"
-map "[v]" output
4x4
Use the xstack filter. Example for a total of 16 videos:
ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v][1:v][2:v][3:v][4:v][5:v][6:v][7:v][8:v][9:v][10:v][11:v][12:v][13:v][14:v][15:v]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4
If you need to scale the inputs first:
ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v]scale=iw/4:-1[v0];[1:v]scale=iw/4:-1[v1];[2:v]scale=iw/4:-1[v2];[3:v]scale=iw/4:-1[v3];[4:v]scale=iw/4:-1[v4];[5:v]scale=iw/4:-1[v5];[6:v]scale=iw/4:-1[v6];[7:v]scale=iw/4:-1[v7];[8:v]scale=iw/4:-1[v8];[9:v]scale=iw/4:-1[v9];[10:v]scale=iw/4:-1[v10];[11:v]scale=iw/4:-1[v11];[12:v]scale=iw/4:-1[v12];[13:v]scale=iw/4:-1[v13];[14:v]scale=iw/4:-1[v14];[15:v]scale=iw/4:-1[v15];[v0][v1][v2][v3][v4][v5][v6][v7][v8][v9][v10][v11][v12][v13][v14][v15]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4
Resize/scale an input
Since both videos need to have the same with for vstack, and the same height for hstack, you may need to scale one of the other videos to match the other:
Simple scale filter example to set width of input0 to 640 and automatically set height while preserving the aspect ratio:
ffmpeg -i input0 -i input2 -filter_complex "[0:v]scale=640:-1[v0];[v0][1:v]vstack=inputs=2" output
For a more advanced method to fit any size video into a specific size while preserving aspect ratio see Resizing videos with ffmpeg to fit into static sized player.
You can also use the scale2ref filter to automatically resize one video to match the dimensions of the other.
Delaying/pausing videos
This example will play the top left video while pausing the others. Once the top left video ends the top right video will play and so on.
Use the tpad, adelay, xstack, and amix filters:
ffmpeg -i top-left.mp4 -i top-right.mp4 -i bottom-left.mp4 -i bottom-right.mp4 -filter_complex "[1]tpad=start_mode=clone:start_duration=5[tr];[2]tpad=start_mode=clone:start_duration=10[bl];[3]tpad=start_mode=clone:start_duration=15[br];[0][tr][bl][br]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v];[1:a]adelay=5s:all=true[a1];[2:a]adelay=10s:all=true[a2];[3:a]adelay=15s:all=true[a3];[0:a][a1][a2][a3]amix=inputs=4[a]" -map "[v]" -map "[a]" output.mp4
This example assumes each input is 5 seconds duration. Adjust start_duration and adelay values as needed.
This command requires FFmpeg 4.3 or newer.
If you don't like the complexity of xstack you can use several hstack/vstack instead as shown in Example 4: 2x2 grid.
See this answer to this question for a newer, simpler way to do this.
Old version:
You should be able to do this using the pad, movie and overlay filters in FFmpeg. The command will look something like this:
ffmpeg -i top.mov -vf 'pad=iw:2*ih [top]; movie=bottom.mov [bottom]; \
[top][bottom] overlay=0:main_h/2' stacked.mov
First the movie that should be on top is padded to twice its height. Then the bottom movie is loaded. Then the bottom movie is overlaid on the padded top movie at an offset of half the padded movie's height.
For 2 videos:
ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex hstack out.mp4
For more videos(3 in this example):
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex hstack=3 out.mp4

ffmpeg concatenate 3 videos with crossfade [duplicate]

This question already has answers here:
FFmpeg command for crossfading between 5 videos .How to manage setpts=PTS-STARTPTS?
(2 answers)
Closed 3 years ago.
Im trying to join 3 videos together with a crossfade effect.
I can get this working for 2 videos (sourced from stackoverflow but cant find the link):
ffmpeg -y -i part1.mp4 -i part2.mp4 -f lavfi -i color=black:s=1920x1080 -filter_complex \
"[0:v]format=pix_fmts=yuva420p,fade=t=out:st=10:d=1:alpha=1,setpts=PTS-STARTPTS[va0]; \
[1:v]format=pix_fmts=yuva420p,fade=t=in:st=0:d=1:alpha=1,setpts=PTS-STARTPTS+10/TB[va1]; \
[2:v]trim=duration=20[over]; \
[over][va0]overlay[over1]; \
[over1][va1]overlay=format=yuv420[outv]" \
-vcodec libx264 -map [outv] merged.mp4
But cant work out how to make this work for 3 videos.
I don't need any audio. Any ideas?
Cheers,
ffmpeg-concat is the easiest way to accomplish what you want and allows you to use a bunch of sexy OpenGL transitions, with the default being crossfade.
ffmpeg-concat 0.mp4 1.mp4 2.mp4 -o out.mp4
ffmpeg-gl-transition is a more complicated custom ffmpeg filter which allows you to use GLSL to smoothly transition between two video streams. This filter is significantly easier to use and customize than the alternatives listed here.
./ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "gltransition=duration=4:offset=1.5" out.mp4
ok so im not sure if this is the best way to do this but i got it working:
ffmpeg -y -i part1.mp4 -i part2.mp4 -i part3.mp4 -f lavfi -i color=black:s=1920x1080 -filter_complex \
"[0:v]format=pix_fmts=yuva420p,fade=t=out:st=10:d=1:alpha=1,setpts=PTS-STARTPTS[v0]; \
[1:v]format=pix_fmts=yuva420p,fade=t=in:st=0:d=1:alpha=1,fade=t=out:st=10:d=1:alpha=1,setpts=PTS-STARTPTS+10/TB[v1]; \
[2:v]format=pix_fmts=yuva420p,fade=t=in:st=0:d=1:alpha=1,fade=t=out:st=10:d=1:alpha=1,setpts=PTS-STARTPTS+20/TB[v2]; \
[3:v]trim=duration=30[over]; \
[over][v0]overlay[over1]; \
[over1][v1]overlay[over2]; \
[over2][v2]overlay=format=yuv420[outv]" \
-vcodec libx264 -map [outv] merge.mp4

Run FFMPEG multiple overlay commands in one command

I'm using ffmpeg to do more operation on one video
the operation that i want to do is add many text in difference time, audio and image.
i can do all of them but not in one command, Do all separately
any suggestions to do multiple text , overlay image and audio in one command
Thanks
To achieve the commands provided in comments in one execution, use
ffmpeg –i input.mp4 –i img.png -i audio.mp4 -filter_complex \
"[0:v][1:v]overlay=15 :15:enable=between(t,10,20), \
drawtext=enable='between(t,12,3*60)': \
fontfile=/usr/share/fonts/truetype/freefon‌​t/FreeSerif.ttf: text='Test Text'[v]" \
-map "[v]" -map 2:a -acodec copy -qscale 4 -vcodec mpeg4 outvideo.mp4
To add more drawtext filters, insert them after the first drawtext filter e.g.
ffmpeg –i input.mp4 –i img.png -i audio.mp4 -filter_complex \
"[0:v][1:v]overlay=15 :15:enable=between(t,10,20), \
drawtext=enable='between(t,12,3*60)': \
fontfile=/usr/share/fonts/truetype/freefon‌​t/FreeSerif.ttf: text='Test Text', \
drawtext=enable='between(t,12,3*60)': \
fontfile=/usr/share/fonts/truetype/freefon‌​t/FreeSerif.ttf: text='Text2'[v]" \
-map "[v]" -map 2:a -acodec copy -qscale 4 -vcodec mpeg4 outvideo.mp4

Merge MP4 files with ffmpeg [duplicate]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 2 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I have two videos of the same exact length, and I would like to use ffmpeg to stack them into one video file.
How can I do this?
Use the vstack (vertical), hstack (horizontal), or xstack (custom layout) filters. It is easier and faster than other methods.
Combine/stack two videos or images
Vertical
Using the vstack filter.
ffmpeg -i input0 -i input1 -filter_complex vstack=inputs=2 output
Videos must have the same width.
Horizontal
Using the hstack filter.
ffmpeg -i input0 -i input1 -filter_complex hstack=inputs=2 output
Videos must have the same height.
With a border
Using the pad filter. This examples creates a 5px black border between the two sides.
ffmpeg -i input0 -i input1 -filter_complex "[0]pad=iw+5:color=black[left];[left][1]hstack=inputs=2" output
With audio
Downmix and use original channel placements
Add the amerge filter to combine the audio channels from both inputs:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output
This assumes each input contains a stereo audio stream.
-ac 2 is included to downmix to stereo in case both inputs contain multi-channel audio. For example, if both inputs are stereo, you would get a 4-channel output audio stream instead of stereo if you omit -ac 2.
Put all audio from each input into separate channels
Use amerge (or amix) and pan filters:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2,pan=stereo|c0<c0+c1|c1<c2+c3[a]" -map "[v]" -map "[a]" output
This assumes each input contains a stereo audio stream.
Using audio from one particular input
This example will use the audio from input1:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v]" -map "[v]" -map 1:a output
Adding silent audio / If one input does not have audio
If you mix inputs that have audio and inputs that do not have audio then amerge will fail because each input needs audio. You can add silent audio with the anullsrc filter to prevent this:
ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];anullsrc[silent];[0:a][silent]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output.mp4
3 videos or images
ffmpeg -i input0 -i input1 -i input2 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" output
If you want vertical use vstack instead of hstack.
2x2 grid
Using xstack
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v][2:v][3:v]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]" -map "[v]" output
Using hstack and vstack
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v]hstack=inputs=2[top];[2:v][3:v]hstack=inputs=2[bottom];[top][bottom]vstack=inputs=2[v]" -map "[v]" output
This syntax is easier to understand, but less efficient than using xstack as shown above.
2x2 grid with text
Using the drawtext filter:
ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex
"[0]drawtext=text='vid0':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v0];
[1]drawtext=text='vid1':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v1];
[2]drawtext=text='vid2':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v2];
[3]drawtext=text='vid3':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v3];
[v0][v1][v2][v3]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]"
-map "[v]" output
4x4
Use the xstack filter. Example for a total of 16 videos:
ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v][1:v][2:v][3:v][4:v][5:v][6:v][7:v][8:v][9:v][10:v][11:v][12:v][13:v][14:v][15:v]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4
If you need to scale the inputs first:
ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v]scale=iw/4:-1[v0];[1:v]scale=iw/4:-1[v1];[2:v]scale=iw/4:-1[v2];[3:v]scale=iw/4:-1[v3];[4:v]scale=iw/4:-1[v4];[5:v]scale=iw/4:-1[v5];[6:v]scale=iw/4:-1[v6];[7:v]scale=iw/4:-1[v7];[8:v]scale=iw/4:-1[v8];[9:v]scale=iw/4:-1[v9];[10:v]scale=iw/4:-1[v10];[11:v]scale=iw/4:-1[v11];[12:v]scale=iw/4:-1[v12];[13:v]scale=iw/4:-1[v13];[14:v]scale=iw/4:-1[v14];[15:v]scale=iw/4:-1[v15];[v0][v1][v2][v3][v4][v5][v6][v7][v8][v9][v10][v11][v12][v13][v14][v15]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4
Resize/scale an input
Since both videos need to have the same with for vstack, and the same height for hstack, you may need to scale one of the other videos to match the other:
Simple scale filter example to set width of input0 to 640 and automatically set height while preserving the aspect ratio:
ffmpeg -i input0 -i input2 -filter_complex "[0:v]scale=640:-1[v0];[v0][1:v]vstack=inputs=2" output
For a more advanced method to fit any size video into a specific size while preserving aspect ratio see Resizing videos with ffmpeg to fit into static sized player.
You can also use the scale2ref filter to automatically resize one video to match the dimensions of the other.
Delaying/pausing videos
This example will play the top left video while pausing the others. Once the top left video ends the top right video will play and so on.
Use the tpad, adelay, xstack, and amix filters:
ffmpeg -i top-left.mp4 -i top-right.mp4 -i bottom-left.mp4 -i bottom-right.mp4 -filter_complex "[1]tpad=start_mode=clone:start_duration=5[tr];[2]tpad=start_mode=clone:start_duration=10[bl];[3]tpad=start_mode=clone:start_duration=15[br];[0][tr][bl][br]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v];[1:a]adelay=5s:all=true[a1];[2:a]adelay=10s:all=true[a2];[3:a]adelay=15s:all=true[a3];[0:a][a1][a2][a3]amix=inputs=4[a]" -map "[v]" -map "[a]" output.mp4
This example assumes each input is 5 seconds duration. Adjust start_duration and adelay values as needed.
This command requires FFmpeg 4.3 or newer.
If you don't like the complexity of xstack you can use several hstack/vstack instead as shown in Example 4: 2x2 grid.
See this answer to this question for a newer, simpler way to do this.
Old version:
You should be able to do this using the pad, movie and overlay filters in FFmpeg. The command will look something like this:
ffmpeg -i top.mov -vf 'pad=iw:2*ih [top]; movie=bottom.mov [bottom]; \
[top][bottom] overlay=0:main_h/2' stacked.mov
First the movie that should be on top is padded to twice its height. Then the bottom movie is loaded. Then the bottom movie is overlaid on the padded top movie at an offset of half the padded movie's height.
For 2 videos:
ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex hstack out.mp4
For more videos(3 in this example):
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex hstack=3 out.mp4

Resources