Skip to content

WebRTC 为何能取代 HLS/FLV

先给结论:在“实时直播 / 强互动”这个场景里,WebRTC 对 HLS 和 HTTP-FLV 是代际替代。 它的优势不是“把同一个分片切得更小”,而是从传输模型上取消了“先落盘/先成片、再通过 HTTP 拉取”的中间层。 但在点播、超大并发单向分发、老旧终端等场景,HLS/FLV 仍然有明确的位置。 本文讨论的是“实时直播”,不是“所有视频”。

1. 三种协议到底差在哪

维度 HLS HTTP-FLV WebRTC / WHEP
传输 HTTP/TCP HTTP/TCP SRTP/UDP(ICE 建连)
媒体组织 TS/fMP4 分片 + m3u8 播放列表 连续 FLV 字节流 RTP 包 / 音频视频轨道
播放端拿到什么 一个完整分片后再解码 连续字节流,边收边解封装 单个 RTP 包,边收边解码
典型时延 6–30 秒;LL-HLS 约 2–5 秒 1–3 秒 100 ms–1 秒,优化链路可低于 500 ms
首帧 等分片、等关键帧 等关键帧/缓存窗口 建连后收到首个可解码帧即可
缓存模型 CDN 可按分片缓存,天然适合大规模分发 CDN 可流式转发,但仍是 TCP 每个观众一条 SRTP 连接,边缘需要 SFU 转发
抗弱网 TCP 重传 + 播放器缓冲,延迟随卡顿累积 TCP 队头阻塞,延迟随缓冲累积 UDP + NACK/FEC + 拥塞控制 + 抖动缓冲
P2P 不支持 不支持 支持,可绕开边缘带宽
原生 App iOS/Android 播放器支持成熟 依赖 FLV 解封装/播放器 使用 libwebrtc;WHEP 只是 HTTP 信令

1.1 HLS 的时延是结构性的

HLS 的播放链路大致是:

编码器 → 切片器 → 生成分片 + m3u8 → CDN 缓存 → 播放器下载分片 → 解码播放

播放器必须先拿到一个分片,通常还要在缓冲区里预存几个分片,才能稳定播放。即使把分片切到 1 秒、引入 LL-HLS 的部分分片和阻塞重载,仍然绕不开:

  • 分片边界和关键帧对齐;
  • HTTP 请求、CDN 回源与缓存;
  • 播放器自身的启动缓冲;
  • TCP 的队头阻塞和重传。

所以 HLS 可以把“延迟”从 20 秒优化到 3 秒,但很难稳定进入“几百毫秒 + 可互动”的区间。

1.2 HTTP-FLV 只是“连续化的 HLS”

HTTP-FLV 去掉了 m3u8 刷新,媒体流连续传输,因此比 HLS 更容易做到 1–3 秒。但它仍然跑在 TCP 上:

  • 一个丢包会阻塞后续字节,播放器只能靠缓存硬扛;
  • 延迟会随着网络抖动和重连逐渐累积;
  • 浏览器侧通常依赖 MSE/flv.js,iOS Safari 不是天然支持;
  • 不支持 P2P,边缘带宽成本无法下沉到观众侧。

它是“HLS 的低延迟改良版”,不是另一代传输模型。

1.3 WebRTC 换掉了整条链路

WebRTC 的链路是:

编码器 → RTP/SRTP 包 → SFU/边缘转发 → RTP/SRTP 包 → 接收端解码渲染

没有“先落地成文件、再通过 HTTP 拉取”的步骤。接收端为每个音频/视频轨道维护抖动缓冲,丢包通过 NACK/FEC 处理,拥塞控制决定发送码率。WHEP 只负责把“我要看这条流”的 SDP Offer 通过 HTTP POST 发给边缘,并拿回 SDP Answer;真正的媒体走 ICE 建连后的 UDP/SRTP。

这就是 WebRTC 能做到“低时延”的根本原因:媒体包从产生到消费,不需要等待一个可播放的完整分片。

2. 时延:不是优化 30%,而是换了一个量级

