欢迎光临散文网 会员登陆 & 注册

(8)用ffmpeg拼接音视频、字幕:concat方案的三种用法及优缺点

2020-02-26 23:17 作者:思思陆思思  | 我要投稿

拼接媒体文件,意思就是,比如把两段1分钟的音频首尾拼接起来,就成了一段2分钟的音频。一般是音频接音频,视频接视频,字幕接字幕。其它情况本篇不考虑,但可能本文方法也有适用的情况。

注意拼接不是合并音频双开的意思!!合并以后再讲解。但拼接字幕就可以理解成合并字幕。(但并不能用ffmpeg -i in1.ass -i in2.ass -c:s copy out.ass这个命令行合并!)


ffmpeg的官网wiki对拼接媒体文件的说明教学:https://trac.ffmpeg.org/wiki/Concatenate本篇大约是这个“说明”中较常用内容的通俗汉化,也结合网上以及自己的一些经验来优化。


事先注意:建议所拼接视频的tbr、tbntbc数据一致,最好是同一来源的分段切片视频(比如网上下载的分段flv、ts,这样基本都是一致的)。可用“ffmpeg -i .\in.mp4”或“ffprobe .\in.mp4”来查看这些数据。不一致的话在这三个方案中可能是导致音视频不同步的原因之一(如果纯视频拼接可无视),或者考虑直接用openshot、shotcut等开源免费软件来拼接(不像pr那么重量)。



一、相同编码格式媒体文件的拼接

强调注意是相同编码格式!!这个前提下有两种方法,各有优劣。concat协议方案非常方便,但适用性较小;concat分离器方案麻烦一点,但普适各种甚至跨容器格式的音视频。(拼接常见文本字幕建议使用协议方案,分离器方案好像会出现时间轴偏差的情况)


1.concat协议方案(Concat protocol)

对于少量拼接常见编码格式srt、ass、ssa的字幕文件,常见编码格式如h264的ts切片视频,mp3编码的mp3音频,aac编码的aac音频,up非常推荐这个做法。如果不行再看下一个做法。

这个方案是以“文件”的思路来操作的,就像拼积木那样一块一块拼起来。

命令行如下:

ffmpeg -i "concat:.\in1.ass|.\in2.ass" -c copy .\out.ass

ffmpeg -i "concat:.\in1.ts|.\in2.ts|.\in3.ts" -c copy .\out.ts

这里的拼接顺序也和ffmpeg按从左到右的顺序运行的道理一样。

这个方案也可以拼接常见相同编码、容器格式的视频,不过up感觉过于麻烦,就不说了,可在上面给出的官网wiki了解。


2.concat分离器方案(Concat demuxer)

如果需要大量拼接常见甚至各种,相同或者跨容器格式的音视频(例如拼接相同编码格式的mp4和flv视频),我们使用这个做法。如果不行则尝试下一个做法或开头说的用软件拼接。( 如果是大量拼接从m3u8链接下载的ts切片视频建议用copy /b 0.ts+1.ts+……+n.ts new.ts这种方法,用ffmpeg可能会时间戳冲突。具体见评论。分段flv或者几个ts的话可以考虑ffmpeg)

这个方案是以“流”的思路操作。将一堆媒体文件看成有许多“流”,将它们归类好最后封装输出。


up建议的做法如下命令行:

ffmpeg -f concat -safe 0 -i .\mylist.txt -c copy .\out.mp4

这是利用绝对路径,在txt里必须说明具体目录。因此我们在这里必须加上“-safe 0”。

所以mylist.txt的内容例如下图:

这表示我们想要拼接的文件。拼接顺序是从上到下

手打这种txt可能过于有趣,我们可以先制作一个bat文件。

新建一个记事本,直接输入以下内容:

(for %%i in (*.mp4) do @echo file '%cd%\%%i') > mylist.txt

这里的“mp4”是我们要拼接的视频的容器格式

保存,改后缀为bat,文件名随意。最后这个txt就成了下面这样:

运行这个bat,它会记录当前目录的mp4文件

并在此目录输出一个mylist.txt,其内容就是之前的那样

①如果是跨容器格式拼接,那么新建的记事本所输入内容如下:

(for %%i in (*.mp4 *.flv *.mov) do @echo file '%cd%\%%i') > mylist.txt

这表示要拼接的文件的容器格式是mp4、mov、flv

这样最后也是输出一个mylist.txt

(注意txt里面是按“名称”的排序方式排序,若想改顺序可以手动修改)

up建议用notepad3这个软件,如下图直接打开修改:

如果想重复拼接单个文件n次,cmd输入以下命令运行:

for /l %i in (1,1,n) do @echo file '.\in.mp4' >> mylist.txt

(是for /小写的L)之后其它步骤一样

(这些涉及到cmd命令,感兴趣可前往下面batch文集查看)

简单说说这些“for”的意思。%%i 是指代后面 in () 这个括号里的内容,括号里的诸如 *.mp4 这些表示这个批处理文件当前所存放目录下的所有mp4文件。因此 for %%i in (*.mp4) do 就是说,要对这个目录(不包括其子目录)里的所有mp4进行什么操作。@echo 就像“打字输出”的意思,输出后面 file '%cd%\%%i' 这个内容。%cd% 也是代表该批处理文件当前所存放的目录。所以串起来,@echo file '%cd%\%%i') > mylist.txt 就是说,进行的操作是输出这个内容到还是当前目录下新建的一个mylist.txt(即如上文所展示的图片)

for /l 是指循环in (起点,步长,终点)里表示的次数,((1,1,n)就是从1到n依次循环共n次,(2,2,10)就是2、4、6、8、10共5次)。%i 也是一样指代,和%%i区别是%i用在直接cmd输入命令行,%%i在批处理文件里使用。> 是一次输出用但会覆盖原来之前的内容,>> 可多次输出并在原来内容上作添加。


wiki给出的做法如下图:

这是一张图

这个做法利用的是相对路径(相对目录),即我们在txt里没有指明input文件的具体目录。



二、不同编码格式媒体文件的拼接

一般来说不会有这种需求,要做也比较麻烦了前提较多。官网wiki只给出了一种方法。


3.concat滤镜方案(Concat filter)

前提是视频之间的分辨率、帧率必须一致。这个方案是最后选择,挺万能,但也不保证一定有效。可以通过添加scale或scale2ref滤镜来对某个input视频调整分辨率。具体操作可前往开头的wiki网址查看,滤镜什么意思怎么操作请看下一篇。(是有点超纲了x

命令行如下:(这里用到的和第七篇的硬嵌字幕一样是滤镜)

ffmpeg -i in1.mp4 -i in2.webm -i in3.mov -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" out.mkv

我们可以写得“稍微”简短一点:

ffmpeg -i in1.mp4 -i in2.webm -i in3.mov -filter_complex "[0:0][0:1][1:0][1:1][2:0][2:1]concat=n=3:v=1:a=1[v][a]" -map "[v]" -map "[a]" out.mkv

对于音频,同样地:

ffmpeg -i in1.mp3 -i in2.aac -i in3.ogg -filter_complex "[0:a:0][1:a:0][2:a:0]concat=n=3:v=0:a=1[a]" -map "[a]" out.mkv


最后,up觉得字幕组烤大肉最后的轴合并可以用concat协议方案mad的镜头提纯(不含原声)可以搭配第四篇一起使用~



感谢观看到这里。

(8)用ffmpeg拼接音视频、字幕:concat方案的三种用法及优缺点的评论 (共 条)

分享到微博请遵守国家法律