How we checked these commands: every command on this page was run with FFmpeg 8.1.2 on macOS on 24 October 2026, on short generated test clips, and the output was inspected with ffprobe (resolution, frame rate, duration, streams). Results on your files can differ if your FFmpeg build or input files are different.
Before you start: are your clips identical in format?
Run this for each clip and compare the output:
ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,sample_rate -of compact clip1.mp4
If every clip shows the same video codec, resolution, frame rate, audio codec and sample rate (typical for clips from the same camera or the same export preset), use Method 1. If anything differs, use Method 2.
Method 1: concat demuxer (no re-encoding)
Create a text file called list.txt with one line per clip, in playback order:
file 'clip1.mp4'
file 'clip2.mp4'ffmpeg -f concat -safe 0 -i list.txt -c copy merged.mp4
-c copy copies the streams without re-encoding, so the merge is fast and adds no extra compression. -safe 0 lets the list contain paths that FFmpeg would otherwise reject, such as absolute paths. In our test, a 4-second and a 5-second clip with identical settings (H.264 1280×720 30 fps, AAC 48 kHz) merged into one file of about 9.0 seconds.
What goes wrong with mismatched clips: we added a third, 3-second clip to the list with a different codec (MPEG-4), resolution (1920×1080), frame rate and audio format, so the total should have been 12 seconds. FFmpeg finished without an error, but the merged file was about 11.0 seconds long. Re-encoding the same list instead of using -c copy gave about 9.0 seconds, so the mismatched clip was effectively lost. The concat demuxer is not meant for mixed inputs; see the concat demuxer documentation. Use Method 2 for those clips.
Method 2: concat filter (clips with different settings)
ffmpeg -i clip1.mp4 -i clip3.mov -filter_complex "[0:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30[v0];[1:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30[v1];[0:a]aresample=48000[a0];[1:a]aresample=48000[a1];[v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" -c:v libx264 -crf 20 -preset medium -c:a aac -b:a 192k merged-mixed.mp4
Each clip is first brought to the same size (1280×720, with black bars if the shape differs), the same pixel aspect ratio and the same frame rate, and its audio is resampled to 48 kHz. Only then does concat join them. n=2 is the number of clips. For three clips, add -i for the third file, a matching [2:v]…[v2] and [2:a]…[a2] chain, and set n=3. In our test we joined a 4-second H.264 1280×720 clip (48 kHz audio) and a 3-second MPEG-4 1920×1080 25 fps clip (44.1 kHz PCM audio) into one 7-second H.264 1280×720 30 fps file. See the concat filter documentation.
Every clip needs an audio track for this exact command. If one has no audio, you will need to add silence to it first.