The two-line solution to ffmpeg merge videos
You have clips. You want to merge videos with FFmpeg into a single file. Here's the fastest way:
Create a text file listing your clips:
Then run:
The -c copy flag means FFmpeg copies the streams without re-encoding. It finishes in seconds regardless of file size because it's just stitching bytes together.
The catch: this only works when your clips share the same codec, resolution, and frame rate. If they don't, you'll get garbled output or a cryptic error about non-monotonous DTS timestamps. The rest of this guide covers what to do when the simple path breaks down.
Three ways to ffmpeg concat videos
FFmpeg has three mechanisms for joining clips. Each handles different situations.
Method 1: the concat demuxer (same-format clips)
The concat demuxer is the go-to when your clips are identical in format. Same codec, same resolution, same frame rate. This is common when your clips come from the same camera or the same export preset.
The -safe 0 flag lets FFmpeg read files from any directory path. Without it, you'll get an "unsafe file name" error if your paths contain special characters or aren't relative to the text file.
Use this for clips from the same source: surveillance footage split into hourly chunks, screen recordings broken up by your capture tool. Anything where the format is guaranteed identical.
It breaks when clips have different codecs, or when one clip is 1080p and another is 720p, or audio sample rates don't match. The demuxer will either produce corrupted output or fail outright.
Method 2: the concat filter (different formats)
When clips have different codecs, resolutions, or frame rates, you need the concat filter. It re-encodes everything into a uniform output, which takes longer but actually works.
What each piece does:
[0:v][0:a]grabs the video and audio from the first inputconcat=n=3:v=1:a=1joins 3 inputs, each with 1 video and 1 audio stream-map "[outv]" -map "[outa]"routes the concatenated streams to the outputThe encoder flags (
libx264,crf 23,aac) control output quality
The filter handles resolution differences too. If clip1 is 1920x1080 and clip2 is 1280x720, you'll want to scale them to a common size first:
The pad filter adds black bars (letterboxing/pillarboxing) if the aspect ratios differ, so you don't get stretched video. If you'd rather crop instead of pad, swap pad for crop in the filter chain.
Use this for mixed sources: a clip from your phone plus one from a screen recorder, videos in different containers or codecs.
The trade-off is time. Re-encoding takes a few minutes for short clips, potentially hours for long ones. Output quality depends on your encoder settings. For guidance on picking the right CRF and preset, the video transcoding guide goes deep on codec selection.
Method 3: the concat protocol (MPEG-TS only)
The concat protocol is a third option that works at the file level:
The pipe character (|) separates file paths. This approach works without a file list, which makes it convenient for scripting. But it only works reliably with MPEG-TS streams. MP4 files use a container format that stores metadata (the moov atom) at the beginning or end of the file, and the protocol can't parse that correctly when concatenating.
If your sources are MP4, you'd need to convert them to TS first:
That's three commands instead of one. For MP4 files, the concat demuxer is simpler. The protocol is mostly useful when you already have .ts segments, like HLS output or live stream recordings.
Which method should you use?
Keep it simple:
Same format, same everything? Concat demuxer. Fast, no quality loss.
Different codecs or resolutions? Concat filter. Slower, but handles anything.
Already working with .ts segments? Concat protocol. Niche but useful for HLS workflows.
The demuxer handles probably 80% of real-world merging. You only reach for the filter when formats don't match, and you almost never need the protocol unless you're working with streaming segments.
Merging a whole directory of clips
If you have 50 clips in a folder and want them merged in alphabetical order:
For numbered files (clip001.mp4, clip002.mp4, ...), alphabetical sorting gets the order right automatically. If your filenames don't sort naturally, generate the list manually or use ls -v to sort by version number:
Watch out for a common gotcha: if files.txt already exists from a previous run, the >> append operator will add duplicates. Use > (overwrite) instead of >> (append), or delete the file first.
Troubleshooting common merge failures
Merging sounds simple until something goes wrong. Here are the errors that come up constantly and how to fix each one.
"Non monotonous DTS in output stream"
This means timestamps are out of order. It usually happens when clips were trimmed imprecisely or have slightly different durations in their audio vs video streams. Fix it by resetting timestamps:
The -fflags +genpts flag tells FFmpeg to regenerate presentation timestamps. If that doesn't help, try adding -avoid_negative_ts make_zero as well:
If timestamps are still broken, the nuclear option is to re-encode:
Re-encoding rebuilds all timestamps from scratch. It's slower, but it fixes timestamp issues that -fflags +genpts can't.
Codec mismatch between clips
If one clip is H.264 and another is H.265, the concat demuxer will produce garbage. You have two options:
Transcode the odd one out to match the majority format before merging. If most clips are H.264, convert the H.265 one:
Use the concat filter to re-encode everything at once. More straightforward when you have many mismatched clips.
Check what codecs are in each file before deciding:
This prints just the codec name (e.g. h264 or hevc). Run it on each clip to spot the mismatch. The FFmpeg cheat sheet has more ffprobe commands for inspecting files.
Audio sync drift
When merged video has audio that gradually goes out of sync, the clips probably have different audio sample rates (44100 Hz vs 48000 Hz is common). Force a consistent sample rate with the concat filter:
The -ar 48000 forces the output audio to 48 kHz, which is the standard for video. This resamples any clips that don't match.
One clip has no audio
If some clips have audio and others don't, the concat filter will fail with a stream mapping error. You need to add a silent audio track to the clips that lack one:
Then merge as usual. The anullsrc filter generates silence, and -shortest ensures it matches the video duration.
"Discarding 1 additional packets" / pixel format mismatch
This happens when clips have different pixel formats (e.g. yuv420p vs yuv444p). Force a common pixel format in the concat filter:
The yuv420p format is the safest choice since it's compatible with every player and browser.
"Discarding 1 additional packets" / frame rate mismatch
Different frame rates (30fps vs 29.97fps, or 24fps vs 30fps) can also cause packet discarding and choppy playback. Force a consistent frame rate:
ffmpeg merge videos at scale: batch processing
Merging two clips is a terminal command. Merging hundreds of clips across dozens of output files is an automation problem.
Bash loop for batch merges
Say you have paired clips (intro + main content) and want to merge each pair:
This works on a single machine but ties up your CPU. For anything more than a few dozen videos, offloading the work makes more sense. If you use n8n for workflow automation, the batch video processing guide covers how to set up a similar pipeline with parallel processing and error handling.
Merge videos via API (no local FFmpeg needed)
RenderIO runs FFmpeg in the cloud. You send the command over HTTP and get the merged file back. No installs, no CPU load on your machine.
Here's how to merge two clips using the concat filter via the API:
The API returns a command_id. Poll for completion:
When the status is SUCCESS, the response includes a download URL for your merged file.
You can also use the concat demuxer via the API. Upload the file list as an input, or build the -f concat command inline. For the full submit-poll-download pattern, see the complete API guide. The curl examples reference has 20 more ready-to-paste commands for other operations.
Node.js: merge videos programmatically
The function builds the concat filter dynamically, so you can pass in any number of clips. For a full Node.js setup including error handling and webhooks, see the Node.js API tutorial.
Python: merge and poll
For batch processing hundreds of merges, the Python API tutorial covers concurrent execution with ThreadPoolExecutor.
When merging isn't the right call
Sometimes what looks like a merge problem is actually an editing problem. If you need to:
Add transitions between clips (fades, dissolves): That's video editing, not concatenation. FFmpeg can do crossfade transitions with the
xfadefilter, but the syntax gets complicated quickly. A basic crossfade between two clips looks like this:
The offset is the timestamp (in seconds) where the transition starts, based on the first clip's duration minus the crossfade length.
Overlay clips on top of each other (picture-in-picture): Use the
overlayfilter instead of concat.Compress the merged output: Merge first with
-c copy, then compress the result as a separate step. Trying to do both at once with the demuxer doesn't work since-c copyand encoder flags are mutually exclusive. The video compression guide has the commands for that second step.
FAQ
Can I merge MP4 and MOV files together?
Yes, if they use the same codecs internally. MOV and MP4 are both container formats that can hold H.264 video and AAC audio. If both files contain H.264/AAC, the concat demuxer works fine. If the codecs differ, use the concat filter to re-encode.
How do I merge videos without losing quality?
Use the concat demuxer with -c copy. This copies the original streams byte-for-byte without re-encoding, so there's zero quality loss. It only works when all clips share the same codec, resolution, and frame rate.
Why does my merged video have a black frame between clips?
This usually means the last frame of one clip and the first frame of another overlap or have a timestamp gap. Try adding -fflags +genpts to regenerate timestamps. If that doesn't fix it, the clips may have been trimmed at non-keyframe boundaries. Re-trimming with the FFmpeg cheat sheet trim commands (using re-encode, not -c copy) and then merging again usually resolves it.
Can I merge videos with different aspect ratios?
Yes, with the concat filter. You need to scale and pad each clip to the same output resolution first. The scale + pad example earlier in this guide does exactly that. Without padding or cropping, FFmpeg will refuse to concatenate videos with different dimensions.
Is there a limit to how many videos I can merge?
FFmpeg itself has no hard limit. The concat demuxer reads from a text file, so it handles thousands of entries. The concat filter requires all inputs to be specified on the command line, which bumps into shell argument limits somewhere around a few hundred inputs depending on your OS. For very large merges (1000+ clips), the demuxer is the way to go.
How do I merge videos in a specific order?
The concat demuxer processes files in the order they appear in the text file. List them in the order you want. For the concat filter, the order matches the input order (-i first.mp4 -i second.mp4 ...).
Quick reference
| Scenario | Method | Re-encodes? | Speed |
| Same codec, same resolution | Concat demuxer | No | Seconds |
| Different codecs or resolutions | Concat filter | Yes | Minutes |
| HLS .ts segments | Concat protocol | No | Seconds |
| Batch merge via API | RenderIO API | Depends on command | Varies |
| Different resolutions, keep quality | Filter + scale | Yes | Minutes |
Every command above works through RenderIO's FFmpeg API. Send the command over HTTP, get the result back. The FFmpeg commands list has more operations with matching API calls. The Starter plan at $9/mo covers 500 commands. Get your API key to try it.