Concatenate video files with FFmpeg: concat demuxer, concat filter, and the right choice
Join multiple video files into one. The concat demuxer for matched files (no re-encoding), the concat filter for mismatched ones, and the file-list discipline that prevents the most common bug.
When to use this
You concatenate videos when joining episodic content, stitching ad-inserted segments into a single asset, recombining multi-take recordings, or assembling a master from production deliverables. The right method depends on whether the input files match in codec, container, resolution, and framerate — matched files concat in seconds via stream-copy; mismatched files require re-encoding. Always inspect before deciding.
Command variants
# Create a file list:
cat > files.txt << EOF
file 'part1.mp4'
file 'part2.mp4'
file 'part3.mp4'
EOF
# Concat:
ffmpeg -f concat -safe 0 -i files.txt -c copy output.mp4Near-instant when files match. The default for most concat use cases.
ffmpeg -i part1.mp4 -i part2.mp4 -i part3.mp4 \
-filter_complex "[0:v][0:a][1:v][1:a][2:v][2:a]concat=n=3:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" \
-c:v libx264 -preset medium -crf 21 \
-c:a aac -b:a 192k \
output.mp4Use when files differ in codec, resolution, or framerate. Re-encodes everything.
for f in part*.mp4; do
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,width,height,r_frame_rate \
-of csv=p=0 "$f"
doneRun this first to confirm all files have the same codec, resolution, and framerate. If they match → use concat demuxer. If they don't → use concat filter.
What each parameter does
-f concatTells FFmpeg the input is a concat demuxer file list, not a single video file.
-safe 0Allows file paths in the list to use any filename. Required for absolute paths or filenames with special characters.
-c copyStream-copy everything. Works only when files match exactly in codec/format. The reason concat demuxer is fast.
concat=n=3:v=1:a=1Concat filter with n inputs, 1 video stream each, 1 audio stream each. Forces re-encoding.
filter_complexRoutes each input's video + audio streams into the concat filter and emits combined streams.
What this outputs
A single video file containing all input files joined end-to-end. Concat demuxer produces output identical to the inputs (just glued together); concat filter re-encodes and produces a new file at the encoder settings you specify.
Pitfalls
- The MOST common bug: concat demuxer with mismatched files succeeds but produces broken output (audio/video drift, frozen frames, no audio after part 2). Always verify the codec/resolution/framerate before stream-copy concat.
- File path issues in files.txt: paths must be relative to the file list location, OR you use absolute paths with -safe 0. Mixing is unreliable.
- Single quotes around filenames are required if filenames contain spaces. Double quotes won't work.
- Audio/video stream count mismatches: if part1.mp4 has stereo audio and part2.mp4 has 5.1, concat filter fails. Pre-process to a uniform format first.
- Concat filter with many inputs (>10) gets slow and memory-hungry. For long lists, use intermediate concat passes (5 → 1, then 5 → 1, then 2 → 1 final).
- GOP boundaries: concat demuxer with VBR codecs (most modern codecs) sometimes produces a brief audio/video glitch at the join point. The fix: use closed GOPs and segment-aligned splits.
At production scale
Concat demuxer is essentially free at scale (I/O-bound). Concat filter is libx264-bound and roughly 2× the cost of single-file encoding because it must process every frame of every input. At production scale, structure pipelines so files arrive already matched (uniform encoder, uniform format) so concat demuxer is the default. Re-encoding concat should be the exception, not the rule.
MpegFlow models concat as a dedicated DAG stage that probes inputs first, picks demuxer or filter mode based on actual codec/format match, and reports the choice in the audit log. This avoids the silent-broken-output failure mode that surprises teams using FFmpeg directly.
- FFmpeg
- concat
- video-operations
- editing