WHIP/WHEP vs RTSP/RTMP:WebRTC低延迟直播接入的融合方案
我这两年在流媒体项目里,没少和 RTSP、RTMP 打交道。最近 WHIP、WHEP 这两个名字经常出现在技术群里,尤其在聊网页低延迟直播和 WebRTC 接入的时候。做直播、监控上云、云导播的同学都在问同一个问题:WebRTC 的新接入协议出来了,RTSP、RTMP 是不是该退场了?加上 SmartMediaKit 这类多协议网关越来越普及,一台服务既能收 RTSP 摄像头流、也能接 RTMP 推流、还能让浏览器直接低延迟播放,似乎“大统一”已经不远。这篇文章我想把协议层面的思考和一段实战过程都摊开聊,给正在选流媒体方案的人做个参考,也帮刚接触的朋友把 WHIP/WHEP 到底解决什么问题看清楚。
1. 先说结论:RTSP/RTMP 依然能打,WHIP/WHEP 补上了最后一公里
1.1 RTSP:安防生态的中流砥柱,只是没想着给浏览器用
RTSP 是 IETF 在 1998 年提出的流媒体会话控制协议,它本身不负责传输音视频数据,真正跑媒体的是 RTP/RTCP。客户端通过 DESCRIBE 拿到 SDP 描述,用 SETUP 建立传输通道,发 PLAY 开始收流,整个过程和“控制播放器”很像。由于设计目标就是远程播放和点播控制,它在安防领域混得非常好,IPC、NVR、ONVIF 协议栈几乎都带 RTSP 支持,延迟也能稳定做到 0.2 到 1 秒。RTSP 的问题也很突出:NAT 穿透基本靠端口映射,公网拉流往往要借助中间媒体服务器;加密不是标配,RTP 明文在公网跑让人不太安心;浏览器没有任何原生播放能力,用户要么装 VLC,要么靠后端转封装转协议。
1.2 RTMP:Flash 退休了,协议还在直播推流里跑
RTMP 是 Adobe 时代的产物,基于 TCP 长连接,默认 1935 端口,通过握手、connect、createStream、publish/play 完成推拉流。为什么到现在还在大量使用?核心原因在推流侧:OBS、FFmpeg、各种手机推流 SDK 都支持 RTMP,CDN 的直播摄取入口也普遍默认收 RTMP,整个工具链和运维习惯都是按它长出来的。播放侧则比较尴尬,Flash 退场后浏览器不再原生支持 RTMP,实际播放要依赖服务端再转出 HTTP-FLV 或 HLS。再加上 RTMP 走 TCP,队头阻塞问题在高丢包、弱网环境下会导致延迟抖动明显,所以今天 RTMP 更适合当“生产端协议”,不适合当“消费端协议”。
1.3 WHIP/WHEP:WebRTC 终于有了统一接入入口
WebRTC 在浏览器端很强:支持 ICE 穿透、DTLS-SRTP 加密、SRTP 媒体传输、NetEQ 抖动缓冲、GCC 拥塞控制,端到端延迟能做到 500ms 以内。问题是它一直缺少像“RTMP 推流”这样标准的接入协议,过去想跟 WebRTC 服务对接,必须自己搭信令服务,或者套用一套复杂的 WebSocket 协议。WHIP 解决推流接入,把建立 WebRTC 会话抽象成一次 HTTP POST:客户端提交 SDP Offer,服务端返回 201 和 SDP Answer,推流会话就建立起来了。WHEP 负责播放侧,拉流同样走 HTTP 资源,媒体流方向反过来。两者配套之后,WebRTC 第一次有了类似 RTSP/RTMP 的“统一协议入口”。
| 项目 | RTSP | RTMP | WHIP | WHEP |
|---|---|---|---|---|
| 传输层 | 通常 UDP(RTP),兼容 TCP | TCP 长连接 | UDP(SRTP over ICE) | 同左 |
| 加密能力 | 默认弱,可加扩展 | RTMPS/RTMPE 用得少 | DTLS-SRTP 强制加密 | 同左 |
| 浏览器原生播放 | 不支持 | 不支持 | 支持 | 支持 |
| 端到端延迟 | 0.2s ~ 1s | 1s ~ 5s | 0.3s ~ 0.8s | 0.3s ~ 0.8s |
| NAT 穿透 | 依赖端口映射 | 依赖公网端口 | ICE 自动打洞 | 同左 |
| 典型场景 | 监控、播放器拉流 | 推流、CDN 摄取 | 采集端 WebRTC 推流 | 浏览器低延迟播放 |
从这张表能看出,WHIP/WHEP 并不是在“所有维度”碾压 RTSP/RTMP。它解决的是 Web 端接入和低延迟体验这两个痛点,而 RTSP 在安防生态、RTMP 在推流工具链上的积累依然扎实。与其说“取代”,不如说它们补上了历史欠账。
2. WHIP/WHEP 原理拆解:为什么“发一个 POST”就能建立实时流
2.1 WHIP 推流的完整会话流程
WHIP 现在的正式编号是 RFC 9753,WHEP 也作为配套协议落地。整套流程比很多人想象中简单:
- 推流端创建 PeerConnection,生成 SDP Offer。Offer 里带有媒体描述、ICE candidates、DTLS 指纹等关键信息。
-
推流端把这个 SDP Offer 通过 HTTP POST 发到 WHIP 资源 URL,比如
http://127.0.0.1:8080/whip/live/test_whip,请求头Content-Type: application/sdp。 -
服务端收到请求后创建 WebRTC PeerConnection,返回
201 Created。响应体是 SDP Answer,响应头Location指向会话控制 URL。 - 双方开始 ICE 连通性检查,完成 NAT 穿透,然后做 DTLS 握手,媒体流通过 SRTP 从推流端推到服务端。
- 推流过程中遇到网络切换,客户端可以发送 PATCH 请求做 trickle ICE,或触发 ICE restart。推流结束直接 DELETE 会话 URL,服务端回收资源。
这个设计聪明在把信令和会话控制全部套进 HTTP 语义里,鉴权网关、负载均衡、日志审计都能直接复用现成 HTTP 设施。媒体面则完全交给 WebRTC,加密、降码率、重传都由标准协议栈处理。对于服务端开发者来说,接入 WHIP 相当于在 HTTP 层多了一个“POST 后建立推流会话”的路由。
2.2 WHEP 拉流:方向反了,套路不变
WHEP 的流程跟 WHIP 几乎对称,只是媒体流从服务端流向播放端。播放器向 WHEP 资源 URL 发起 HTTP POST,提交一个 SDP Offer,这个 Offer 通常可以是空 Offer,主要由服务端返回可用的媒体编码能力。服务端返回 201 Created 和 SDP Answer,后面就是标准 WebRTC 播放过程。
WHEP 最适合的场景是“浏览器里直接低延迟看流”。之前做网页直播,想要低延迟一般两条路:一条是走 WebSocket + MSE 自定义播放器,另一条是接第三方低延迟播放组件,两条路都费劲。WHEP 把“从服务端拉一路 WebRTC 流”变成了一个标准资源,网页播放器只要实现了 WHEP 客户端逻辑,就能像点开一个播放地址一样看流。服务端也不需要考虑“源是什么协议”,RTSP、RTMP、HTTP-FLV 这些入站协议都可以先变成内部媒体源,再靠 WHEP 出口转给浏览器。
一个简化版 SDP Offer 长这样:
v=0
o=- 8987654 2 IN IP4 127.0.0.1
s=-
c=IN IP4 0.0.0.0
t=0 0
m=video 9 UDP/TLS/RTP/SAVPF 96 97
a=mid:0
a=ice-ufrag:abcd
a=ice-pwd:efgh
a=fingerprint:sha-256 AA:BB:CC:DD:...
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1
里面的核心字段就三类:媒体编码信息、ICE 身份校验、DTLS 指纹。看到服务端返回
201 Created
,并且响应体里同样带 fingerprint、ice-ufrag 这些字段时,说明信令层面已经通了。
2.3 SmartMediaKit 的核心价值:做协议的“翻译官”
单独用 WHIP/WHEP,你还要解决“源从哪里来”的问题。摄像头大多只说 RTSP,OBS 推流大多默认 RTMP,浏览器又只想走 WebRTC,三者的沟通成本很高。SmartMediaKit 这类多协议网关的做法是在内部做一个统一媒体源管理:RTSP 拉流、RTMP 推流、WHIP 推流先把媒体落到同一个 MediaSource,播放侧再按需从 MediaSource 转成 WHEP、RTSP、RTMP、HTTP-FLV 等不同出口。
这样最大的好处是“入口和出口解耦”。你在接入层不用逼着设备升级协议,在分发层也不用为了不同播放端写多套对接。比如一台老款 IPC 摄像头只支持 RTSP,SmartMediaKit 把 RTSP 拉进来,浏览器播放端直接用 WHEP 看流就可以。这个过程中摄像头完全不知道 WHEP 的存在,浏览器也不需要装任何插件。真正的 SFU 产品,比如 Janus、LiveKit,也能做 WHIP/WHEP,但设计目标更偏向多人实时会话;SmartMediaKit 这类型网关更贴合直播和监控管道,按需拉流、录像、转封装这些能力用起来更顺手。
3. SmartMediaKit 实战:从 RTSP/RTMP 接入到 WHEP 浏览器播放
3.1 先搭环境:端口规划与 Docker 部署
我在本地验证时用的是 Docker 部署,命令大致如下:
docker run -d --name smartmediakit \
-p 1935:1935 \
-p 554:554 \
-p 8080:8080 \
-p 8443:8443 \
your-registry/smartmediakit:latest
端口作用分别说一下:1935 是 RTMP 默认端口,收 OBS/FFmpeg 推流用;554 是 RTSP 默认端口,供 IPC/NVR 或 VLC 拉流;8080 是 HTTP 服务端口,WHIP/WHEP 的信令和管理接口一般挂在这里;8443 给 HTTPS 用,上线环境建议必须开。浏览器访问 WebRTC 业务时,很多时候要求 secure context,也就是 HTTPS 或者 localhost。如果只是本机联调,
http://localhost:8080
能用;远程调试或生产环境,一定加一层 HTTPS 反代,否则某些浏览器会限制音视频相关能力。
注意:SmartMediaKit 不同版本的接口路径会有差异,我这里用
/whip/{app}/{stream}和/whep/{app}/{stream}风格的地址举例,配置前以你实际部署版本的文档为准。
3.2 准备测试流:用 GStreamer 和 FFmpeg 自建 RTSP/RTMP 源
网上那些公开测试流地址不太靠谱,很多是内网或特定网络环境才能访问,真正练手最好自己生成测试源。GStreamer 自带 rtsp-server 的示例程序,可以快速起一路 RTSP 源:
git clone https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server.git
cd gst-rtsp-server/examples
./test-launch "( videotestsrc ! video/x-raw,width=1280,height=720 ! x264enc tune=zerolatency ! rtph264pay name=pay0 pt=96 )"
执行后默认监听 8554 端口,地址是
rtsp://127.0.0.1:8554/test
。这路流虽然只是测试画面,但已经是标准 H.264 编码,能模拟不少摄像头场景。如果更想模拟 OBS 推流,用 FFmpeg 推 RTMP 也很方便:
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-f lavfi -i sine=frequency=1000:sample_rate=48000 \
-c:v libx264 -preset veryfast -tune zerolatency \
-c:a aac \
-f flv rtmp://127.0.0.1:1935/live/test_rtmp
然后在 SmartMediaKit 管理端添加“拉流代理”,把
rtsp://127.0.0.1:8554/test
拉进来,给它一个本地 streamId,比如
test
。这一步很关键,相当于让 SmartMediaKit 内部先缓存一路 RTSP 源,后续 WHEP 播放只是“消费”这个内部源。
3.3 验证 WHIP 推流入口:OBS 和 curl 都能测
先测 WHIP 推流入口是否正常。新版 OBS 的直播服务里直接有 WHIP 选项,服务地址填
http://127.0.0.1:8080/whip/live/test_whip
,有鉴权就填 Bearer Token,然后点开始推流。如果信令成功,SmartMediaKit 里会出现一路
test_whip
的流。
没有 OBS 的时候,也可以用 curl 验证 WHIP 端点:
curl -X POST \
-H "Content-Type: application/sdp" \
--data-binary @offer.sdp \
http://127.0.0.1:8080/whip/live/test_whip
把
offer.sdp
换成上面那份简化 SDP 或者标准 SDP,正常会返回
201 Created
,响应体是 SDP Answer。需要强调一下,curl 只能证明 WHIP 的信令通路是通的,真正推媒体还需要支持 WebRTC 的客户端,它不会主动发送媒体包。
3.4 用 WHEP 在浏览器里拉流:从信令看到画面
浏览器端验证 WHEP 最方便,打开 SmartMediaKit 自带的 WebRTC 播放页面,填
http://127.0.0.1:8080/whep/live/test
,就能看到路测试画面。也可以从 RTMP 源验证,把 streamId 换成
test_rtmp
,地址变成
http://127.0.0.1:8080/whep/live/test_rtmp
,同样能播放。也就是说,我们先用 FFmpeg 推了一路 RTMP 流,然后在浏览器里用 WHEP 点播,整套链路就是“RTMP 采集端 + WebRTC 分发端”。
想再深入一点,可以在播放时打开 Chrome 的
chrome://webrtc-internals
,看 inbound-rtp 里的媒体信息。正常情况下能看到
mediaType: video
、
bytesReceived
在持续增长,编码格式是 H264 或 VP8 之一。延迟体感很明显,基本在几百毫秒级别,比 RTMP+HLS 的几秒延迟舒服得多。
3.5 常见接线矩阵:哪些源到出口值得打通
| 源 -> 出口 | 典型场景 | 建议程度 |
|---|---|---|
| RTSP IPC -> WHEP 浏览器 | 监控上云、远程巡检、大屏看板 | 强烈建议 |
| RTMP OBS -> WHEP 浏览器 | 活动直播、电商开播、低延迟观看 | 推荐 |
| WHIP 采集端 -> RTMP CDN | WebRTC 进源站,继续用老分发链路 | 看上游支持 |
| RTSP 摄像头 -> RTMP 分发 | 老牌方案,接入简单但延迟偏高 | 存量保留 |
| WHIP 采集 -> RTSP/RTMP 转出 | 用 WebRTC 做接入,继续沿用老生态 | 过渡期好用 |
这张矩阵的价值在于提醒我们:技术选型不是“哪个新用哪个”,而是“输入端按设备能力选,输出端按终端能力选”。
4. 常见问题与排查:部署 WHIP/WHEP 最容易踩的坑
4.1 能拿到 SDP Answer,但浏览器一直黑屏
这是最常见的现象,信令已经通了,媒体却出不来。多半是编码不兼容。WebRTC 场景下浏览器对 H.264、VP8、VP9 支持最好,而摄像头常见的 H.265/HEVC 在 Chrome、Firefox 里支持很差。如果 SmartMediaKit 只做转封装不做转码,H.265 源发给浏览器就会黑屏或只有声音没有画面。排查方法就是打开
chrome://webrtc-internals
,看 inbound-rtp 的 mimeType;看到
video/H265
之类,基本就是源头编码问题。另外 H.264 的 profile 和 level 过高也可能触发兼容问题,尽量用 baseline 或 main profile 测试。
提示:WebRTC 不等于“所有编解码器都支持”。H.265 在部分 Safari 版本里可用,但绝不能作为默认兼容目标。
4.2 WHIP 推流推不上去,或者频繁断开
多数情况下是 ICE 打洞失败。WHIP 信令建立后,媒体能不能通,取决于两端能不能用 ICE 找到一条可用路径。内网测试时经常没问题,host candidate 就够了;一旦跨公网,没有 STUN/TURN 就只能碰运气。建议是:自建 coturn 或者使用云厂商的 TURN 服务,在 SmartMediaKit 的 WebRTC 配置里把 STUN/TURN 地址填上。排查时看 WebRTC 日志,确认有没有一对
srflx
或
relay
candidate 进入 selected candidate pair。只有 host candidate,且两端不在一张网里,那必然不稳定。
4.3 WHEP 延迟飘忽、码率越看越低
WebRTC 的 GCC 拥塞控制是“自适应降码率”的,链路丢包一上来,它会先把码率压下来保流畅,所以你会看到画面偶尔变模糊,但不会像 RTMP 那样明显卡顿。这不算故障,但能反映链路质量差。处理思路:一是检查网络丢包率,必要时换 TURN 路径或调整服务端部署位置;二是给流设定最大码率上限,防止突发带宽不足时拥塞控制反应过激;三是如果直播源本身码率很高,比如 4K 或高帧率,考虑用 Simulcast 或 SVC,让播放端按带宽选择合适层级。
4.4 多路并发一上来,CPU 和带宽双双告警
WebRTC 每路流都要做 SRTP 加解密、NACK 重传、拥塞控制,单路开销明显高于 RTMP 纯转发。压测时很容易发现 CPU 先顶不住。生产环境建议每路设置码率上限,打开 Simulcast/SVC 能力,让不同终端按需订阅,避免所有播放端都拿最全的流。横向扩展方面,多实例部署后按 streamId 维度做负载均衡,同一个流尽量集中在一个实例上,跨实例转发越少越好。SmartMediaKit 适合单机或中小规模,再往上就要引入集群架构。
| 现象 | 常见原因 | 检查项 | 应对 |
|---|---|---|---|
| 黑屏、无画面 | 编码不支持 / 源未转码 | inbound-rtp mimeType | 源转 H.264/VP8 |
| WHIP 推不上流 | ICE 打洞失败 | selected candidate pair | 配 STUN/TURN |
| 卡顿、码率下降 | 丢包 / 拥塞控制生效 | 丢包率、码率走势 | 优化链路、限制码率 |
| 并发低、CPU 高 | WebRTC 计算开销大 | CPU、带宽利用率 | 限制码率 + 集群 |
5. 如果是我做选型:WHIP/WHEP 取代不了谁,但能补齐谁
5.1 不急着“全切”,先把入口和出口解耦
我的观点很明确:WHIP/WHEP 在未来三五年内不会彻底取代 RTSP/RTMP,而是补足 Web 原生低延迟这一块。RTSP 最大的依仗是安防设备生态,摄像头、NVR、指挥调度系统已经围绕它转了几十年;RTMP 最大的依仗是推流工具链,OBS、FFmpeg、CDN 摄取入口都把 RTMP 当默认项。你很难让存量摄像头直接推 WHIP,也很难让整个直播行业一夜之间抛弃 RTMP。更务实的做法是把 SmartMediaKit 这类网关放在中间,入口保持设备支持什么就用什么,出口按终端能力选择。浏览器用户给 WHEP,老播放器继续走 RTSP/RTMP,手机端该用 HLS 还是用 HLS。
5.2 几个可以直接套用的判断标准
- 如果播放端以浏览器为主,对延迟要求低于 1 秒,优先 WHEP,不要再纠结 HLS。
- 如果采集端以 OBS、手机推流 SDK 为主,先保留 RTMP 入口,再逐步试点 WHIP。
- 如果是安防摄像头接入,入口坚持 RTSP/ONVIF,出口再考虑 WHEP。
- 如果团队没有 WebRTC 基础,选 SmartMediaKit 这种封装好的网关,别从零实现信令和媒体栈,否则光 ICE 打洞和 DTLS 调试就能拖垮整个项目周期。
5.3 一条 30 分钟内跑通的最小验证路径
这里给一条可以直接照做的最小闭环:本机用 Docker 起 SmartMediaKit,用 GStreamer test-launch 起动一路 RTSP 源,在 SmartMediaKit 管理端添加代理拉流,然后浏览器访问 WHEP 地址播放。整个过程不涉及公网、不涉及摄像头采购,足以验证 WHIP/WHEP 的延迟和稳定性预期。之后再逐步叠加 OBS WHIP 推流、TURN 中继、多实例集群,看生产环境能跑到什么指标。
最后说点个人体会。我踩过最大的坑,是把“换个新协议”当成目标,其实最重要的是链路整体能不能达到业务要求。WHIP/WHEP 很好,但不是银弹;RTSP/RTMP 很旧,但生态壁垒还在。最聪明的用法是把它们放在 SmartMediaKit 这类网关后面,各自干各自擅长的事。你不需要在设备端和播放端之间强推同一套协议,只需要保证中间转换足够稳。
更多推荐
所有评论(0)