export-final
組裝最終檔案。引數:$project slug,若使用者需要第二個交付成果,$platform 會覆蓋 output.platform。完整的請求在 $ARGUMENTS 中。空的 $ 佔位符表示此技能是自動觸發而非透過斜線呼叫:從會話上下文的 PIPELINE_STATE 中選取專案,並說出你選了哪一個。指令名稱遵循建構合約;python engine/ve.py --help 為最終依據。
已確立的渲染架構
- 影片:每個分段使用相同的編碼參數,從 IDR 框架開始,產生快取化的 MP4/MKV,然後以
-f concat -safe 0 -c copy拼接。經驗證為無損且近乎即時。 - 音訊:對整個時間軸進行一次連續通過,輸出為
pcm_s24le。絕不對每個分段進行快取。 - 僅混成一次,AAC 編碼恰好執行一次。
不要在匯出時重新設計此架構。特別是,不要將其「簡化」為單一的 filter_complex 跨越所有分段:一個 150 個分段的圖形大約有 19k 字元,而約 260 個分段會溢位 Windows 命令列,產生無法啟動的程序而不是有用的錯誤訊息。同時這也會丟棄每個分段的快取,而快取正是第二次匯出只需幾秒鐘的原因。
篩選圖表一律寫入檔案,並以 -/filter_complex fc.txt 形式傳遞。無條件執行,不僅是在圖形很長的時候。
步驟 1 - 預檢
在編碼任何內容之前:
- 執行 qc-pass。對一個未通過 QC 的專案進行匯出,會浪費管線中最長的操作。
- 確認
output.platform。它決定了響度目標、解析度以及字幕安全區域。如果$platform與output.platform不同,不要默默修改專案 —— 而是渲染第二個輸出路徑,並說明哪個是哪個。 - 報告計畫:分段數量、預期總幀數、預期時長、編解碼器,以及此通道是否正在燒錄字幕與圖形。
步驟 2 - 渲染分段
python engine/ve.py render $project
在 .cache/seg/ 下按分段進行快取,鍵值依據來源強鍵、入/出/出幀、篩選器、編碼器與工具版本而定。僅有變更的分段會重新渲染。使用 --only seg_0012 可渲染單一分段供檢查。
編碼器預設值:h264_nvenc、cq 20、preset p6。這張 Ada 顯示卡上的 NVENC 與 libx264 的 VMAF 大致相當 —— 在 2 Mbps 時落後 0.19 VMAF,在 8 Mbps 時領先 0.06 —— 同時速度快 2-4 倍。對於預覽來說是正確的預設值,對於最終成品來說也是可辯護的選擇。僅在使用者要求每 bit 最高品質且願意等待時才切換到 libx264。
兩個編碼器在此機器上每次執行都是位元重現的,這正是內容定址分段快取安全可靠的原因。
步驟 3 - 拼接,但先保護它
concat_compatible() 在每次 -c copy 拼接前都必須執行,毫無例外。 如果參數不匹配,拼接分離器會給你一個損壞的檔案,並返回 exit 0 —— 沒有警告,沒有錯誤,一個播放十秒後就崩潰的檔案。QC 檢查 (c) 就是這個檢查。
它會比較每個分段的解析度、像素格式、編解碼器、設定檔、level、時間基準、取樣率與通道佈局。不匹配表示某個分段使用了不同的參數渲染 —— 通常是因為編碼器設定變更後,快取仍然陳舊。應重新渲染有問題的分段,而不是強制拼接。
步驟 4 - 音訊與響度
python engine/ve.py render $project
然後對平台目標進行雙通道 loudnorm,目標來自 output.loudnorm(YouTube:I -14,TP -1.5,LRA 11;其他平台不同,位於 presets/formats/ 中)。
通道 2 必須帶有明確的 -ar 48000。 缺少此參數時,輸出會默默變成 192 kHz —— loudnorm 的內部取樣率會洩漏到輸出中,檔案大小是預期的四倍,且某些播放器會對其進行錯誤的重取樣。這是整個鏈中最常被忽略的旗標。
使用雙通道而非單通道:單通道 loudnorm 是動態估計值,在背景音樂安靜的開頭素材上會偏離目標一個分貝或更多,而這正是每個有背景音樂的 talking-head 影片的特點。
步驟 5 - 僅混成一次
步驟 2 到 5 都是 ve render $project:它會渲染或重用快取的分段,進行拼接,一次性渲染音軌,進行響度正規化,然後將 AAC 320k 恰好混成一次,輸出至 projects/$project/out/final.mp4(根據 output.path)。
在混成步驟不要重新編碼影片。如果需要修改畫面,應在分段層級進行變更,其餘由快取處理。
混成之後,ve render 會合成渲染的疊加層,然後如果 captions.burn_in 為 true 則燒錄 ASS 字幕 —— 依此順序,因此字幕會位於圖形之上。兩者都會重新編碼母帶,這就是為什麼 ve gfx 和 ve captions 是你在 ve render 之前 而不是之後執行的事情。在之後執行會導致母帶落後一個版本,且沒有任何警告。
ve export 是另一個後續步驟:它會執行完整的 QC,若失敗則拒絕(除非傳遞 --force),然後蓋上日期戳記的交付複本,並在旁邊寫入一個 .manifest.json 檔案。
步驟 6 - 驗證交付檔案,然後交付
對實際輸出檔案(而非計畫)執行強制性檢查:
- 幀數等於已啟用分段的
(出幀 - 入幀)總和。QC (a)。 - 音訊採樣數等於
幀數 / fps * 48000。QC (b)。 ebur128整合響度在平台目標的 0.5 LU 範圍內,真實峰值低於上限。QC (f)。- 容器、解析度、幀率與時長符合
output。 - 抽查三幀:第一幀、中間的一個分段邊界、最後一幀。邊界處的黑幀表示某個分段渲染過短。
然後報告:輸出路徑、檔案大小、時長、測量到的 LUFS 與真實峰值、幀數、分段數量以及來自快取的分段數量。將 stage 設定為 "export"。
二次交付
垂直裁切並非對已完成檔案進行重新裁剪。它是不同的 output.platform,意味著不同的響度目標、不同的字幕預設集以及不同的安全區域,而且通常需要不同的故事傳遞方式。請明確說明這一點,而不是對 16:9 母帶進行縮放。
失敗模式
| 症狀 | 原因 | 修復方式 |
|---|---|---|
| 輸出播放一段後中斷,ffmpeg 以 exit 0 退出 | 拼接時參數不匹配 | 每次拼接前執行 concat_compatible();重新渲染有問題的分段 |
| 母帶為 192 kHz | loudnorm 通道 2 缺少 -ar 48000 | 加入該參數並重新執行通道 2 |
| 編碼程序無法啟動 | 篩選圖表寫在命令列上 | 一律寫入 fc.txt 並傳遞 -/filter_complex |
| 響度偏離目標一個分貝 | 單通道 loudnorm | 使用雙通道 |
| 每次匯出都變慢 | 快取因編碼器設定變更而失效 | 這是預期行為;確認該設定變更是有意的 |
| 剪輯處出現黑幀 | 分段渲染過短 | 重新渲染該分段;檢查 QC (a) |
| 最終影片中聲音比預覽時小 | amix 缺少 normalize=0 | 在音訊圖表中修復,重新渲染音訊 |