4. 推流全链路概览
分辨率、帧率、码率,这三兄弟经常打架。我见过不少团队,一上来就推 1080p 60fps,结果卡成幻灯片。然后跑来问我:「为什么我的 WebRTC 这么卡?」
其实问题很简单——你选错了参数。分辨率越高,每帧数据量越大;帧率越高,每秒要处理的帧数越多。两者叠加,码率直接爆炸。网络扛不住,卡顿就来了。
先搞清楚一个核心公式
视频传输的带宽需求,大致可以这么算:
带宽 ≈ 分辨率宽 × 分辨率高 × 帧率 × 色彩深度 × 压缩比
注意,这只是个估算。实际编码器效率、画面复杂度都会影响。但你可以看到——分辨率和帧率是乘数关系。你同时拉高两者,带宽需求是指数级增长的。
关键认知: 分辨率和帧率不是越高越好。它们是一对跷跷板。你要根据场景,找到那个「刚刚好」的点。
不同场景的推荐配置
我根据自己的项目经验,整理了一张表。你可以直接拿来用:
| 场景 | 推荐分辨率 | 推荐帧率 | 说明 |
|---|---|---|---|
| 屏幕共享(PPT/文档) | 1920×1080 | 15 fps | 静态内容多,低帧率足够 |
| 屏幕共享(代码/IDE) | 1920×1080 | 30 fps | 滚动代码需要流畅 |
| 视频会议(单人) | 1280×720 | 30 fps | 720p 是性价比之王 |
| 视频会议(多人) | 640×480 | 24 fps | 小窗口下 480p 够用 |
| 直播推流(游戏) | 1920×1080 | 60 fps | 高帧率对游戏体验重要 |
| 直播推流(教学/讲座) | 1280×720 | 30 fps | 人像为主,30fps 流畅 |
| 移动端(弱网) | 640×360 | 20 fps | 保流畅,牺牲清晰度 |
我的习惯: 做屏幕共享时,我一般先设 15fps。如果用户反馈鼠标移动不跟手,再提到 30fps。别一上来就拉满。
帧率对卡顿的影响,比你想象的大
很多人只盯着分辨率,觉得「分辨率高才清晰」。但帧率对卡顿的影响,其实更直接。
你想想看:
- 帧率太低: 画面一卡一卡的,像幻灯片。人眼能感知到 15fps 以下的卡顿。
- 帧率太高: 编码器每帧的编码时间被压缩。如果 CPU 跟不上,编码延迟会飙升。延迟一高,接收端就感觉「卡」。
- 帧率波动: 比稳定低帧率更可怕。从 30fps 突然掉到 10fps,用户会明显感觉到「顿挫感」。
我在项目中遇到过一个问题:用户推 1080p 60fps,CPU 占用 90% 以上。编码器来不及处理,帧率实际只有 20fps 左右。但接收端看到的却是「忽快忽慢」——因为发送端在拼命丢帧。
避坑指南: 我曾经以为「帧率越高越流畅」。结果在弱网环境下,高帧率导致每个包都变小,但包数量暴增。UDP 丢包率直线上升。后来我学乖了——网络不好时,先降帧率,再降分辨率。
如何动态调整?WebRTC 的 Simulcast 和 SVC
手动配置是基础。但实际场景中,网络是动态变化的。你不能让用户自己去调分辨率吧?
WebRTC 提供了两种方案:
- Simulcast( simulcast 编码): 同时编码多个分辨率的流。接收端根据网络情况,选择合适的一路。比如同时推 720p、480p、360p 三路。
- SVC(可伸缩视频编码): 编码成一个流,但包含多个层级。网络好时解码全部,网络差时只解码基础层。
我个人更推荐 Simulcast。原因很简单——兼容性好。大部分浏览器都支持。SVC 虽然更优雅,但 VP9 的 SVC 支持度还不够广。
配置 Simulcast 的代码示例:
const pc = new RTCPeerConnection();
const transceiver = pc.addTransceiver(track, {
direction: 'sendonly',
sendEncodings: [
{ rid: 'h', maxBitrate: 2500000, scaleResolutionDownBy: 1.0 },
{ rid: 'm', maxBitrate: 800000, scaleResolutionDownBy: 2.0 },
{ rid: 'l', maxBitrate: 200000, scaleResolutionDownBy: 4.0 }
]
});
这段代码里:
rid: 'h'是高清流,分辨率不变,码率 2.5Mbpsrid: 'm'是中清流,分辨率缩小 2 倍,码率 800Kbpsrid: 'l'是低清流,分辨率缩小 4 倍,码率 200Kbps
接收端会自动切换。网络好时用 'h',变差时降级到 'm' 或 'l'。整个过程用户无感知。
核心思路: 不要试图用一个固定参数应对所有网络。动态调整才是王道。Simulcast 就是帮你做这件事的。
帧率与分辨率的权衡决策树
为了让你更直观地理解,我画了一张决策图。你可以根据场景,快速找到最优配置:
实战中的几个坑
嗯,这里要注意几个容易踩的坑:
- 别把帧率设成 60fps 就以为万事大吉。 如果编码器跟不上,实际帧率会剧烈波动。不如设一个稳定的 30fps。
- 分辨率降低不等于清晰度降低。 在移动端小屏幕上,720p 和 1080p 的差异几乎看不出来。但带宽节省了一半。
- 帧率对延迟的影响比分辨率大。 高帧率意味着更短的编码时间窗口。如果 CPU 不够强,编码延迟会飙升。延迟一高,用户就觉得「卡」。
- 动态调整时,先降帧率,再降分辨率。 这是我踩坑踩出来的经验。降帧率对画质影响小,用户感知弱。降分辨率会直接模糊,用户容易察觉。
一个小技巧: 在 WebRTC 的 RTCRtpSender 上,你可以动态调整 setParameters 里的帧率和分辨率。不需要重新创建 PeerConnection。这样切换非常平滑。
总结一下
分辨率与帧率的平衡,说白了就是「在有限的带宽下,找到用户体验的最优解」。没有万能参数,只有场景适配。
我的建议是:
- 先确定场景(屏幕共享?视频会议?直播?)
- 再根据网络条件动态调整
- 优先保证帧率稳定,再考虑分辨率
- 用 Simulcast 或 SVC 实现自适应
记住一句话:稳定的低帧率,好过波动的高帧率。 用户能接受 20fps 的流畅,但接受不了 30fps 突然掉到 10fps 的顿挫。