# [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`