議與多檔畫質(zhì):RTMP / SRT / WHIP 與 Simulcast)
上一篇講完架構(gòu)這一篇把鏡頭拉到鏈路的最底層**推流協(xié)議選型和多檔畫質(zhì)**。這兩個話題經(jīng)常被分開講但它們其實是同一件事的兩面協(xié)議決定了「丟包時怎么辦」編碼方式?jīng)Q定了「一次推流能出幾檔畫質(zhì)」而這兩者又共同決定了弱網(wǎng)下觀眾看到的是什么。我們先把三種主流推流協(xié)議的權(quán)衡機制講透再講清楚「多檔畫質(zhì)、服務(wù)端免轉(zhuǎn)碼」到底是怎么實現(xiàn)的。---## 一、先從「丟包怎么辦」看三種協(xié)議判斷一個協(xié)議適不適合互動直播最有效的角度不是背結(jié)論而是看它在丟包時做什么選擇。### RTMP繼承 TCP 的可靠有序RTMP 通常建立在持久 TCP 連接上消息被切成 chunk 并在多個 chunk stream 上復(fù)用控制命令和數(shù)據(jù)用 AMF 序列化音視頻消息承載對應(yīng)的編碼數(shù)據(jù)。RTMPS 是在 TLS 上承載 RTMP提供機密性和完整性但**不消除 TCP 的隊頭阻塞**。這套設(shè)計在它誕生的年代是合理的TCP 的可靠傳輸省去了協(xié)議自己處理丟包重傳的麻煩。但代價就是我們上一篇講過的隊頭阻塞——任何分節(jié)丟失后面已到達(dá)的數(shù)據(jù)都要排隊等它重傳。今天 RTMP 在生態(tài)里的位置已經(jīng)很單薄播放側(cè)因為瀏覽器不再原生支持 Flash 播放基本退場僅剩的價值是一些老舊推流工具只認(rèn)它。而即便是「推流入口」這層價值也在被 SRT 和 WHIP 取代。### SRT為弱網(wǎng)而生的現(xiàn)代化選擇SRT 建立在 UDP 之上面向不穩(wěn)定網(wǎng)絡(luò)中的低時延可靠傳輸。理解它要把三個機制分開- **ARQ自動重傳請求**接收端根據(jù)序列號發(fā)現(xiàn)缺包并發(fā)送 NAK發(fā)送端在數(shù)據(jù)仍有時效時重傳。它解決「怎么恢復(fù)丟包」。- **TSBPD基于時間的包交付**依據(jù)發(fā)送時間戳和協(xié)商的 latency 安排包何時交付吸收網(wǎng)絡(luò)抖動、恢復(fù)發(fā)送時序。它解決「何時交付」。- **過期包丟棄**啟用并滿足條件時放棄已來不及按計劃交付的數(shù)據(jù)。它解決「何時停止補救」。latency 這個參數(shù)給重傳和抖動吸收提供時間預(yù)算調(diào)大通常提高恢復(fù)機會、增加交付等待調(diào)小則相反。但它**不是整個 SRT 會話的嚴(yán)格數(shù)學(xué)時延上界**——握手、網(wǎng)絡(luò)排隊、應(yīng)用緩沖、斷線重連都在它之外。這也解釋了為什么 SRT 入庫的端到端時延通常比 WHIP 高它是「用延遲換弱網(wǎng)魯棒性」的有意取舍不是實現(xiàn)缺陷。### WHIP把 WebRTC 標(biāo)準(zhǔn)化成推流協(xié)議WHIP 本質(zhì)上不是全新的傳輸協(xié)議而是給 WebRTC 補上了一套標(biāo)準(zhǔn)化的「推流簽約流程」用 HTTP 完成 SDP offer/answer 交換媒體仍走 WebRTC 原生棧- **ICE** 負(fù)責(zé)打通網(wǎng)絡(luò)路徑含 NAT 穿透的地址協(xié)商- **DTLS-SRTP** 負(fù)責(zé)媒體鏈路加密注意若媒體在邊緣終止 SRTP 后重新加密轉(zhuǎn)發(fā)它是逐段保護(hù)不等于端到端加密- **RTP** 承載媒體配合 **NACK**選擇性重傳和可選的 **FEC**前向糾錯處理丟包擁塞控制動態(tài)調(diào)整發(fā)送碼率。WHIP 沒有 SRT 的 TSBPDRTP 接收端通常按**包數(shù)或字節(jié)數(shù)**維護(hù)重排歷史。這里有個容易搞混的點**包緩存數(shù)量不等于時間窗口**——同樣 512 個包在不同碼率、包長和幀率下覆蓋的時間完全不同不能由它直接推出播放等待時延。WHIP 已經(jīng)正式發(fā)布為 RFC 9725不再是草案。---## 二、三者橫向?qū)Ρ葇 維度 | RTMP | SRT | WHIP || --- | --- | --- | --- || 傳輸層 | TCP | UDP ARQ | UDP RTPNACK / FEC / 擁塞控制 || 丟包處理 | TCP 必須重傳并按序交付可能隊頭阻塞 | ARQ 恢復(fù)TSBPD 定時交付可丟棄過期包 | NACK/FEC 依協(xié)商與實現(xiàn)使用jitter buffer 和解碼截止策略決定是否等待 || 延遲邊界 | 無嚴(yán)格數(shù)學(xué)上界 | latency 是工程預(yù)算不是無條件端到端上界 | 動態(tài)緩沖與擁塞控制無無條件數(shù)學(xué)上界 || 加密 | 本身無加密RTMPS 用 TLS | 可配置 AES payload 加密 | 強制 DTLS-SRTP 鏈路加密不自動等于 E2EE || 瀏覽器原生支持 | 已不支持 | 不支持 | 原生支持 || 典型定位 | 歷史遺留正在退出 | 弱網(wǎng)上行的現(xiàn)代選擇 | 主流實時推流/播放協(xié)議 |結(jié)論不是「誰打敗誰」而是**它們沒有脫離實現(xiàn)與網(wǎng)絡(luò)條件的數(shù)學(xué)延遲上界。**「TCP 不好、UDP 好」這種粗線條判斷會漏掉真正的工程重點——丟包時的取舍策略。---## 三、工程上怎么選統(tǒng)一信號差異化處理一個務(wù)實的做法是讓 WHIP 和 SRT **共存**服務(wù)不同場景- 網(wǎng)絡(luò)干凈、追求最低延遲時優(yōu)先 **WHIP**- 上行不穩(wěn)定、需要更強魯棒性時用 **SRT**用一點延遲換可靠性。兩者的原生統(tǒng)計口徑并不等價SRT 有 loss / retrans / drop / too-late 等RTP 側(cè)是序列號缺口 / NACK / RTX / FEC所以不能把兩邊的計數(shù)器直接套進(jìn)同一個公式。正確做法是**在接收端按統(tǒng)一采樣窗口、原包身份、恢復(fù)結(jié)果和播放 deadline 派生產(chǎn)品指標(biāo)再驅(qū)動同一套降級決策。**降級動作分兩步代價從低到高1. **先降編碼碼率**實時生效不中斷推流2. **碼率降到底仍不達(dá)標(biāo)才降分辨率**砍同播層數(shù)需要重啟推流有短暫中斷。背后的邏輯很直接調(diào)碼率零代價可以頻繁觸發(fā)調(diào)層數(shù)有中斷代價只有在「壓到底都不夠」時才動用。同樣重要的是**恢復(fù)要慢、要穩(wěn)**——質(zhì)量指標(biāo)回落到恢復(fù)區(qū)間并持續(xù)觀察一段時間后才逐級恢復(fù)避免「加了又砍、砍了又加」的震蕩。 采樣窗口、降級閾值、恢復(fù)閾值、冷卻時間都是需要按協(xié)議、方向、內(nèi)容檔位和終端能力**配置并由真實網(wǎng)絡(luò)數(shù)據(jù)校準(zhǔn)的產(chǎn)品參數(shù)**不是協(xié)議常數(shù)。任何把某組實驗值講成「通用閾值」的說法都要警惕。---## 四、多檔畫質(zhì)的兩種做法服務(wù)端轉(zhuǎn)碼 vs Simulcast想要「1080P / 720P / 360P 同播」有兩條路。**傳統(tǒng)做法服務(wù)端轉(zhuǎn)碼。** 服務(wù)端先把收到的流完整解碼成原始畫面再按每個目標(biāo)檔位重新編碼一遍。解碼 多次重新編碼是相當(dāng)重的計算負(fù)擔(dān)而且天然帶來額外處理延遲費用也按輸出檔位和時長單獨計。**Simulcast推流端一次出多檔。** 關(guān)鍵要理解一句話**Simulcast 不是「一份編碼、服務(wù)端裁剪出多檔」而是發(fā)送端同時產(chǎn)生多份可獨立解碼的編碼。** 比如一路 1080P 輸入開 3 層 Simulcast就產(chǎn)生 1080P、720P、360P 三份獨立編碼分別以 RTP 發(fā)送推流端編碼器│├── 主編碼器1080P──? RTP 流RID high├── 縮放層編碼器720P──? RTP 流RID mid└── 縮放層編碼器360P──? RTP 流RID low三條流各自獨立、完整可解碼服務(wù)端按 RID 識別并轉(zhuǎn)發(fā)對應(yīng)層服務(wù)端收到每一層時它已經(jīng)是可直接轉(zhuǎn)發(fā)給觀眾的完整畫面**不需要解碼、不需要重新編碼只做字節(jié)轉(zhuǎn)發(fā)**。這就是「網(wǎng)絡(luò)側(cè)不用轉(zhuǎn)碼」的技術(shù)根因轉(zhuǎn)碼的工作量沒有消失只是被挪到了推流端的編碼器上——**用推流端的編碼算力換服務(wù)端的轉(zhuǎn)碼算力。**---## 五、為什么是 Simulcast不是 SVC懂一點編解碼的人會問可分層編碼SVC不是更省帶寬嗎- **SVC 的思路**編碼輸出包含基礎(chǔ)層和一個或多個增強層層之間有依賴關(guān)系轉(zhuǎn)發(fā)端可按依賴結(jié)構(gòu)選擇轉(zhuǎn)發(fā)子集通常比多份完全獨立編碼更省總碼率。- **代價是復(fù)雜度和兼容性**轉(zhuǎn)發(fā)端必須正確處理層標(biāo)識、依賴關(guān)系和切換點接收端也必須支持對應(yīng)的 codec/profile/scalability mode。H264/HEVC 是否可用 SVC取決于瀏覽器、系統(tǒng)解碼器、協(xié)商和產(chǎn)品實現(xiàn)。所以選 Simulcast 還是 SVC**本質(zhì)是當(dāng)前終端矩陣下的兼容性取舍不是哪個標(biāo)準(zhǔn)更先進(jìn)**。選型時應(yīng)以目標(biāo)終端矩陣和互操作測試為準(zhǔn)而不是聽某一家產(chǎn)品的現(xiàn)狀。---## 六、無縫切換切換點必須「可獨立解碼」最后一個關(guān)鍵問題觀眾從 720P 切到 360P 時怎么切才不花屏答案和點播的碼率切換是**同一條原理**獨立編碼的流只能從一個可解碼的接入點開始接入解碼器不能從中間任意一點切入。點播里表現(xiàn)為「只在分片邊界換檔」直播的 Simulcast 分層切換里表現(xiàn)為「等待目標(biāo)層的隨機接入點常見是請求關(guān)鍵幀」觀眾當(dāng)前播放 mid 檔720P│▼檢測到丟包率上升決定降檔到 low360P│▼請求或等待 low 層的可用關(guān)鍵幀│▼從該關(guān)鍵幀開始改為轉(zhuǎn)發(fā) low 層數(shù)據(jù)要注意**關(guān)鍵幀邊界本身不等于無條件無縫**。是否無感取決于關(guān)鍵幀等待時間、緩沖狀態(tài)和 RTP 連續(xù)性處理。關(guān)鍵幀請求會消耗碼率、存在等待時間所以正確切換能避免引用鏈損壞和花屏但不保證零等待、零卡頓。順便借這個原理聊聊向頭部點播平臺學(xué)什么它們的 ABR 決策不只看瞬時網(wǎng)速還看**播放緩沖區(qū)還剩多少內(nèi)容**切換點嚴(yán)格對齊編碼階梯按內(nèi)容定制。這些思路可以借鑒但**點播和直播的約束差一個數(shù)量級**——點播可以攢大緩沖、可以離線反復(fù)試驗最優(yōu)編碼參數(shù)低延遲直播緩沖預(yù)算更小、編碼必須實時。照抄參數(shù)會出問題能真正復(fù)用的是決策哲學(xué)**以觀感為中心而不是以某個單一技術(shù)指標(biāo)為中心。**---## 小結(jié)- **三種協(xié)議看丟包策略**RTMP 繼承 TCP 的隊頭阻塞SRT 用 ARQ TSBPD 過期丟棄換弱網(wǎng)魯棒性WHIP 復(fù)用 WebRTC/RTP 的反饋、擁塞控制和動態(tài)緩沖。- **共存優(yōu)于二選一**WHIP 追低延遲SRT 保弱網(wǎng)上行兩者統(tǒng)計口徑不同要在接收端派生統(tǒng)一的產(chǎn)品指標(biāo)再驅(qū)動降級。- **降級有代價梯度**先壓碼率不中斷再砍分辨率短暫中斷恢復(fù)要慢要穩(wěn)。- **多檔畫質(zhì)靠 Simulcast**發(fā)送端出多份獨立編碼服務(wù)端只轉(zhuǎn)發(fā)不轉(zhuǎn)碼用推流端算力換服務(wù)端算力。- **無縫切換的通用原理**在可獨立解碼、時間線連續(xù)的位置切換關(guān)鍵幀是常用但非唯一的手段。下一篇我們講一個同樣容易被忽略、但直接關(guān)系業(yè)務(wù)安全的話題**推拉流的簽名、Token 與防盜鏈**。---**系列導(dǎo)航**- 上一篇[02 · 自建 CDN 架構(gòu)總覽](02-自建CDN架構(gòu)總覽-控制面與媒體面分離.md)- 下一篇[04 · 推拉流安全簽名、Token 與防盜鏈](04-推拉流安全-簽名Token與防盜鏈.md)- 返回[系列導(dǎo)覽](README.md)