"Merging" means playing clips back-to-back into one file. The method depends on whether your clips already match. If they share the same codec, resolution, and frame rate, the concat demuxer stitches them without re-encoding — instant and lossless. If they differ, the concat filter re-encodes everything into one consistent stream.
Key takeaways
- Same codec/size/fps → concat demuxer with a file list,
-c copy, lossless. - Different clips → concat filter, which re-encodes to one stream.
- The demuxer needs a text file listing each input as
file '...'. - Always normalize fps/resolution before the filter or audio can drift.
Lossless merge (matching clips)
Create a list file, then point the demuxer at it. Nothing is re-encoded, so it finishes almost instantly:
# list.txt file 'clip1.mp4' file 'clip2.mp4' file 'clip3.mp4' # merge without re-encoding ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4
Merge clips that don't match
When resolutions, codecs, or frame rates differ, the demuxer will glitch. Use the concat filter so each input is decoded and re-encoded into one uniform stream:
ffmpeg -i a.mp4 -i b.mov -filter_complex \ "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" \ -map "[v]" -map "[a]" out.mp4
Normalize first for clean joins
The most reliable workflow with mixed sources is to bring every clip to the same resolution and frame rate before concatenating. Scale and set fps on each input inside the same filter graph:
ffmpeg -i a.mp4 -i b.mov -filter_complex \ "[0:v]scale=1920:1080,fps=30,setsar=1[v0]; \ [1:v]scale=1920:1080,fps=30,setsar=1[v1]; \ [v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \ -map "[v]" -map "[a]" out.mp4
Merge visually instead
FFmpegLab lets you drop clips onto a timeline in order and handles the normalize-and-concat math for you, writing the underlying command — fully offline. Add a smooth crossfade between clips instead of a hard cut, then compress the final cut.