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。所以实际项目中,我一般会做一个编码器协商逻辑:

  1. 先检测浏览器支持的编码器列表
  2. 按 H264 > VP9 > VP8 的优先级尝试
  3. 如果 H264 硬件编码可用,优先使用
  4. 如果 CPU 占用过高,降级到 VP8

我的建议:

  • 通用场景:用 VP8,兼容性最好
  • 带宽敏感场景:用 VP9,省带宽
  • 性能敏感场景:用 H264 硬件编码,省 CPU
  • 混合场景:动态切换,根据网络和 CPU 状况自适应

4.4 知识体系总览

说了这么多,我画了一张图帮你理清思路。屏幕流约束的核心就是三个维度,每个维度下有不同的选择策略:

屏幕流约束三大维度 分辨率设置 • 1280x720(代码/文档) • 1920x1080(设计/视频) • 1366x768(PPT演示) • 720p以内(移动端) 帧率控制 • 5-10 fps(静态内容) • 10-15 fps(PPT翻页) • 24-30 fps(视频播放) • 30 fps(游戏/设计) 编码器选择 • VP8(兼容性最好) • VP9(省带宽吃CPU) • H264(硬件加速) • 动态协商策略 核心原则:根据场景做取舍 画质 ↔ 流畅度 ↔ 兼容性,三者不可兼得

这张图把三个维度的关系理清楚了。你实际做项目时,就是在这三个维度里找平衡点。没有银弹,只有最适合你场景的方案。

最后说一句:别在代码里写死这些参数。做成可配置的,让用户或者运维人员能根据实际情况调整。我见过太多项目因为写死了分辨率或编码器,上线后出问题还得紧急发版。灵活一点,省心很多。