Skip to content
White's Tech Notes
Go back

hyperframes render 多 worker 會在 worker 邊界掉幀

MediaEdit page

問題

用 npx hyperframes render(預設 4 workers)渲染一支 109 秒的直式影片,成品在 27.3s 與 81.8s 各出現約 0.3 秒的黑閃——背景圖整片消失,但疊在上面的 HUD、對話框、角色立繪都還在。

麻煩的是這種缺陷很難驗出來:

  1. ffmpeg blackdetect 完全抓不到。那幾幀因為 UI 圖層還在,整體亮度不夠低,全片掃描只回報片尾正常的黑幕。
  2. 抽幀抽不到。0.3 秒只有 9 幀,除非剛好抽在那個區間。這次是抽場景切換後的檢查幀才誤打誤撞撞上。
  3. 一度誤判成抽幀假象。ffmpeg -ss 27.5 -i file 是 input seek(快但不精確),懷疑是解碼出不完整的幀;改用 ffmpeg -i file -ss 27.5(output seek,精確)重抽,結果一樣黑,才確定是影片本身的問題。

原因

異常區段的起始幀是 818 和 2454。全片 3270 幀 ÷ 4 workers ≈ 817,所以 818 和 2454 正好是 worker 2 與 worker 4 的接手點。

worker 接手後的前幾幀,背景圖還沒載入完成(或 GSAP 還沒把 timeline seek 到定位)就開始截圖,於是只截到 UI 圖層。worker 3 的邊界 1635 也在,只是剛好落在一個本來就很暗的場景,肉眼與數值都看不出來——沒報錯不等於沒發生。

解法

偵測:只量背景區域的逐幀亮度

避開固定不動的 UI 圖層(這支影片是頂部 HUD 180px、底部對話框 540px),只 crop 中間的舞台區:

ffmpeg -i renders/output.mp4 \
  -vf "crop=1080:1200:0:180,scale=16:16:flags=area,signalstats,metadata=print:key=lavfi.signalstats.YAVG:file=yavg.txt" \
  -an -f null -

再用 python 掃 yavg.txt,找「比前一幀驟降且持續數幀」的區段。

兩個關鍵細節:

  • scale 一定要加 flags=area。預設 bicubic 把 1080x1200 降到 16x16 取樣不準,正常的夜景也可能回報極低亮度,會誤導判斷。
  • 門檻不能設太嚴。第一次用「低於前後鄰居的 45%」掃全片,回報「無異常」;實際掉幀是 56 → 28.13,比值 0.502 剛好被濾掉。放寬到 75% 才抓到。

判讀訣竅:掉幀區段的 YAVG 值會完全相同(連續 9 幀都是 28.13),因為是同一張畫面重複;正常畫面只要有 Ken Burns 之類的緩動,每幀數值都會微幅變動。

修正:單 worker

npx hyperframes render --workers 1

沒有 worker 邊界就沒有這個問題。代價很小:這支影片從 2m30s 變成 3m11s,只慢 40 秒,重掃已無異常。

關鍵洞察

平行渲染的接縫是缺陷的高發區,而且缺陷會剛好長成自動化檢查看不見的樣子。

blackdetect 這類現成工具假設「壞掉 = 整幀變黑」,但實際壞掉的只是其中一個圖層。當畫面是分層合成的,就要針對會變動的那一層單獨量測,而不是量整幀的統計值——固定不動的 UI 圖層會把訊號稀釋掉。

另一半的教訓是關於驗證本身:第一次掃描回報「無異常」時差點就此收工,但那個結論其實是門檻參數的產物,不是事實。當自動檢查與肉眼觀察衝突時,先假設是檢查方法有問題,把原始數值印出來看,而不是相信那句「無異常」。



Previous Post
SQLite FTS5 trigram 搜不到兩個字的中文詞
Next Post
bash 全形標點緊接變數會被吃進變數名,set -u 下讓整個函式靜默不執行