(8)用ffmpeg拼接音視頻、字幕:concat方案的三種用法及優(yōu)缺點
拼接媒體文件,意思就是,比如把兩段1分鐘的音頻首尾拼接起來,就成了一段2分鐘的音頻。一般是音頻接音頻,視頻接視頻,字幕接字幕。其它情況本篇不考慮,但可能本文方法也有適用的情況。
注意拼接不是合并音頻雙開的意思??!合并以后再講解。但拼接字幕就可以理解成合并字幕。(但并不能用ffmpeg -i?in1.ass -i in2.ass -c:s copy out.ass這個命令行合并?。?/span>
ffmpeg的官網wiki對拼接媒體文件的說明教學:https://trac.ffmpeg.org/wiki/Concatenate本篇大約是這個“說明”中較常用內容的通俗漢化,也結合網上以及自己的一些經驗來優(yōu)化。
事先注意:建議所拼接視頻的tbr、tbn、tbc數據一致,最好是同一來源的分段切片視頻(比如網上下載的分段flv、ts,這樣基本都是一致的)。可用“ffmpeg -i?.\in.mp4”或“ffprobe .\in.mp4”來查看這些數據。不一致的話在這三個方案中可能是導致音視頻不同步的原因之一(如果純視頻拼接可無視),或者考慮直接用openshot、shotcut等開源免費軟件來拼接(不像pr那么重量)。
一、相同編碼格式媒體文件的拼接
強調注意是相同編碼格式!!這個前提下有兩種方法,各有優(yōu)劣。concat協(xié)議方案非常方便,但適用性較?。籧oncat分離器方案麻煩一點,但普適各種甚至跨容器格式的音視頻。(拼接常見文本字幕建議使用協(xié)議方案,分離器方案好像會出現時間軸偏差的情況)
1.concat協(xié)議方案(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 是指循環(huán)in (起點,步長,終點)里表示的次數,((1,1,n)就是從1到n依次循環(huán)共n次,(2,2,10)就是2、4、6、8、10共5次)。%i 也是一樣指代,和%%i區(qū)別是%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協(xié)議方案,mad的鏡頭提純(不含原聲)可以搭配第四篇一起使用~

感謝你觀看到這里。