How to Create Animated Split Screen with FFmpeg
This guide explains how to combine two video feeds into a
split-screen composition using FFmpeg, where the dividing line between
both inputs dynamically animates across the frame. By using FFmpeg's
built-in blend filter with per-pixel mathematical
expressions, you can smoothly move, sweep, or oscillate the split
boundary over time without needing external video editing software.
Step 1: Normalize Video Dimensions and Framerates
The blend filter requires both video streams to have
identical dimensions, framerates, and pixel formats. Pre-scale both
inputs inside the filter graph to ensure compatibility:
ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30,format=yuva420p[v0]; \
[1:v]scale=1920:1080,fps=30,format=yuva420p[v1]" ...Step 2: Create a Linear Moving Split
To create a boundary that moves linearly from the left edge to the
right edge over a set duration (e.g., 10 seconds), use the
blend filter's all_expr parameter.
ffmpeg -i left.mp4 -i right.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30[v0]; \
[1:v]scale=1920:1080,fps=30[v1]; \
[v0][v1]blend=all_expr='if(lte(X, W*(t/10)), A, B)'[outv]" \
-map "[outv]" -map 0:a? -c:v libx264 -pix_fmt yuv420p output_linear.mp4How the Expression Works:
X: The horizontal coordinate of the current pixel.W: The total width of the video frame.t: The current timestamp in seconds.A: The pixel value from the first input ([v0]).B: The pixel value from the second input ([v1]).if(lte(X, W*(t/10)), A, B): If the current X-coordinate is less than or equal to the calculated boundary position, display input A; otherwise, display input B.
Step 3: Create an Oscillating (Back-and-Forth) Boundary
To make the split line smoothly swing back and forth across the
center of the frame, introduce a trigonometric function
(sin) into the expression:
ffmpeg -i left.mp4 -i right.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30[v0]; \
[1:v]scale=1920:1080,fps=30[v1]; \
[v0][v1]blend=all_expr='if(lte(X, (W/2) + (W/4)*sin(2*PI*t/4)), A, B)'[outv]" \
-map "[outv]" -map 0:a? -c:v libx264 -pix_fmt yuv420p output_oscillating.mp4(W/2)sets the center anchor point of the split.(W/4)*sin(...)limits the travel distance to 25% of the frame width to the left and right.2*PI*t/4controls the oscillation speed, completing one full cycle every 4 seconds.
Step 4: Add a Colored Dividing Line
To clearly separate the two videos, you can highlight the animated boundary with a solid border line. This condition checks if the pixel falls within a narrow coordinate window around the boundary and overrides the color value:
ffmpeg -i left.mp4 -i right.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30[v0]; \
[1:v]scale=1920:1080,fps=30[v1]; \
[v0][v1]blend=all_expr='if(between(X, (W/2 + (W/4)*sin(2*PI*t/4)) - 3, (W/2 + (W/4)*sin(2*PI*t/4)) + 3), 255, if(lte(X, (W/2 + (W/4)*sin(2*PI*t/4))), A, B))'[outv]" \
-map "[outv]" -map 0:a? -c:v libx264 -pix_fmt yuv420p output_border.mp4between(X, Boundary - 3, Boundary + 3)creates a 6-pixel wide strip where the boundary currently sits.255forces the pixels inside that strip to maximum luminance, creating a visible white divider.
Step 5: Audio Handling
In the commands above:
-map "[outv]"selects the processed video stream.-map 0:a?includes the audio from the first video if present.- To mix the audio tracks of both source files simultaneously, add the
amixfilter:
ffmpeg -i left.mp4 -i right.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30[v0]; \
[1:v]scale=1920:1080,fps=30[v1]; \
[v0][v1]blend=all_expr='if(lte(X, W*(t/10)), A, B)'[outv]; \
[0:a][1:a]amix=inputs=2:duration=first[outa]" \
-map "[outv]" -map "[outa]" -c:v libx264 -pix_fmt yuv420p output_mixed_audio.mp4