Create a 3x3 Video Grid Using FFmpeg xstack
This guide demonstrates how to use the FFmpeg xstack
filter to merge nine separate video files into a single 3x3 grid layout.
You will learn the exact command-line syntax, how to define the custom
grid coordinates, and how to manage the accompanying audio tracks for a
clean and professional final render.
The 3x3 Grid Command
To combine nine videos into a 3x3 grid, you must pass all nine videos
as inputs and use the xstack filter. The filter requires
you to define the number of inputs and specify the exact coordinate
placement for each video stream.
Here is the standard command assuming all nine input videos have the exact same dimensions (width and height):
ffmpeg -i input1.mp4 -i input2.mp4 -i input3.mp4 \
-i input4.mp4 -i input5.mp4 -i input6.mp4 \
-i input7.mp4 -i input8.mp4 -i input9.mp4 \
-filter_complex \
"[0:v][1:v][2:v][3:v][4:v][5:v][6:v][7:v][8:v]xstack=inputs=9:layout=0_0|w0_0|w0+w1_0|0_h0|w0_h0|w0+w1_h0|0_h0+h3|w0_h0+h3|w0+w1_h0+h3[v]" \
-map "[v]" output.mp4Understanding the Coordinates Layout
The layout parameter in xstack uses a grid
of X_Y coordinates separated by pipe (|)
characters. The coordinates correspond to each input video in the order
they are listed (from index 0 to 8).
Assuming each video has a width (w) and height
(h):
- Top Row:
- Video 1 (Top-Left):
0_0(Starts at origin) - Video 2 (Top-Middle):
w0_0(Shifted right by the width of the first video) - Video 3 (Top-Right):
w0+w1_0(Shifted right by the width of the first two videos)
- Video 1 (Top-Left):
- Middle Row:
- Video 4 (Middle-Left):
0_h0(Shifted down by the height of the first video) - Video 5 (Center):
w0_h0(Shifted right and down) - Video 6 (Middle-Right):
w0+w1_h0
- Video 4 (Middle-Left):
- Bottom Row:
- Video 7 (Bottom-Left):
0_h0+h3(Shifted down by the height of the first and fourth videos) - Video 8 (Bottom-Middle):
w0_h0+h3 - Video 9 (Bottom-Right):
w0+w1_h0+h3
- Video 7 (Bottom-Left):
Handling Different Input Sizes
The xstack filter requires all input streams to have
identical pixel formats, and the layout math is much simpler if they are
the exact same size. If your source videos have different resolutions,
you should scale them first within the filtergraph.
The command below scales all nine inputs to 640x360
before passing them to the xstack filter, resulting in a
perfectly aligned 1920x1080 output:
ffmpeg -i input1.mp4 -i input2.mp4 -i input3.mp4 \
-i input4.mp4 -i input5.mp4 -i input6.mp4 \
-i input7.mp4 -i input8.mp4 -i input9.mp4 \
-filter_complex \
"[0:v]scale=640:360[v0]; \
[1:v]scale=640:360[v1]; \
[2:v]scale=640:360[v2]; \
[3:v]scale=640:360[v3]; \
[4:v]scale=640:360[v4]; \
[5:v]scale=640:360[v5]; \
[6:v]scale=640:360[v6]; \
[7:v]scale=640:360[v7]; \
[8:v]scale=640:360[v8]; \
[v0][v1][v2][v3][v4][v5][v6][v7][v8]xstack=inputs=9:layout=0_0|w0_0|w0+w1_0|0_h0|w0_h0|w0+w1_h0|0_h0+h3|w0_h0+h3|w0+w1_h0+h3[v]" \
-map "[v]" output.mp4Adding Audio
By default, the above commands only output video. To manage audio, you have two primary options:
Option 1: Use Audio from One Specific Video
To use the audio from the first input video
(input1.mp4), map its audio channel using
-map 0:a:
ffmpeg -i input1.mp4 -i input2.mp4 ... [inputs] ... \
-filter_complex "[0:v]...xstack...[v]" \
-map "[v]" -map 0:a output.mp4Option 2: Mix All Audio Tracks Together
To mix the audio tracks of all nine inputs so they play
simultaneously, use the amix filter:
ffmpeg -i input1.mp4 -i input2.mp4 -i input3.mp4 \
-i input4.mp4 -i input5.mp4 -i input6.mp4 \
-i input7.mp4 -i input8.mp4 -i input9.mp4 \
-filter_complex \
"[0:v][1:v][2:v][3:v][4:v][5:v][6:v][7:v][8:v]xstack=inputs=9:layout=0_0|w0_0|w0+w1_0|0_h0|w0_h0|w0+w1_h0|0_h0+h3|w0_h0+h3|w0+w1_h0+h3[v]; \
[0:a][1:a][2:a][3:a][4:a][5:a][6:a][7:a][8:a]amix=inputs=9[a]" \
-map "[v]" -map "[a]" output.mp4