4、屏幕流约束:分辨率设置、帧率控制、视频编码器选择(VP8/VP9/H264)
屏幕共享这件事,说起来简单——把屏幕内容抓下来发出去就行。但真正做过的人都知道,坑全藏在细节里。分辨率设多少?帧率要不要锁?编码器选哪个?这些参数调不好,用户那边看到的要么是马赛克,要么是卡成PPT。
我个人习惯把屏幕流约束分成三个维度来考量:画质、流畅度、兼容性。这三者往往互相打架,你得根据场景做取舍。下面我一个个拆开讲。
4.1 分辨率设置:不是越高越好
很多人一上来就设 1920x1080,觉得高清才专业。其实不然。屏幕共享的分辨率,取决于你共享的内容类型。
我遇到过这样一个项目:客户要求共享 4K 设计稿,结果接收端全是 1366x768 的笔记本。你传 4K 过去,对方还得缩放看,反而浪费带宽和 CPU。
分辨率设置的核心原则是:匹配接收端,而不是匹配源端。
推荐的分辨率策略:
- 代码/文档共享:1280x720 足够,文字清晰即可
- 设计稿/视频预览:1920x1080,保证细节可见
- PPT 演示:1366x768 或 1920x1080,看观众设备
- 移动端共享:720p 以内,避免发热和卡顿
代码里怎么设?看这个例子:
// 获取屏幕流时设置分辨率约束
const constraints = {
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 15 }
}
};
const stream = await navigator.mediaDevices.getDisplayMedia(constraints);
注意这里用的是 ideal 而不是 exact。为什么?因为浏览器不一定支持你指定的分辨率,用 ideal 会让浏览器尽量靠近,而不是直接报错。嗯,这个坑我踩过——用 exact 设 1920x1080,结果用户外接显示器拔了,直接黑屏。
4.2 帧率控制:15fps 还是 30fps?
帧率这个问题,说白了就是「流畅度」和「资源消耗」之间的博弈。
屏幕共享和摄像头视频不一样。摄像头拍的是连续运动,30fps 是基本要求。但屏幕共享呢?你想想看,大部分时候屏幕内容是不动的——你在看文档、写代码、浏览网页。这时候 30fps 纯属浪费。
我个人的经验是:
| 场景 | 推荐帧率 | 原因 |
|---|---|---|
| 静态文档/代码 | 5-10 fps | 内容几乎不变,低帧率省带宽 |
| PPT 翻页演示 | 10-15 fps | 翻页时有动画,但不需要太高 |
| 视频播放共享 | 24-30 fps | 视频本身需要流畅,否则卡顿明显 |
| 游戏/设计软件 | 30 fps | 操作频繁,低帧率影响体验 |
小技巧:你可以动态调整帧率。检测到屏幕内容变化频繁时提高帧率,静止时降低。WebRTC 的 RTCRtpSender.setParameters() 可以实时改帧率,不用重新获取流。
我曾经做过一个在线教育项目,老师共享 PPT 时用了 30fps,结果学生端带宽不够,画面一直缓冲。后来改成 10fps,问题解决了,而且老师翻页的动画效果也没受影响。你想想看,PPT 翻页也就一秒的事,10fps 完全够用。
4.3 视频编码器选择:VP8、VP9、H264 怎么选?
这是个大话题。三个编码器各有优劣,选错了就是灾难。
先看一张对比表:
| 特性 | VP8 | VP9 | H264 |
|---|---|---|---|
| 兼容性 | Chrome/Firefox 原生支持 | Chrome 支持,Firefox 部分支持 | 几乎所有浏览器 + 硬件编码 |
| 压缩率 | 中等 | 高(比 VP8 省 30-50% 带宽) | 中等(与 VP8 接近) |
| 编码速度 | 快 | 慢(CPU 消耗大) | 快(有硬件加速) |
| 屏幕共享适用性 | 好 | 适合静态内容 | 最好(硬件编码不占 CPU) |
我个人在实际项目中的选择逻辑是这样的:
VP8:最稳妥的选择
VP8 是 WebRTC 的默认编码器,所有浏览器都支持。如果你不想折腾兼容性问题,选 VP8 准没错。但它的压缩率一般,带宽紧张时画质下降明显。
VP9:省带宽,但吃 CPU
VP9 的压缩率确实好,同样的画质下带宽能省一半。但代价是编码计算量大,CPU 占用高。我做过测试,在 i5 处理器上编码 1080p 30fps 的屏幕流,VP9 的 CPU 占用比 VP8 高了 40%。
所以 VP9 适合什么场景?静态内容为主、接收端带宽有限、发送端 CPU 够用。比如远程桌面、文档协作这类场景。
注意:VP9 在 Safari 上不支持。如果你的用户有 Mac 用户,慎用 VP9。
H264:硬件加速是杀手锏
H264 最大的优势是硬件编码。现在的笔记本、手机基本都有 H264 硬件编码器,编码几乎不占 CPU。这对屏幕共享来说太重要了——你想想,用户一边共享屏幕一边开其他应用,CPU 被编码器吃光了,其他应用卡成狗,体验能好吗?
我做过一个在线会议项目,一开始用 VP8,用户反馈共享屏幕时电脑风扇狂转。换成 H264 硬件编码后,CPU 占用从 60% 降到了 15%,风扇声音小多了。
代码里怎么指定编码器?看这里:
// 创建 RTCPeerConnection 时指定编码器优先级
const pc = new RTCPeerConnection({
sdpSemantics: 'unified-plan'
});
// 在 createOffer 之前设置编码器偏好
const transceiver = pc.addTransceiver('video', {
direction: 'sendonly',
sendEncodings: [
{
rid: 'h264',
codecPayloadType: 107, // H264 的 payload type
maxBitrate: 2000000
}
]
});
// 或者通过修改 SDP 来调整编码器顺序
// 把 H264 移到 VP8 前面,优先使用 H264
嗯,这里要注意:不同浏览器的编码器支持情况不一样。Chrome 支持 VP8/VP9/H264,Firefox 支持 VP8/VP9(H264 需要特定版本),Safari 只支持 H264。所以实际项目中,我一般会做一个编码器协商逻辑:
- 先检测浏览器支持的编码器列表
- 按 H264 > VP9 > VP8 的优先级尝试
- 如果 H264 硬件编码可用,优先使用
- 如果 CPU 占用过高,降级到 VP8
我的建议:
- 通用场景:用 VP8,兼容性最好
- 带宽敏感场景:用 VP9,省带宽
- 性能敏感场景:用 H264 硬件编码,省 CPU
- 混合场景:动态切换,根据网络和 CPU 状况自适应
4.4 知识体系总览
说了这么多,我画了一张图帮你理清思路。屏幕流约束的核心就是三个维度,每个维度下有不同的选择策略:
这张图把三个维度的关系理清楚了。你实际做项目时,就是在这三个维度里找平衡点。没有银弹,只有最适合你场景的方案。
最后说一句:别在代码里写死这些参数。做成可配置的,让用户或者运维人员能根据实际情况调整。我见过太多项目因为写死了分辨率或编码器,上线后出问题还得紧急发版。灵活一点,省心很多。