一條進來的源流要變成幾十個檔案:多個碼率、多個解析度、可能多個 codec、再乘以 HLS 與 DASH 兩種清單。這個「一變多」的過程是直播成本結構裡最大的計算支出,也是畫質的第二道關卡——源流再好,轉碼階梯設計錯了,多數觀眾看到的仍然是糟糕的畫面。
📖 學
一、三個常被混用的詞
Transcoding(轉碼)——解碼再重新編碼,可以換 codec、換解析度、換碼率。計算成本最高。
Transrating(轉碼率)——只改碼率,解析度與 codec 不變。比完整轉碼便宜,但仍需解碼重編。
Transmuxing/repackaging(轉封裝)——不碰壓縮資料,只把同樣的編碼位元流換一個容器(例如 RTMP 的 FLV 換成 fMP4 分片)。計算成本極低,畫質無損。
實務上最重要的是認出哪些工作其實只需要 transmux。 把一條 1080p H.264 的源流同時輸出 HLS 與 DASH,如果用 CMAF 共用分片,這件事完全不需要重新編碼——它是 transmux。很多系統在這裡做了不必要的轉碼,白燒計算成本又損失畫質。
二、ABR 階梯怎麼設計
階梯(ladder)是一組 (解析度, 碼率) 的組合。一個傳統的固定階梯大概長這樣:
| 階 | 解析度 | 碼率 | 目標觀眾 |
|---|---|---|---|
| 1 | 1920×1080 | 5,000 kbps | 固網/高速行動 |
| 2 | 1280×720 | 2,800 kbps | 一般寬頻 |
| 3 | 854×480 | 1,400 kbps | 行動網路 |
| 4 | 640×360 | 800 kbps | 弱網 |
| 5 | 426×240 | 400 kbps | 極弱網/保底 |
設計原則:
相鄰階的碼率比控制在 1.5–2 倍。 太近(1.2 倍)等於浪費一階的計算與儲存,觀眾感受不到差別;太遠(3 倍以上)切換時畫質跳變明顯,而且中間頻寬的觀眾被迫選低的那階,浪費可用頻寬。
最低階必須真的能在最差網路跑。 它的作用是「不要黑畫面」,不是好看。
最高階不要超過源流品質。 把 1080p 源流上轉成 4K 階只是浪費,畫質不會變好。
階數要考慮成本。 每多一階就多一份轉碼、儲存與(對 LL-HLS 而言)請求量。低延遲場景通常刻意減少階數,見 ABR 與延遲的交互。
三、Per-title / 內容感知編碼
固定階梯的問題是它假設所有內容的複雜度相同。一場靜態的講座與一場賽車,在 2,800 kbps 下的品質天差地遠:講座可能用 1,200 kbps 就夠了(多花的頻寬純屬浪費),賽車可能 5,000 kbps 還在崩。
Per-title encoding 的作法是先分析內容複雜度,再為這個內容客製階梯。更細的版本是 per-shot/per-scene,以鏡頭為單位調整。
對直播而言,per-title 有一個根本限制:你沒有「整個內容」可以先分析。 點播可以先跑一遍再決定,直播不行。實務上的替代方案是:
- 以節目類型預設不同階梯(體育一套、談話一套、遊戲一套),這是最簡單也最常見的。
- 滾動視窗分析:用剛過去的幾秒估計複雜度,動態調整碼率上限。這有效但引入延遲與不穩定性。
- 接受浪費:在多數規模下,per-title 省下的頻寬未必抵得過系統複雜度。
所以 per-title 在直播的 ROI 明顯低於點播,而供應商常把點播的節省數字(18–22% 量級的說法流傳很廣)直接套用到直播上,這是一個需要警覺的高估,見 主張 vs 可佐證。
四、Packaging:把編碼結果變成可播的東西
打包器(packager)做幾件事:
- 把編碼位元流切成分片(必須在 I 幀邊界)。
- 包成容器(fMP4 或 TS)。
- 產生清單(
.m3u8/.mpd)。 - 套用加密(如果有的話)。
第 4 項是安全與打包的交界,也是成本影響最大的一處。 加密在打包階段做,意味著:
- 用 CMAF + cbcs 模式加密,同一份分片可以同時被 Widevine、PlayReady、FairPlay 解密 → 只需要打包一次。
- 用舊的分流做法(DASH 用 cenc、HLS 用 SAMPLE-AES),就必須為 FairPlay 單獨打包一份,儲存與 CDN 快取效率都減半。
這是 CMAF 對內容保護最實際的貢獻,詳見 內容保護基礎。
五、轉碼放哪裡:源站 vs 邊緣
集中轉碼(源站)——一個地方轉完,分發出去。簡單、可控,但跨區域的分發距離長。
邊緣轉碼——在靠近觀眾的地方轉。可以省跨區頻寬,但同一個轉碼工作會在多個邊緣重複執行,計算成本乘上區域數。
判準是「轉碼成本 vs 跨區頻寬成本」的比較。多數情況下集中轉碼 + CDN 分發更划算,因為 CDN 的跨區傳輸已經高度優化。邊緣轉碼主要用在需要個體化的場景——例如逐會話的浮水印,那必須在靠近使用者的地方做,而且它的成本模型完全不同(從「每條流一次」變成「每個觀眾一次」),這是 案例拆解 裡一個關鍵的成本警告。
六、一個實際的轉碼成本直覺
假設一條 1080p 源流要出 5 階 ABR:
- 1080p 的即時 H.264 編碼,軟體(x264 medium)約需 2–4 個現代 CPU 核心。
- 五階合計(1080p + 720p + 480p + 360p + 240p),低解析度便宜得多,總計約 4–8 核。
- 硬體編碼(NVENC)可以把這個降到單張卡跑數十路。
所以「要不要用硬體編碼」在規模化時不是品質問題而是數量級問題。 一千路併發的轉碼,用軟體要數千核,用硬體要數十張卡。
🧠 記
先認出哪些工作只需要 transmux,不要做不必要的轉碼。
相鄰階碼率比 1.5–2 倍;最低階負責「不黑畫面」,最高階不要超過源流。
per-title 在直播的 ROI 明顯低於點播,因為沒有完整內容可先分析。
CMAF + cbcs 讓一份分片服務三家 DRM,這是打包階段對成本影響最大的決定。
逐會話個體化(浮水印需要)會把成本模型從「每條流」變成「每個觀眾」,必須單獨計算。
✍️ 實踐
用 FFmpeg 產一組 ABR 階梯並檢查分片邊界,約 30 分鐘:
ffmpeg -re -i input.mp4 \
-filter_complex "[0:v]split=3[v1][v2][v3]; \
[v1]scale=1920:1080[v1out];[v2]scale=1280:720[v2out];[v3]scale=854:480[v3out]" \
-map "[v1out]" -c:v:0 libx264 -b:v:0 5000k -maxrate:v:0 5350k -bufsize:v:0 7500k \
-map "[v2out]" -c:v:1 libx264 -b:v:1 2800k -maxrate:v:1 2996k -bufsize:v:1 4200k \
-map "[v3out]" -c:v:2 libx264 -b:v:2 1400k -maxrate:v:2 1498k -bufsize:v:2 2100k \
-x264-params "keyint=48:min-keyint=48:scenecut=0" \
-map a:0 -c:a aac -b:a 128k -ac 2 \
-f hls -hls_time 2 -hls_playlist_type event \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
stream_%v.m3u8然後做兩件檢查:
cat stream_0.m3u8,確認#EXT-X-TARGETDURATION與實際#EXTINF一致。- 把
keyint改成 100(大於 2 秒 × fps)再跑一次,觀察分片長度會變得不受控——因為切不到 I 幀。
第 2 步是重點:它讓「GOP 必須整除分片長度」從一條規則變成親眼看過的現象。
🔗 延伸學習
- Unified Streaming — DRM 文件——打包器視角的加密設定,把 cenc/cbcs 與各家 DRM 的對應關係寫得很具體。
- Fora Soft — CMAF: The Packaging Format That Unified HLS and DASH——CMAF 的動機與實際節省;屬於供應商級資料,數字宜自行驗證。