方案 典型端到端时延 主要延迟来源
HLS 6–30 s 分片时长、播放列表刷新、CDN 缓存、播放器缓冲
LL-HLS 2–5 s 部分分片、阻塞重载、HTTP/TCP、播放器缓冲
HTTP-FLV 1–3 s TCP 重传/队头阻塞、播放器缓冲、GOP
WebRTC/WHEP 0.1–1 s 采集/编码、网络 RTT、抖动缓冲、解码渲染

PPCDN 在公开的直播时延性能测试报告中给出的实测结果是:

  • P2P 直连:约 70 ms
  • WHIP 入库 + WHEP 播放:约 108 ms
  • SRT 入库 + WHEP 播放:约 386 ms

这些数字来自特定测试条件,不代表对所有网络环境的承诺;但它们说明了一件事:WebRTC 的时延下限和 HLS/FLV 不在同一个数量级。

对强互动业务,这个差异会直接改变产品形态:

  • 竞拍/抢购:出价和画面同步,不会“举牌后画面还停在上一秒”;
  • 连麦/游戏:主持人和观众可以实时对话;
  • 远程操作/云游戏:操作指令和画面反馈形成闭环;
  • 在线教育:老师提问、学生回答不需要等“缓冲几秒”。

3. 播放性能:低时延只是第一层

3.1 首帧和切换更快

HLS 要等分片,FLV 要等关键帧和缓冲窗口;WebRTC 建连后收到首个可解码帧就能出画面。用户点击播放到看到画面的时间更短,切换清晰度也不必等待下一个分片边界。

3.2 卡顿恢复策略不同

TCP 系协议遇到丢包时,数据会排队重传,播放器只能靠增加缓冲吸收;一旦缓冲耗尽就卡顿。WebRTC 使用 UDP,通过 NACK/FEC 和拥塞控制处理丢包,延迟不会因为一次重传被永久推高。

这并不意味着 WebRTC 对弱网“免疫”:丢包严重时仍会花屏、降码率或卡顿。区别在于它可以把问题控制在毫秒到秒级,而不是让整条 TCP 流进入“越卡越慢”的恶性循环。

3.3 ABR/Simulcast 更细

HLS 的清晰度切换通常发生在分片边界,切晚了会浪费带宽,切早了可能卡顿。WebRTC 可以在 RTP 层按 simulcast 层或码率档位切换,切换粒度更细,配合接收端带宽估计更平滑。

PPCDN 还支持 H264/HEVC 多轨同播和 Simulcast:编码端一次输出多档,边缘只转发不转码;播放端按终端能力选择 H264 或 HEVC,不需要为不同终端准备多套流。

3.4 P2P 把带宽成本下沉

HLS/FLV 的每个观众都要从 CDN 拉流;WebRTC 可以让观众之间直连,边缘只服务一部分观众。PPCDN 支持 P2P 直连,并且能测量 P2P 的端到端时延,而不是只靠体感判断“有没有加速”。

3.5 但 WebRTC 不是没有代价

必须承认:

  • WebRTC 的连接数更多,边缘需要 SFU 做转发,不能像 HLS 一样靠一个静态分片服务无限观众;
  • 加密(DTLS-SRTP)和实时解码对 CPU/电量更敏感;
  • 每个观众一条连接,CDN 的“缓存命中”优势用不上;
  • 网络特别差、UDP 被限制的环境,仍需要 SRT/FLV/HLS 兜底。

所以准确说法是:在实时互动体验上 WebRTC 碾压 HLS/FLV;在大规模单向分发的单位成本上,HLS 仍然很强。

4. 终端兼容性:现代浏览器和原生 App 都已经就位

4.1 浏览器

终端/浏览器 HLS HTTP-FLV WebRTC/WHEP
Chrome/Edge/Firefox 桌面 通常需 MSE + hls.js 需 MSE + flv.js 原生支持
Safari 桌面 原生支持 不支持(无 MSE FLV) 原生支持
iOS Safari 原生支持 不支持 原生支持(WebRTC)
Android Chrome 通常需 MSE/hls.js 需 MSE + flv.js 原生支持

WebRTC 的优势不是“所有设备都能跑”,而是现代浏览器和移动端已经普遍内置 WebRTC。HLS 虽然“协议简单”,但在 Chrome/Firefox 桌面端反而需要额外播放库;FLV 在 iOS Safari 上则基本不可用。

4.2 原生 App

原生 App 不依赖浏览器的 <video>,而是直接集成 WebRTC SDK:

