FFmpeg全名是Fast Forward MPEG(Moving Picture Experts Group),為開源的影音多媒體處理框架,可以進行影音的解碼、編碼、編碼轉換、混合、抽取、串流和濾鏡,無論影音格式是從哪個地方出來的,從過去到現在的影音格式它幾乎都能夠支援。當然,我們也可以用它來合併影片與字幕。



影片和字幕合併的方式主要分為兩種,第一種是將字幕直接烙印在影片上,或者說「燒錄」(Burn-in)在影片上,與影片一起進行編碼,使得影片與字幕形成單一的視訊軌(Video Track),稱為「硬字幕」(Hardsub)。第二種則是借助支援字幕軌(Subtitle Track)的檔案容器(如MKV),將影片和字幕封裝在一起,影片播放器在播放時可以同時播放視訊軌和字幕軌,將字幕輸出到影片上,稱為「軟字幕」(Softsub)。軟字幕也可以利用外掛字幕檔案(如SRT、ASS等)的方式來實現,稱為「外掛字幕」。

另外還有幾個名詞要先解釋。

內嵌字幕

內嵌字幕即硬字幕,但許多人(包括筆者自己)常會將封裝在影片檔案內的軟字幕稱作內嵌字幕。「內嵌字幕是硬字幕」的說法不知道是從何處來的,明明「內嵌歌詞」就是把歌詞寫進檔案容器內(可以延伸閱讀這篇文章了解MP3音樂檔的標籤),而不是把歌詞與音樂直接編碼在一起呀!

內掛字幕/內封字幕

內封字幕即軟字幕。內掛字幕則是相對於「外掛字幕」所產生的名詞,也是軟字幕。

內封(軟)字幕和內嵌(硬)字幕的差異

再來比較這兩種把影片和字幕合併在一起的方式有什麼差異吧!

內封字幕 內嵌字幕
是否需播放器支援? 否(字幕絕對會被顯示出來)
字幕是否可單獨提取?
字幕是否可被修改而不需重新編碼影片?
影片在播放時是否可控制字幕的顯示與否,以及顯示時的位置和樣式?

用FFmpeg將字幕內嵌在影片中

文字字幕

FFmpeg可以將外掛文字字幕檔,也就是SRT、ASS等檔案內嵌到任意的影片中,利用subtitles這個影片濾鏡參數就可以達成。基本的指令如下:

ffmpeg -i 輸入的影音檔案路徑 -vf "subtitles='輸入的字幕檔案路徑'" 輸出的影音檔案路徑

FFmpeg也可以將有內封字幕的檔案作為內嵌字幕的來源。指令如下:

ffmpeg -i 輸入的影音檔案路徑 -vf "subtitles='輸入的含內封字幕的影片檔案路徑'" 輸出的影音檔案路徑

如果那個有內封字幕的檔案擁有兩個以上的字幕軌,可以使用以下指令,利用si影片濾鏡參數來選擇要用第幾個字幕軌:

ffmpeg -i 輸入的影音檔案路徑 -vf "subtitles='輸入的含內封字幕的影片檔案路徑':si=第幾個字幕軌(從0開始數)" 輸出的影音檔案路徑

如果字幕來源是SRT,利用force_style影片濾鏡參數,我們可以另外設定字幕的字型和字體大小。像這樣:

ffmpeg -i 輸入的影音檔案路徑 -vf "subtitles='輸入的字幕檔案路徑':force_style='FontName=字型名稱,FontSize=字體大小'" 輸出的影音檔案路徑

例如要使用思源黑體作為字幕字型,並將字體大小設定為17的話,可以套用以下指令:

ffmpeg -i 輸入的影音檔案路徑 -vf "subtitles='輸入的字幕檔案路徑':si=1:force_style='FontName=Noto Sans CJK TC Regular,FontSize=17'" 輸出的影音檔案路徑

force_style影片濾鏡參數常用的選項如下:

  • FontName:字型名稱。
  • FontSize:字體大小。
  • Alignment:以數值來表示字幕的對齊方式,如下所示。
       左 中 右
    上  5  6  7
    中  9 10 11
    下  1  2  3
  • BoldItalicUnderlineStrikeout:分別是粗體、斜體、底線、刪除線。0為禁用;-1為啟用。
  • PrimaryColour:主體顏色。
  • Outline:邊框厚度。
  • OutlineColor:邊框顏色。
  • Shadow:陰影距離。
  • BackColour:陰影顏色。
  • MarginL:字幕距離左邊的距離,右對齊時無效。
  • MarginR:字幕距離右邊的距離,左對齊時無效。
  • MarginV:字幕距離底部或頂部的距離,中對齊時無效。

顏色的格式為&HAABBGGRR,其中的AA為透明度;BB為藍色;GG為綠色;RR為紅色,以十六進制表示(00~FF)。例如不透明的紅色為&H000000FF

如果FFmpeg在編碼時出現如下圖的「No usable fontconfig configuration file found, using fallback.」的訊息,它就很有可能無法正常套用到我們系統內部安裝的字體。此時可以再另外給它fontsdir影片濾鏡參數來設定字型檔的存放目錄。像這樣:

ffmpeg -i 輸入的影音檔案路徑 -vf "subtitles='輸入的字幕檔案路徑':fontsdir='字型檔的所在目錄'" 輸出的影音檔案路徑

ffmpeg-subtitle

圖形字幕

對於SUP等圖形字幕,要改用FFmpeg的overlay影片濾鏡來完成字幕的內嵌。指令如下:

ffmpeg -i 輸入的影音檔案路徑 -i 輸入的圖形字幕檔案路徑 -filter_complex "[0:v][1:s]overlay[v]" -map "[v]" -map 0:a 輸出的影音檔案路徑

用FFmpeg將字幕內封在MKV檔案中

指令如下:

ffmpeg -i 輸入的影音檔案路徑 -i 輸入的字幕檔案或含內封字幕的影片檔案路徑 -map 0:v -map 0:a -map 1:s -scodec copy 輸出的MKV檔案路徑

如果FFmpeg出現如下圖的「Too many packets buffered for output stream」訊息,則要使用-max_muxing_queue_size參數來設定大一點的緩衝空間。指令如下:

ffmpeg -i 輸入的影音檔案路徑 -i 輸入的字幕檔案或含內封字幕的影片檔案路徑 -map 0:v -map 0:a -map 1:s -scodec copy -max_muxing_queue_size 1024 輸出的MKV檔案路徑

ffmpeg-subtitle

我們還可以將字型檔直接封裝進MKV檔案中,讓ASS/SSA字幕軌能夠直接套用MKV檔案中內建的字型。指令如下:

ffmpeg -i 輸入的影音檔案路徑 -i 輸入的字幕檔案或含內封字幕的影片檔案路徑 -map 0:v -map 0:a -map 1:s:0 -scodec copy -attach OTF字型檔路徑 -metadata:s:3 mimetype=application/vnd.ms-opentype -attach TTF字型檔路徑 -metadata:s:4 mimetype=application/x-font-ttf 輸出的MKV檔案路徑

以上指令,利用FFmpeg的-attach參數可以添加檔案至輸出的MKV容器中,多個-attach參數可以添加多個檔案。-metadata:s:3 mimetype表示要設定第3軌(從0開始數,即第0軌─影片、第1軌─聲音、第2軌─字幕、第3軌─字型)的MIME Type,-metadata:s:4 mimetype表示要設定第4軌的MIME Type,依此類推。

FFmpeg固然好用,不過筆者會更建議使用MKVToolNix來操作MKV檔案。