15、视频拼接:使用concat协议和concat滤镜拼接多个视频文件。
视频拼接,说白了就是把几段视频首尾连起来,变成一个长视频。这事儿看起来简单,但实际做起来坑不少。我记得刚入行那会儿,领导扔给我三个不同分辨率的MP4文件,让我合成一个,我直接用cat命令合并——结果播放器直接崩溃。嗯,从那以后我才知道,视频拼接不是简单的文件堆叠。
FFmpeg提供了两种主流方案:concat协议和concat滤镜。它们各有各的脾气,选错了,轻则报错,重则音画不同步。今天我就把这两种方案掰开揉碎了讲清楚。
15.1 两种方案的核心区别
先看一张图,你就明白它们各自适合什么场景了。
说白了,concat协议就是个搬运工,它不碰你的视频内容,直接把数据流拼起来。而concat滤镜是个加工厂,它会重新编码,把不同规格的视频统一成同一个标准。
15.2 concat协议:无损快速拼接
这个方案我最常用。前提是你的视频文件必须「门当户对」——编码格式、分辨率、帧率、采样率都得一模一样。我在项目中遇到过好几次,客户说「我这些视频都是同一个相机拍的,肯定一样」,结果一查,有的帧率是29.97,有的是30,拼接完就出现微妙的音画不同步。
15.2.1 文件列表方式(推荐)
我个人习惯用文件列表的方式,清晰好维护。先创建一个文本文件,比如 mylist.txt:
file 'clip1.mp4'
file 'clip2.mp4'
file 'clip3.mp4'
然后执行:
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4
这里几个参数我解释一下:
-f concat:告诉FFmpeg使用concat协议-safe 0:允许使用绝对路径或特殊字符。如果不加,路径里带空格或中文就会报错-c copy:直接复制流,不重新编码。这是速度最快的模式
15.2.2 直接拼接方式
如果文件不多,也可以直接写在一行:
ffmpeg -i "concat:clip1.mp4|clip2.mp4|clip3.mp4" -c copy output.mp4
这种方式适合临时用一下。但说实话,我很少这么干——一旦文件名里有特殊字符,解析就容易出问题。
15.3 concat滤镜:灵活但慢
当你的视频参数不一致时,就得请concat滤镜出场了。它会重新编码,把所有视频统一成你指定的参数。
15.3.1 基础用法
ffmpeg -i clip1.mp4 -i clip2.mp4 -i clip3.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]" output.mp4
这个命令看着复杂,其实拆开看很简单:
[0:v][0:a]:第一个文件的视频流和音频流concat=n=3:v=1:a=1:拼接3个文件,输出1路视频和1路音频[outv][outa]:给输出流起个名字,方便后面映射
15.3.2 统一分辨率再拼接
我在实际项目中经常遇到这种情况:几个视频分辨率不一样,但又要拼在一起。这时候我会先统一分辨率:
ffmpeg -i clip1.mp4 -i clip2.mp4 \
-filter_complex "[0:v]scale=1920:1080,setsar=1[v0]; \
[1:v]scale=1920:1080,setsar=1[v1]; \
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mp4
你想想看,如果不统一分辨率,拼接出来的视频画面会突然变大或变小,观众看着多难受。
15.4 实战对比表
为了方便你选择,我整理了一个对比表:
| 特性 | concat协议 | concat滤镜 |
|---|---|---|
| 是否需要重新编码 | 否(直接复制) | 是(重新编码) |
| 拼接速度 | 极快(秒级) | 较慢(取决于视频长度和编码参数) |
| 输出质量 | 无损 | 有损(取决于编码参数) |
| 输入参数要求 | 必须完全一致 | 可以不一致(但需统一处理) |
| 适用场景 | 同源视频、监控录像拼接 | 不同来源视频、需要统一规格 |
15.5 避坑指南
做视频拼接这几年,我踩过的坑能写满一页纸。挑几个最常见的说说:
- 音画不同步:我曾经拼接两个帧率不同的视频,结果声音越往后越对不上。后来发现是concat滤镜默认用第一个视频的帧率,后面的视频帧率不一致导致。解决方案是先用
fps滤镜统一帧率。 - 黑屏或绿屏:这通常是编码参数不一致导致的。比如一个视频是yuv420p,另一个是yuv422p,拼接时就会出问题。用
format=yuv420p滤镜统一像素格式就好。 - 文件列表乱码:如果文件路径里有中文,记得把文件列表保存为UTF-8编码,并且加上
-safe 0参数。
ffprobe查看一下:ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,sample_rate -of default=noprint_wrappers=1 clip1.mp4。把几个视频的参数对比一下,再决定用哪种方案。
15.6 总结
视频拼接这事儿,选对方案就成功了一半。参数一致的视频,用concat协议,又快又好;参数不一致的,用concat滤镜,灵活处理。嗯,就这么简单。
最后提醒一句:生产环境中,能用concat协议就别用concat滤镜。重新编码不仅慢,还会损失画质。除非你确实需要统一参数,否则别给自己找麻烦。