平台 推荐方案
Android org.webrtc / libwebrtc,SurfaceViewRenderer 渲染
iOS WebRTC.framework,RTCMTLVideoView 渲染
Flutter flutter_webrtc
React Native react-native-webrtc
桌面 libwebrtc、GStreamer WHEP 客户端

这意味着:原生 App 完全可以拉 WHEP 流并播放。 WHEP 不是浏览器专有协议,它只是一个标准化的 HTTP 信令流程;媒体仍然是标准 WebRTC。

5. 原生 App 如何拉 WHEP

5.1 先拿播放决策,再建 WebRTC

以 PPCDN 为例,App 后端或 App 自身先向 ppcenter 请求播放决策:

POST /v1/play/requests
Authorization: Bearer <viewer-token>
Content-Type: application/json

{
  "streamName": "B01-frontView",
  "clientId": "android-xxxx",
  "capabilities": ["whep"]
}

响应里的 edgeStreamUrl 是已经带签名的边缘流基址,例如:

https://edge-1.edge.pp-cdn.org/{appId}/{streamName}

App 根据设备能力追加 codec 段:

H264: {edgeStreamUrl}/h264/whep
HEVC: {edgeStreamUrl}/hevc/whep

不要把 edgeStreamUrl 当成普通视频 URL 去下载。它是 WHEP 的 POST 目标,query 中的 txTime/txSecret 是边缘播放鉴权参数。

5.2 WHEP 信令流程

App                          Edge
 |                            |
 | 1. 创建 RTCPeerConnection   |
 | 2. addTransceiver(recvonly) |
 | 3. createOffer              |
 |                            |
 | 4. POST /h264/whep?tx...   |
 |    Content-Type: application/sdp
 |    <SDP Offer>             |
 | -------------------------->|
 |                            |
 | 5. 200 OK                  |
 |    Content-Type: application/sdp
 |    Location: .../session/...
 |    <SDP Answer>            |
 | <--------------------------|
 |                            |
 | 6. setRemoteDescription     |
 | 7. ICE 连通,收到音视频轨道 |
 | 8. 渲染                     |
 |                            |
 | 9. PATCH trickle ICE(可选)|
 | 10. DELETE Location(结束) |

关键点:

  • 音频和视频都使用 recvonly transceiver;
  • Offer 里只声明接收,不发送本地音视频;
  • Answer 的 Content-Type 必须是 application/sdp;
  • 保存响应头 Location,退出播放时发送 DELETE,避免边缘留下僵尸会话;
  • ICE candidate 可以随 Offer 一次性给全,也可以 trickle(PATCH);移动端网络切换时 trickle 更常见;
  • stunServers 来自播放决策;如果没有 STUN/TURN,跨 NAT 的连通性会下降。

5.3 Android(libwebrtc)伪代码

val factory = PeerConnectionFactory.builder()
    .setVideoDecoderFactory(DefaultVideoDecoderFactory(eglBase.eglBaseContext))
    .createPeerConnectionFactory()

val pc = factory.createPeerConnection(
    PeerConnection.RTCConfiguration(iceServers).apply {
        sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN
    },
    observer
)!!

pc.addTransceiver(
    MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO,
    RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY)
)
pc.addTransceiver(
    MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO,
    RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY)
)

val offer = pc.createOffer(SdpObserver...)
pc.setLocalDescription(offer, ...)

// POST application/sdp,body = offer.description
val response = httpPost("$edgeStreamUrl/h264/whep?txTime=...&txSecret=...", offer.description)
pc.setRemoteDescription(
    SessionDescription(SessionDescription.Type.ANSWER, response.body),
    ...
)

// onTrack: 把 videoTrack 绑定到 SurfaceViewRenderer
// onIceCandidate: 通过 PATCH application/trickle-ice-sdpfrag 发送

5.4 iOS(WebRTC.framework)要点

  • RTCPeerConnectionFactory + RTCPeerConnection;
  • RTCRtpTransceiverInit(direction: .recvOnly);
  • RTCMTLVideoView 绑定 RTCVideoTrack;
  • URLSession 发 WHEP POST/PATCH/DELETE;
  • 注意 Location 是相对/绝对 URL,按 HTTP 规范解析。

