Preface
前陣子筆者在工作上的事情比較多,有一陣子沒更新了。這次想來聊聊【串流】這件事。
接觸程式開發以來,很少聽到串流這塊領域,感覺它是一塊特有的冷門區域,進入門檻有點高度。
儘管串流在我們的生活中無所不在,不論是 Netflix、YouTube 等影音媒體,你所看到的畫質、播放速度,每個都是串流處理的事情。
很幸運在這份工作中接觸到這塊領域,串流分為許多環節,不過簡單來說可以是 推流端 -> Media Server -> 拉流端。而其中使用的協定又分很多種,例如推流 RTSP、RTMP 等; 拉流 WebRTC、HLS、FLV 等,Media Server 也有 MediaMTX, SRS, Ant Media Server。 而負責推流的工具例如 FFmpeg, GStreamer… (聽起來很多吧哈哈,真的是塊坑,但我很開心能有所收穫)
那所以今天想來簡單講一下串流每個環節處理的事情,還有它的專有名詞,但由於篇幅長度,細節就暫時不贅述 (給未來的自己挖坑)。
推流端
編碼標準 (Codec)
原始影像 (raw frame) 非常大,舉例來說 (大小 1920 x 1080 @30 FPS 的影片),
- 單張圖片的 pixels = 1920 x 1080 = 2,073,600 pixels
- 每個 pixel 由 R、G、B 三通道組成 (有時候會是 RGBA,包括透明度通道),每個通道是 8 bits,所以每個 pixel 是 24 bits (or 32 bits)
- 這個影片每秒的數據量 = 像素數量 (pixels) x 單個像素大小 (bits) x 每秒幀數 (FPS) = 2073600 x 24 x 30 = 1,492,992,000 bits/second = 1.49 Gbps = 186.6 MB
如果不透過編碼技術壓縮,這在網路上傳輸非常困難。
那常見的編碼技術有幾種 :
Mux / Demux
Mux 是 Multiplex 的縮寫,意思是多路傳輸,也就是把多個數據流 (影片、音頻素材) 封裝的過程。
編碼後的壓縮數據是 ES (Elementary Stream),ES 會被切成多個封包,並加上一個 PES Header 成為 PES (Packetized Elementary Stream),PTS (Presentation Time Stamp) 跟 DTS (Decoding Time Stamp) 就是在這出現的。
接下來 Muxer 會將不同 PID (Packet Identifier) 的影像 PES 與音訊 PES 按時間順序 interleaving,插入 PSI (Program Specific Information) (MPEG-TS 體系) 或 Metadata (MP4/MOV 體系),定義屬性與解碼參數。
Demuxer 會尋找封裝格式的同步字節 (如 TS 的 0x47、MP4 的 Box Header),然後讀取 Header 來獲得編碼參數,並傳遞給解碼器。根據封包標記 (PID、Track ID) 將 PES 數據分發至對應的解碼管線,提取 PTS / DTS 作為渲染引擎的參考依據。
傳輸 (Streaming)
在完成 Mux 封裝後,數據需要透過特定的應用層協議發送至 Media Server。
| 協議 | 傳輸層 | 特點 |
|---|---|---|
| RTMP | TCP | 適合一對多的單向廣播 |
| RTSP | UDP/TCP | 監控系統 |
| SRT | UDP | 跨國直播推流、網路環境不穩定 |
| WebRTC | UDP | 多對多的即時互動 |
| RIST | UDP | 多路徑的能力; RIST 可以同時發送數據到兩條不同電信商的網路,並在接收端去重,即使一條斷掉,畫面也不會閃爍。 |
| HLS | HTTP(TCP) | 大規模分發、CDN 緩存 |
速率控制 (Bitrate)
Bitrate 決定了頻寬的佔用。
CBR (Constant Bitrate) : 強制每一秒的數據量保持固定。在畫面簡單時填充無效數據 (Padding),複雜時犧牲畫質。適用於網路頻寬受限的直播場景。
VBR (Variable Bitrate) : 根據畫面複雜度分配位元率。簡單畫面低位元率,複雜畫面高位元率。常見於 點播 VOD (Video On Demand) 或錄影存檔,旨在維持視覺品質的一致性。
GOP (Group of Pictures)
GOP 是影音壓縮中時間預測的基礎單位。它由一個 I-Frame (關鍵幀) 開始,後面跟隨多個 P-Frame (預測幀) 與 B-Frame (雙向預測幀)。
P-Frame / B-Frame 必須依賴 I-Frame 才能解碼。也就是說拉流端進入直播間時,必須等到下一個 I-Frame 出現才能顯示畫面。因此 GOP Length 決定了隨機存取的接入點。
IDR Frame (Instantaneous Decoding Refresh) : 當 IDR Frame 出現時,解碼器會清空幀緩衝區 (DPB) 以防止錯誤累積。
FFmpeg、GStreamer
這兩個工具扮演 : 數據採集 -> 解法 -> 封裝 -> 傳輸 的角色。
FFmpeg : CLI 工具
GStreamer : 開發框架 (是個大坑),基於 Plugin-based 的 Pipeline 架構
未來有機會可以多講講這裡。
Media Server
| Media Server | 開發語言 | 連結 |
|---|---|---|
| MediaMTX | Go | Link |
| SRS | C++ | Link |
| Ant Media Server | Java | Link |
| Nginx-RTMP | C | Link |
| LiveKit | Go | Link |
拉流端
| Protocol | 傳輸層 | 撥放器支援度 | Pros | Cons |
|---|---|---|---|---|
| HLS (HTTP Live Streaming) | HTTP(TCP) | 高 | 穿透力強、ABR (自適應畫質) | 延遲高,不適合互動 |
| WebRTC | UDP | 高 | 低延遲、雙向通訊 | 伺服器成本高、大規模分發較難 |
| HTTP-FLV | TCP | 中 | 穿透力強、低延遲 | 瀏覽器相容性正逐漸被淘汰 |
| DASH | HTTP(TCP) | 高 | 強化版的 HLS | 設定較為複雜 |
| RTSP | UDP/TCP | 低 (需專業撥放器) | 低延遲 | 網頁端幾乎無法直接播放 |
穿透力是指順利通過防火牆 (Firewall) 與網路位址轉換 (NAT) 的能力,由於 WebRTC 走的是 UDP,所以需要透過 ICE / STUN / TURN 找到傳送路徑。