# [FFmpeg] 烙印字幕至影像上 (Hardsub)
## 簡介
如果你的播放設備不支援字幕 (softsub, 也就是封裝在影片內的字幕) ,你就要重新編碼視訊將字幕烙印在畫面上 (hardsub),播放時一定有字幕,因為字幕是烙印在畫面上,只要有畫面就有字幕。
## 字幕篩選器
要將字幕烙印至影像上做成 Hardsub 必須使用到 libass (`subtitles` 篩選器),ffmpeg 的 configuration 如果含有 `--enable-libass` 則代表 libass 是可用的。
要將字幕烙印至影像上,必須要重新編碼視訊才可以,所以不能使用 `-codec:v copy` 、 `-c:v copy` 、 `-vcodec copy` 來複製視訊串流。注意,`subtitles` filter 只能指定輸入字幕檔名,無法指定路徑,所以必須將字幕檔放置在工作目錄下。
將 ASS 字幕做成 Hardsub:
```powershell
ffmpeg -input.mp4 -vf "subtitles=filename='sub.ass'" output.mp4
```
若輸入檔名為第一個選項,可以省略 `filename=`, `f=`:
```powershell
ffmpeg -input.mp4 -vf "subtitles='sub.srt'" output.mp4
```
從輸入影片內讀取第1個字幕 (`s:0`)做成 Hardsub:
```powershell
ffmpeg -input.mkv -vf "subtitles=input.mkv:si=0" output.mkv
```
如果需要強制指定字幕的樣式,可以先使用 Aegisub 在字幕內設定所需樣式幕並另存為 ASS 檔,再給 FFmpeg 處理。或者可以使用 `subtitles` 篩選器的 `force_style` 選項。
強制覆蓋字幕樣式:
```powershell
-vf "subtitles='sub.srt':force_style='FontName=Microsoft JhengHei,FontSize=20,PrimaryColour=&HAA00FF00'"
```
## 字體變形問題
若 subtitles 篩選器的輸入影像不是正方形像素(PAR 1:1),這會導致輸出字幕寬高比例錯誤。
假設 input.mkv 為 1280x720 [PAR 1:1 DAR 16:9] 轉成 704x480:
```powershell
ffmpeg -i input.mkv -vf "scale='w=704:h=480',subtitles='sub.srt'" output.mkv
```
input.mkv (1280x720 [PAR 1:1 DAR 16:9]) → scale (704x480 [PAR 40:33 DAR 16:9]) → subitles → output.mkv
由於 `scale` 的輸出與輸入解析度不同,將自動改變 PAR 使 DAR 與輸入相同為 16:9,這使 `subtitles` 的輸入像素寬高(PAR)比不是 1:1,輸出字幕將會得到錯誤的寬高比。
> 註:DAR = Width / Height * PAR
以下介紹三種解決方式...
### 指定字幕原始大小
使用 `subtitles` filter 的 `original_size` 參數指定影像解析度讓字幕寬高正常縮放。
承上,已知 `subtitles` 的輸入影像為 704x480 [PAR 40:33 DAR 16:9]
$$ 顯示寬度=480*16/9=853.333... $$
設定字幕原始大小 854x480:
```powershell
ffmpeg -i input.mkv -vf "scale='w=704:h=480',subtitles='sub.srt':original_size='854x480'" output.mkv
```
### 篩選器鏈順序
改變 `subitles` filter 順序使其輸入為正方形像素 (PAR 1:1) 的影像。
將 `subtitles` 移動到 `scale` 之前:
```powershell
ffmpeg -i input.mkv -vf "subtitles='sub.srt',scale='w=704:h=480'" output.mkv
```
input.mkv (1280x720 [PAR 1:1 DAR 16:9]) → subitles → scale (704x480 [PAR 40:33 DAR 16:9]) → ... 字體比例正常
### 編輯字幕
已知輸出字幕會被縱向壓扁,那麼只要編輯字幕先將字體橫向壓扁,如此一來之後被縱向壓扁後,字體寬高會變回正常。如果字幕是 ASS/SSA 格式,編輯字幕風格將 `ScaleX, ScaleY` 設為 `82, 100` 即可。
$$ 輸入 PAR =1/1 $$
$$ 輸出 PAR = (16 / 9) / (704 / 480) = 40 / 33 $$
$$ 反變形比值 = 輸入 /輸出 = (1 / 1) / (33 / 40) = 0.825 $$
將編輯後 ASS 字幕做成 Hardsub:
```powershell
ffmpeg -i input.mkv -vf "scale='w=704:h=480',subtitles='sub.ass'" output.mkv
```
## 以圖片為基礎的字幕
由於目前 `subtitles` filter 只能使用 ASS/SSA、SRT... 之類的文字字幕,若字幕為 "以圖片為基礎" 的格式,例如,Blu-ray 字幕 (`hdmv_pgs_subtitle`) 或 DVD 字幕 (`dvdsub`) 是以圖片為基礎的類型,你可以透過使用 `overlay` filter 將字幕覆蓋至影像上。
將 M2TS 內的視訊與字幕串流結合為一個視訊串流:
```powershell
ffmpeg -i input.m2ts -filter_complex "[0:v][0:s]overlay[v]" -map "[v]" -map 0:a -c:v libx264 -c:a copy output.mkv
```
假設 M2TS 檔案內有多個字幕串流,如果要挑選第二個字幕串流可以使用 "0:s:1" 這樣的串流說明符:
```powershell
ffmpeg -i input.m2ts -filter_complex "[0:v][0:s:1]overlay[v]" -map "[v]" -map 0:a -c:v libx264 -c:a copy output.mkv
```
###### tags: `ffmpeg`