5.5 App 侧必须处理的异常

现象 处理
401/403 重新获取 viewer token / 重新签名 edgeStreamUrl
404 流当前不在线,回到“等待开播”状态
503 暂时没有可用 Edge,指数退避重试
ICE failed 销毁旧连接,重新请求播放决策;不要复用失败 PC
网络切换 监听网络变化,重建 PeerConnection(Wi-Fi/4G 切换)
切后台 暂停/释放解码与渲染,回前台重新建连
txTime 过期 重新向 ppcenter 请求播放 URL;不要长期缓存带签名的 URL
P2P 关闭 只走 Edge WHEP 完全可用;P2P 是可选加速,不是播放前提

6. PPCDN 的落地方式

PPCDN 的实时链路是:

ppobs / 浏览器
  ├─ WHIP 推流(低时延)
  └─ SRT 推流(抗弱网)
          │
          ▼
       Origin
          │  不解码、不转码,透传 Simulcast / 多轨
          ▼
        Edge(SFU)
          │
          ├─ WHEP/WebRTC ──> 浏览器 / 原生 App
          └─ P2P 直连 ─────> 观众之间(可选)

具体能力:

  • WHIP/SRT 双协议入库,按网络场景选择;
  • H264/HEVC 多轨同播,播放端按终端能力选轨;
  • Simulcast/ABR,边缘按丢包、RTT、带宽选择层;
  • P2P 直连并测量端到端时延;
  • WHEP 播放,原生 App 和浏览器使用同一套边缘;
  • 录像通过独立 API 切分/上传,不阻塞直播链路。

相关文档:

  • 推流/播放 API:仓库 docs/api/streaming.md
  • PPCDN 架构设计:仓库 docs/design/ppcdn-architecture-design.zh-CN.md
  • 直播时延性能测试报告

7. HLS/FLV 仍然适合什么

“淘汰”不是“协议消失”。下面这些场景,HLS/FLV 仍然合理:

  • 点播/回看:文件已经完整,HLS 的分片缓存和 CDN 成本优势最大;
  • 超大并发单向直播:百万级观众、只需观看、不需要互动,HLS 的单位带宽成本更低;
  • 老旧终端/智能电视/机顶盒:原生 HLS 支持成熟,WebRTC 集成成本更高;
  • 弱网/受限网络:UDP 被限制时,SRT/FLV 仍然有兜底价值;
  • DRM/广告/字幕等传统媒体生态:HLS 的周边能力更完整。

所以正确的工程策略不是“全站删掉 HLS/FLV”,而是:

实时互动主链路用 WebRTC/WHEP;点播、回看、超大单向分发保留 HLS/FLV 作为分层能力。

8. 迁移检查清单

  • [ ] 推流端支持 WHIP 或 SRT,至少一条低时延入库链路;
  • [ ] 边缘具备 SFU/WHEP,而不是把 WebRTC 包转成 HLS 再播放;
  • [ ] 播放端能按设备能力选择 H264/HEVC,并正确处理 401/404/503;
  • [ ] viewer token 短时有效,edgeStreamUrl 不长期缓存;
  • [ ] App 处理 ICE failed、网络切换、前后台切换;
  • [ ] 保留 HLS/FLV 兜底路径,按终端能力或网络质量降级;
  • [ ] 监控首帧时间、卡顿率、P2P 成功率、端到端时延,而不是只看“有没有画面”。

9. 结论

HLS/FLV 解决的是“把视频可靠地分发出去”,WebRTC 解决的是“让视频实时地到达并可以互动”。前者优化的是缓存、分片和带宽;后者优化的是传输路径和反馈闭环。

在实时直播场景,WebRTC 的优势是结构性的:

  • 时延:从秒级进入百毫秒级;
  • 播放体验:首帧更快、卡顿恢复更平滑、ABR 更细;
  • 终端:现代浏览器和原生 App 都能通过 WHEP 接入;
  • 成本:P2P 可以把部分带宽从边缘下沉到观众侧。

原生 App 也完全可以拉 WHEP:集成 libwebrtc,按 WHEP 的 HTTP 信令交换 SDP,媒体走标准 WebRTC 即可。WHEP 不是浏览器专属,它只是让 WebRTC 的“建连”变得像普通 HTTP API 一样简单。