FFmpeg全名是Fast Forward MPEG(Moving Picture Experts Group),為開源的影音多媒體處理框架,可以進行影音的解碼、編碼、編碼轉換、混合、抽取、串流和濾鏡,無論影音格式是從哪個地方出來的,從過去到現在的影音格式它幾乎都能夠支援。FFmpeg當然也能夠輕鬆辦到影片和聲音的串接,在特定條件下甚至還不需重新編碼呢!



對於影片和聲音的串接,FFmpeg主要有三種方式可以達成:

  1. Concat Filter
  2. Concat Demuxer
  3. Concat Protocol

Concat Filter

利用FFmpeg提供的-filter_complex選項來手動設定影音濾鏡,這個方式需要重新進行影音編碼,但輸入的影片和聲音格式(編碼方式和影音參數)可以是不同的,算是萬用的作法啦!不過缺點就是因為要重新編碼,所以可能會減損畫質和音質,而且也會需要比較多的處理時間。

指令格式如下:

ffmpeg -i 要被串接的影音檔案路徑1 -i 要被串接的影音檔案路徑2 -i 要被串接的影音檔案路徑3 -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]" 輸出的影片檔案路徑

以上是串接三個影音檔案時用的指令,如果您只需要串接兩個或是要串接超過三個,或者是要設定只串接某幾個檔案的影片或是只串接某幾個檔案的聲音,請自行調整-i選項,以及-filter_complex選項後接的參數。例如要串接兩個聲音檔,指令要改成:

ffmpeg -i 要被串接的聲音檔案路徑1 -i 要被串接的聲音檔案路徑2 -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[outa]" -map "[outa]" 輸出的聲音檔案路徑

若只有少數幾個要被串接的影音檔案的格式與其它的影音檔案格式不符,建議先將它們轉成相符的格式,再使用下面介紹的Concat Demuxer來串接會比較好。

Concat Demuxer

如果輸入的影片和聲音格式是相同的(檔案容器格式可以不相同),可以使用這個方式來進行串接,就不需要重新編碼了。

-i參數前加上-f concat,可以讓-i輸入一個文字檔案,這個文字檔案的撰寫方式如下:

# this is a comment
file '/path/to/file1'
file /path/to/file2
file /path/to/file3

檔案的串接順序是從上到下,檔案路徑若要加引號括起來,只能夠使用單引號。假設這個文字檔案的檔名為concat.txt,則以下的FFmpeg指令:

ffmpeg -f concat -safe 0 -i concat.txt -c copy 輸出的影音檔案路徑

以上指令,可以將影音檔案/path/to/file1/path/to/file2/path/to/file3串接起來。-safe 0參數用來關閉路徑的保護功能,讓-i輸入的文字檔中的路徑可以使用絕對路徑。若使用相對路徑,則是相對於文字檔的路徑,並不是相對於目前的工作目錄。

若不想要另外新增文字檔案的話,在Linux作業系統下,指令也可以寫成這樣:

ffmpeg -f concat -safe 0 -i <(echo "file '/path/to/file1'"; echo "file /path/to/file2"; echo "file /path/to/file3") -c copy 輸出的影音檔案路徑

直接在指令中產生文字檔案的內容餵給FFmpeg服用,而像這種<(...)的指令用法稱為「行程替換」(process substitution)。Linux作業系統會自動將<(...)替換為/dev/fd/目錄下的檔案,檔案內容則是由<(...)括號內的指令輸出的。由於這樣的用法會導致文字檔的相對路徑是相對於/dev/fd/目錄,因此勢必得使用絕對路徑來連結影音檔案才行。

Concat Protocol

如果輸入的影片和聲音的檔案容器本身就是可以直接串接(例如TS、PCM)的話,可以使用這個方式來進行串接,就不需要重新編碼了。

指令格式如下:

ffmpeg -i "concat:要被串接的聲音檔案路徑1|要被串接的影音檔案路徑2|要被串接的影音檔案路徑3" -c copy 輸出的影音檔案路徑

不過在Linux作業系統下,似乎直接使用cat指令來串接這些檔案應該會省事一點?不見得,如果輸入的檔案容器和輸出的檔案容器不同的話,cat指令就不適用了。而且不使用-c copy參數的話,FFmpeg還可以一邊串接一邊進行影音處理呢!