提示

返回博客列表

好几段视频想拼成一条?彻底搞懂视频合并(MP4 合并实战与坑全解)

好几段视频想拼成一条?彻底搞懂视频合并(MP4 合并实战与坑全解)

拍了一段开场、一段正片、一段结尾,想拼成一条完整视频发出去——看似简单,新手却常遇到"合并后只有第一段能播""中间黑屏""音画错位""顺序乱了"。这篇文章把 MP4 合并的几种方式、能用和不能用的边界、以及所有坑一次讲透,并给出批量脚本和工程级建议。

一、为什么 MP4 不能直接 cat 拼接

TS 流设计上能直接首尾相接(每个包 188 字节自带同步字节),但 MP4 不行。MP4 的索引(moov atom)写在文件头或尾,描述"每一帧数据在哪"。直接 cat a.mp4 b.mp4 > c.mp4 会得到两份 moov,播放器只认第一份,于是第二段直接错乱或播放器认为文件结束。所以 MP4 合并必须借助工具重新组织索引或重编码。

二、方法一:concat demuxer(推荐,满足条件时无损)

如果所有片段编码参数完全一致(同编码、同分辨率、同帧率、同码率、同色彩空间),可以这样:

# 建列表(注意顺序)
cat > list.txt <<'EOF'
file 'part1.mp4'
file 'part2.mp4'
file 'part3.mp4'
EOF

ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

-c copy 不重编码,秒级完成,画质零损失。条件是"参数一致",否则报错或播放异常。

三、方法二:concat 滤镜(万能,但重编码)

当片段参数不一致(不同分辨率、不同编码、不同帧率),用滤镜先解码再统一编码:

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[outv][outa]" \
  -map "[outv]" -map "[outa]" -c:v libx264 -crf 18 -c:a aac output.mp4

n=3 表示 3 段。它会把所有片段重编码成统一参数,兼容性最好,代价是慢、轻微损画质。

四、方法三:先转成统一格式再 demuxer(折中)

片段来自不同设备、参数杂乱时,先各自统一成相同规格,再用方法一无损拼:

# 统一转成相同规格
ffmpeg -i part1.mp4 -c:v libx264 -crf 23 -c:a aac -r 30 -s 1280x720 p1.mp4
# 对 part2/part3 同样处理...
# 再用 concat demuxer 合并
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

适合"参数乱但想保持无损合并"的场景。

五、能不能混不同分辨率/编码

  • 同编码不同分辨率:demuxer 会失败,必须滤镜法(它会统一到第一个或指定尺寸,可能缩放);
  • 不同编码(H.264 + H.265):demuxer 直接报错,必须滤镜法重编码;
  • 不同帧率:建议统一帧率避免跳变或丢帧;
  • 不同色彩空间/HDR vs SDR:务必先统一(见色彩空间专题),否则画面异常。

六、音频流数量不一致怎么办

某段有双音轨、某段只有单音轨,concat 滤镜会报错"流数不匹配"。处理:统一音轨数(用 -mappan 合并/丢弃指定轨),再合并:

# 只取每段的第一条音轨,避免数量不一致
ffmpeg -i part1.mp4 -i part2.mp4 \
  -filter_complex "[0:v][0:a:0][1:v][1:a:0]concat=n=2:v=1:a=1[outv][outa]" \
  -map "[outv]" -map "[outa]" out.mp4

七、批量把目录下所有片段按顺序合并

ls *.mp4 | sed "s/^/file '/;s/$/'/" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

注意文件名排序(自然数排序),避免 1,10,11,2 的乱序。更稳妥用 sort -V 或脚本按数字排序。

八、合并方式对比

方式 速度 画质 条件 适用
concat demuxer 最快 无损 参数完全一致 同设备分段
concat 滤镜 轻微损 无要求 参数杂乱
先统一再 demuxer 无损 可先转统一 折中

九、常见翻车现场

现象 根因 解法
合并后只有第一段 直接 cat 或损坏的 moov 用 concat demuxer/filter
中间黑屏 参数不一致 + demuxer 改用 filter 重编码
音画错位 音频流数不一致 统一音轨数后再合并
顺序错乱 文件名排序问题 用自然排序重命名
合并极慢 用滤镜重编码 统一参数后用 demuxer 无损

十、工程级建议

  • 拍摄时统一参数(分辨率/帧率/编码)能从根上避免合并麻烦;
  • 合并前先 ffprobe 各片段确认参数,再决定用 demuxer 还是 filter;
  • 大工程用滤镜法虽然慢,但产出最稳,配合 -crf 18 画质几乎无损;
  • 结尾加 faststart-movflags +faststart)让网络播放秒开。

十一、常见问题

Q:手机拍的几段能直接拼吗? 大概率参数一致,demuxer 能直接拼;不一致就滤镜法。

Q:能不能加转场? 简单淡入淡出可在滤镜里加 fade;复杂转场得用剪辑软件。

Q:合并会损画质吗? demuxer 无损;filter 重编码有轻微损失,用 -crf 18 之类保持高画质。

Q:TS 切片怎么拼? 见专门的 TS 合并专题,TS 可直接 cat 或 demuxer,友好得多。

十二、端到端实战:把 3 段不同设备拍的素材拼成一条

假设 part1 是手机竖拍 1080x1920、part2 是相机 1920x1080、part3 是录屏 1280x720,全要拼成横屏 1280x720:

# 1) 统一规格
ffmpeg -i part1.mp4 -vf "scale=720:1280,pad=1280:720:(ow-iw)/2:(oh-ih)/2" -c:v libx264 -crf 20 -c:a aac p1.mp4
ffmpeg -i part2.mp4 -vf "scale=1280:720" -c:v libx264 -crf 20 -c:a aac p2.mp4
ffmpeg -i part3.mp4 -vf "scale=1280:720" -c:v libx264 -crf 20 -c:a aac p3.mp4
# 2) 列出并合并
printf "file '%s'\n" p1.mp4 p2.mp4 p3.mp4 > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

关键是先统一分辨率/编码/帧率,否则 demuxer 会失败、或滤镜法需要处理尺寸变换。

十三、合并时加转场(基础淡入淡出)

要在两段之间做 0.5 秒交叉淡化,用 xfade

ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
  "[0][1]xfade=transition=fade:duration=0.5:offset=4.5,format=yuv420p[v]" \
  -map "[v]" -map 0:a out.mp4

offset 是转场开始时间(第一段的时长减 duration)。复杂转场(滑动、圆形)xfade 都支持,但注意音频在 xfade 处需单独处理(可用 acrossfade)。

十四、更多 FAQ

Q:合并后时长对不上? 可能是某段被截断或帧率不一致导致丢帧,统一帧率重试。

Q:能不能直接拖进剪辑软件拼? 能,但 ffmpeg 方案适合批量/自动化、无 GUI 环境。

Q:合并会改文件名顺序吗? 不会,顺序由 list.txt 或命令行参数决定,注意自然排序。

Q:TS 切片合并有什么特殊? TS 可直接 cat 或 demuxer,比 MP4 友好,详见 TS 合并专题。

小结

MP4 合并三选法:参数全一致用 concat demuxer(无损最快)不一致用 concat 滤镜(重编码万能)折中先统一参数再 demuxer。核心是先看清片段参数是否一致,再决定路数,别上来就 cat。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部