影片中文字幕 — 翻譯與內嵌
將已存在於磁碟上的英文影片產生簡體中文硬字幕版本,並附帶相符的 SRT 字幕檔。
下載功能刻意不包含在內。請假設來源 MP4 檔案已經準備好。
此處理流程與主題無關 — 它最初是基於一部 22 分鐘的 Apex 身法影片建立,但腳本中沒有任何部分會知道或關心影片內容是什麼。每個影片會變動的是詞彙表和字幕帶的位置。
好的輸出看起來像什麼
使用此功能的人在意一種特定、已確定的外觀。這些不是每次都要重新考慮的預設值 — 它們是透過反覆迭代真實輸出結果而得出的,若未經告知就加以更改將視為回歸問題:
- 僅限簡體中文。 絕對不要混入繁體中文。交付前請確認。
- 每個字幕永遠只有一行。 雙行字幕是最常見的投訴。如果一行太長,應分割成兩個連續的字幕提示 (cue),而非使用換行。
build_srt.py會強制執行此規則。 - 字幕要簡短。 「一行」不代表可以是一行很寬的文字。目標是渲染後寬度不超過約 1100 像素 (在 1080p 畫面中約佔 57%)。
- 沒有背景框。 白色文字,硬邊深色描邊,柔和深色陰影。
- 思源黑體 Bold (內建於
assets/NotoSansSC-Bold.ttf)。直立且粗重,擁有強烈的拉丁字形 — 此類影片充滿了中文句子中夾雜的英文術語,而裝飾性字體無法妥善處理這種情況。 - 社群實際上用英文說的術語就保留英文。 哪些術語屬於此類是因主題而異的問題,而詞彙表正是用來回答這個問題的。
- 內嵌的章節卡 (chapter cards) 要在其下方加上中文行,而非上方。
工作流程
1. 探查來源檔案,並挑選詞彙表
ffprobe -v error -show_entries format=duration -show_entries stream=codec_type,codec_name,width,height,r_frame_rate -of default=nw=1 source.mp4
精確記錄持續時間和幀率 — 稍後的每個步驟都依賴於它們。
然後判斷影片內容,並閱讀 references/glossaries/README.md,它會引導你到正確的檔案,並說明要閱讀其哪個章節。在開始翻譯之前,請完整閱讀對應詞彙表的字幕使用原則章節 — 它很短,但包含了該遊戲的慣例。
內建詞彙表:Apex Legends、Warframe、osu!、Minecraft 速通/MCSR、StarCraft 星海爭霸、Counter-Strike 反恐精英、ARC Raiders。
如果此影片沒有對應的詞彙表,這是正常情況。 請根據可驗證的官方簡體中文名稱進行翻譯,保留你必須決定的術語清單,並在最後交付該清單。如果某個術語沒有官方中文名稱,請使用描述性翻譯,並說明這並非官方名稱 — 不要將猜測當作既定事實。切勿為已有名稱的事物發明新名稱。
2. 取得附帶時間戳的英文逐字稿
如果影片來自 YouTube,其自動產生的字幕是可用的基礎:yt-dlp --write-auto-subs --sub-langs "en.*" --skip-download。它們是滾動式字幕,帶有逐字時間標記,因此需要將它們去重整合為句子片段。
自動字幕會嚴重扭曲專業術語,你必須在翻譯時修復它們。 ASR 是根據通用英語模型進行語音轉錄,因此每個非常見單詞的領域術語都會以一個看似合理的錯誤單詞返回。來自 Apex 身法影片的真實例子:「forward rez/raft/raz」→RAS,「Neor strafe」→Neo strafe,「pedo strafe」→Pito strafe,「mantel boost」→mantle boost,「alerts」→lurches,「my VO was so high」→my velo (velocity),「I couldn't attach out of that」→couldn't tap-strafe out of that。在任何術語密集的影片中都預期會出現此類錯誤 — 詞彙表能幫助你辨識它們。
如果語音確實無法還原 — 例如音樂插曲、重疊的喊叫聲 — 請為該片段保留空的 zh 欄位以將其刪除,並告知使用者你刪除了哪些時間戳。編造一個看似合理的句子比完全沒有字幕更糟糕。
3. 翻譯成分段 JSON
[{"i": 1, "start": 0.24, "end": 4.90,
"en": "Seeing movement players pull off tricks like these is super cool and all, but",
"zh": "看身法玩家秀出這種操作確實很酷,但真正的問題是"}]
保留 en 欄位 — 它不是裝飾用的。build_srt.py 會用它來判斷一個句子是連續的還是獨立的話語,從而決定是否合併兩個提示,這可以防止出現像「算了好」或「是,長官你好啊」這樣的連寫錯誤。
4. 建立 SRT 檔案
python scripts/build_srt.py segments.json sub.srt --font assets/NotoSansSC-Bold.ttf
它會列印一份報告。請將非零的 overlaps、multiline、latin_cjk_runons 或 term_split_across_cues 視為需要在編碼前修正的錯誤。少量的 under_0.35s 提示如果只是 1–3 個字的感嘆詞則可以接受 — 請檢查它們,不要直接忽略。
5. 尋找並翻譯內嵌的章節卡
python scripts/find_chapters.py source.mp4
創作者通常會將章節卡燒錄 (burn) 到影片中,而不是使用 YouTube 章節功能,因此中繼資料中可能沒有顯示。此腳本會報告候選視窗;從每個視窗中擷取一個幀,並在撰寫翻譯前閱讀實際的卡片文字。輸出 chapters.json:[{"start":42,"end":46,"zh":"第 1 章:定義 lurch 組合"}]。
6. 檢查字幕可能與畫面內文字重疊的位置
結尾卡通常是肇事者 — 位於正常位置的字幕會蓋在創作者的社交媒體資訊上。擷取一個幀,找到空白區域,並宣告如下:
[{"from": 1334.0, "to": 100000, "bottom": 820}]
預設字幕帶位於典型的 FPS HUD 上方。不同的遊戲或非遊戲畫面可能會將其自身元素放在該處 — 例如 MOBA 的小地圖、節奏遊戲的判定線、談話影片的下三分之一處。在接受預設值之前,請擷取一個幀並觀察。
7. 建立疊加層並進行編碼
python scripts/build_overlay.py sub.srt ov --font assets/NotoSansSC-Bold.ttf \
--duration 1354.351 --chapters chapters.json --avoid avoid.json
python scripts/burn_in.py source.mp4 ov/concat.txt out.mp4
檢查疊加層報告的漂移 (drift) 是幾毫秒,而不是幾百毫秒。
在開始約 20 分鐘的編碼之前,先在 PIL 中將一個疊加層 PNG 合成到真實影格上並查看效果。這只需要幾秒鐘,但能捕捉到位置和字型錯誤,否則這些錯誤會在 20 分鐘後才顯現。
8. 驗證
python scripts/verify.py out.mp4 --expect-frames <frames> \
--contact-sheet sheet.jpg --at 75 300 660 945 1340
查看聯絡表。確認:單行、在明亮影格上清晰可讀、章節行位於其卡片下方、沒有與 HUD 或結尾文字重疊。
9. 後續修正 — 拼接,不要重新編碼
當使用者要求更改幾行時 (他們一定會),請重新建立 SRT,與前一個 SRT 進行差異比對,找出哪些提示移動了,然後:
python scripts/splice.py out.mp4 source.mp4 sub.srt out_fixed.mp4 \
--font assets/NotoSansSC-Bold.ttf --change-from 310 --change-to 316 \
--duration 1354.351 --chapters chapters.json --avoid avoid.json
python scripts/verify.py out_fixed.mp4 --expect-frames <frames> --seams 310 316
只需 15 秒,而不是 20 分鐘。影格計數必須完全相同。
交付成果
連同 out.mp4,一併交付 SRT 檔案 (對話加上章節行,已合併並重新編號),以便日後不需重新進行所有工作即可編輯字幕。同時提供一個中文標題和描述 — 如果影片是轉載,請指出原始的第一人稱描述暗示了作者身份,並且音樂歸屬區塊應保留其原始英文,因為授權條款要求該確切形式。
如果你必須決定不在詞彙表中的術語,請列出它們。一次決定並記錄下來的術語,比下次用不同方式做出的相同決定更有價值;references/glossaries/README.md 說明了如何將這樣的清單轉變為詞彙表檔案。
參考資料
references/glossaries/README.md— 應該閱讀哪個詞彙表、閱讀其哪個章節,以及當影片沒有對應詞彙表時該怎麼做。請從這裡開始。references/glossaries/*.md— 詞彙表本身。檔案很大。請閱讀原則章節及相關章節;使用 grep 搜尋个别術語。references/pipeline.md— 技術說明與此流程中的特定陷阱。在除錯任何看起來像是時間、拼接或渲染問題之前,請先閱讀此文件;這些問題大部分都已經被診斷過一次了。