對話式影片字幕
概述
字幕是其獨立的層:它承載每個口語單字,絕不依賴畫面中已有的內容。畫面中的事物標籤(零件名稱、優缺點、箭頭)是不同的圖層,應使用不同的視覺語言(物件旁的標註);切勿因為「畫面已顯示」而從字幕中刪除任何單字。
流程:words.json + forbid.json(字幕不得覆蓋的區域) + config.json + 設定檔
→ plan → manifest.json(標準資料) → burn(燒錄預覽 = 視覺真相) / export srt|ass|vtt → validate。
格式角色(請勿混淆):
| 格式 | 承載內容 | 不承載內容 |
|---|---|---|
manifest.json | 單字、時間、佈局、placement、已接受重疊、含原因的上移、渲染檢查:資料真相來源 | 像素 |
.srt | 文字 + 時間 | 粗細、顏色、輪廓、作用中單字、位置。SRT 中絕不承諾樣式 |
.ass | 字體系列 + 粗體/\b700、轉換為 libass 指標的字體大小、輪廓、背景框、每個時間片段的作用中單字、位置 | 淡入淡出;需要字體:subtitles=x.ass:fontsdir=fonts |
.vtt | ::cue CSS(字體系列、粗細、透過 text-shadow 的輪廓、背景)+ 每個時間片段的類別 .active_<spk> / .em_<spk> / .dim / .u | 精確位置;頁面需使用 @font-face 載入字體 |
燒錄 preview.mp4 | 所有內容:唯一的視覺真相來源 | — |
使用時機
- 對話短劇、訪談、有旁白的解說影片:直式或方形,最多兩行。
- 您已有單字時間軸(或音訊:可選用環境金鑰的雲端 STT),且知道人臉 / 手部 / 關鍵道具位置(方框;對於 3D 場景,渲染單色遮罩並框選)。
- 不適用於歌詞影片(刻意不支援彈跳、縮放的單字)。
演算法
分段(設定檔中的 chunk):暫停超過 pause_s(0.35 秒)、句子結尾、說話者變換時強制斷開;當一個區塊已有 2 個以上單字時,逗號處軟斷開;受 max_words、像素寬度(安全區的 max_width_frac)和 max_dur_s(約 1.2 秒的語音閱讀效果良好)限制。區塊絕不結尾於功能詞(не、в、а、and、the…):該詞會移至下一個區塊。若同句中的相鄰區塊可容納單一單字,則合併。單字時長被限制為中位數的 2.5 倍,以免單字懸掛在停頓中。時間:一個單元在其第一個單字前 ≤ 50 毫秒出現,不切斷前一個單字,在其最後一個單字後停留 hold_s,至少 min_show_s。
放置 — placement: {mode: fixed_bottom_center, collision_lift: false}(對話預設)
- 整個影片使用一條基線:
baseline = safe.bottom - baseline_margin_px(或明確設定)。每個單元在其上底部對齊(y + h = baseline)並在畫面上置中(x + w/2 = W/2)。沒有任何移動:無上移、無橫移、無依說話者 x 偏移。行寬受限制,使置中行保持在安全區內。 - 在基線處與禁止框交錯的行保持原位:該單元會獲得
overlap_accepted: [classes],QA 工作表會繪製黃色框「重疊已接受(固定基線)」。這是資訊,不是失敗。與平台 UI 交錯仍是錯誤(縮小字體或拆分片語)。 - 選項
collision_lift: true(模式baseline_lift):說話者下方的 x(align: speaker)或置中並有左/右備用;若每個 x 都交錯,則以整個lift_step_px步長上移直至空閒。該單元會獲得lift = {px, reason: [在基線處命中的類別], t0, t1},清單會列出所有上移在collision_lifts中。無原因 → 無上移。僅在簡報要求不惜代價保持臉部清晰時使用。 - 絕不捨棄任何單字。
外觀。 輪廓(outline_px)+ 柔和陰影 + 淺色背景,其透明度僅提升到足以使最深色的亮色與其後像素的第 90 百分位數保持 ≥ 4.5:1(WCAG)的程度。說話者以作用中單字的顏色區分,並在混合/卡片模式中加上 4 像素的說話者顏色條;無對話氣泡、無厚重名牌。平靜的動畫:僅透明度淡入淡出,無縮放彈出、無垂直滑動。
QA(scripts/validate.py,也可由 demo 執行):
- 結構:manifest 與
templates/manifest.schema.json比對; - 行數 ≤ 2;
- 放置:在
fixed_bottom_center中,所有單元的 y 基線和 x 中心擴散為 0(0.5 像素容差),且無上移;在baseline_lift中,每個上移都在網格上、有原因,且該單元在基線處確實交錯; - 在每一幀上與平台 UI 零重疊;禁止框:
baseline_lift中為 0,fixed_bottom_center中報告為overlap_accepted(資訊); - 每個單字恰好一次、按順序、說話時可見;
- 對比度 ≥ 4.5 且無彈跳,兩者均由
burn逐幀測量; - 字體解析:檔案存在、Pillow 系列和樣式、OS/2 粗細、
fc-scan,以及 libassfontselect選取宣告的檔案和粗細; - 像素:在燒錄幀以及 ASS 的 libass 渲染上,作用中顏色存在,字形底部在佈局的 3 像素內,字幹寬度在宣告粗細的參考點陣圖的 1 像素內,且輪廓在
outline_px的 1 像素內。
設定檔(profiles/*.json)
| 設定檔 | 內容 | 最佳用途 |
|---|---|---|
karaoke | 一次 2–4 個單字,說話中的單字為說話者顏色,其餘暗淡 | 最穩定;固定行、解說影片 |
reveal | 單字在說話時淡入;佈局預先固定;≤ 2 行 | 平靜的旁白 |
cards | 每張卡片一個想法(≤ 8 個單字,2 行),密集面板,關鍵字著色 | 緩慢、可引用的台詞;比說話提前閱讀 |
kinetic | 一次一個記號,較大字體 | 僅限重點句;上下文少 |
hybrid(預設) | ≤ 3 個單字,單字淡入,在說話中的單字下方加底線,強調色,說話者條 | 對話 |
研發系統的選項作為參數:tempo = chunk.max_dur_s: 1.2 + timing.min_show_s: 0.83(hybrid 中啟用);stress = emphasis: "energy"(從 --audio 計算的每個說話者單字響度 z 分數),或 "keyword" 搭配 keywords 清單。
指令
python -m subkit demo examples/fixture # 5 種設定檔 + hybrid_lift -> 預覽、srt/ass/vtt、validation_report.{md,json}
python -m subkit plan --words W --forbid F --config C [--profile hybrid] [--audio A] -o manifest.json
python -m subkit burn manifest.json --forbid F --video in.mp4 [--audio A] -o preview.mp4 --qa qa.jpg
python -m subkit export manifest.json --format ass -o captions.ass # srt | ass | vtt
python scripts/check_clean.py # 提交前:無 media/keys/abs 路徑
ELEVENLABS_API_KEY=... python -m subkit stt audio.wav -o words.json # 可選;或 --provider groq 搭配 GROQ_API_KEY
陷阱
- libass ≠ Pillow 字體大小。 libass 以 OS/2 winAscent+winDescent 調整大小,並將基線放置在行頂部下方 winAscent 處;匯出會轉換兩者,否則 ASS 文字會縮小約 35%、變細且位置更低。
- ASS 中的可變字體會回退到預設實例(通常為 Regular)。請提供您使用的粗細的靜態實例(此處為
Onest-Bold.ttf,700)並傳遞fontsdir。 ffmpeg -ss在-i之前會重設時間戳:字幕篩選器隨後會渲染 t=0。在燒錄 ASS 時,請在-i之後搜尋。\k/\kf卡拉 OK 以厘秒為單位,並永久為每個說話中的單字著色;若要「僅當前單字」,請發出時間片段(如匯出所做的那樣)。- SRT 沒有樣式:如果交付物需要粗細或強調,請提供 ASS/VTT 或燒錄影片。
- 浮動行(依說話者 x、遲滯、「看起來更好」的上移)在對話中會看起來像抖動。請保持預設固定模式;在
baseline_lift中,驗證器會重新檢查每個上移是否確實交錯。 - 對比度是根據亮色與其後最亮 10% 像素(而非平均值)來判斷:火焰、雪地和亮點會導致平均值失敗。
- 請勿捨棄已在畫面上繪製的單字。請將已繪製的標籤移至註釋層。
templates/safe_zones.json中的安全區僅為近似值;平台 UI 會變化,因此請在發布前重新檢查。
檢查清單
- words.json 涵蓋整個語音(雲端 STT 或強制對齊器);說話者已標記
- forbid.json:人臉、手部、火焰/道具(每個鏡頭)+(
align: speaker的speakers框) - config:尺寸、fps、
safe_zone、說話者顏色(不同的色相,兩者在背景上均 ≥ 4.5:1) -
plan→ manifest;閱讀overlap_accepted(固定)或collision_lifts(上移模式,每個都有實際原因) -
burn→ 查看 QA 工作表(青色 = 基線,黃色 = 重疊已接受,橙色 = 含原因的上移)以及實際幀 -
validate全部 PASS;提供燒錄影片(如果播放器能渲染,則加上 ASS/VTT;SRT 僅作為純文字)