媒体约束精讲:视频分辨率与帧率设置
媒体约束,说白了就是告诉浏览器:「我要什么样的摄像头和麦克风」。
我个人习惯把 getUserMedia 的约束参数分成三块:视频、音频、高级选项。今天我们先啃最硬的那块骨头——视频约束。
分辨率:不是越大越好
很多新手一上来就写 width: 1920, height: 1080,结果发现手机摄像头不支持,直接报错。
我建议你这样做:
const constraints = {
video: {
width: { ideal: 1280 },
height: { ideal: 720 }
}
};
看到 ideal 了吗?它表示「理想值」,浏览器会尽量满足,但不行就降级。还有 min、max、exact 三个关键字:
| 关键字 | 含义 | 使用场景 |
|---|---|---|
exact |
精确匹配,不满足就报错 | 必须用 4K 录制时 |
ideal |
理想值,允许降级 | 日常推荐 |
min |
最小值下限 | 保证清晰度底线 |
max |
最大值上限 | 限制带宽占用 |
exact 和 ideal,它们会冲突。我见过有人这样写,结果浏览器直接抛 OverconstrainedError。
帧率:流畅与性能的平衡
帧率决定了视频的流畅度。30fps 是标准,60fps 适合游戏直播,15fps 以下会明显卡顿。
我曾经在做一个远程医疗项目时,发现 60fps 导致 CPU 占用飙到 90%,画面反而因为丢帧变得更卡。后来改成 30fps,CPU 降到 40%,体验反而好了。
const constraints = {
video: {
frameRate: { ideal: 30, min: 15 }
}
};
嗯,这里要注意:帧率越高,编码压力越大。移动端建议最高 30fps。
音频采样率与声道设置
音频约束经常被忽略,但它在语音通话、录音场景里至关重要。
采样率:决定声音的「分辨率」
采样率越高,声音还原度越好。常用的有:
- 8000Hz:电话音质,够用但很糊
- 16000Hz:宽带语音,适合 VoIP
- 44100Hz:CD 音质,音乐录制标配
- 48000Hz:专业音频,WebRTC 默认值
我个人习惯语音通话用 16000Hz,音乐录制用 48000Hz。为什么?因为 48000Hz 的数据量是 16000Hz 的 3 倍,网络不好的时候会卡。
const constraints = {
audio: {
sampleRate: { ideal: 48000 },
channelCount: { ideal: 2 }
}
};
声道:单声道还是立体声?
大部分场景用单声道就够了。立体声虽然听起来更「沉浸」,但数据量翻倍,而且很多笔记本麦克风本身就是单声道,你设了立体声也没用。
MediaStream 后再用 getSettings() 查看实际参数。
设备ID精确指定
你有没有遇到过这种情况:用户插了外接摄像头,但 WebRTC 还是用内置摄像头?
解决办法就是使用 deviceId。
// 先枚举设备
const devices = await navigator.mediaDevices.enumerateDevices();
const videoDevices = devices.filter(d => d.kind === 'videoinput');
// 然后指定设备
const constraints = {
video: {
deviceId: { exact: videoDevices[1].deviceId }
}
};
我记得有一次做多摄像头切换功能,用户要求能自由切换前后摄像头。如果不指定 deviceId,浏览器会随机选一个,体验非常差。
deviceId 在同一个域名下是稳定的,但不同域名或清除浏览器数据后会变。不要把它存到数据库里做长期绑定。
高级约束与降噪处理
WebRTC 还提供了一些高级约束,能帮你做降噪、回声消除等处理。
内置降噪开关
const constraints = {
audio: {
noiseSuppression: true, // 降噪
echoCancellation: true, // 回声消除
autoGainControl: true // 自动增益
}
};
这三个属性默认就是 true,但不同浏览器的实现质量差别很大。我曾经在 Chrome 上测试降噪效果很好,但换到 Safari 就发现背景噪音完全没消掉。
为什么会这样?因为浏览器只是「建议」开启,具体算法由底层驱动决定。如果你需要稳定的降噪效果,建议用 Web Audio API 做后处理。
视频高级约束
视频方面还有一些不太常用但很有用的约束:
facingMode:指定摄像头方向(user/environment)aspectRatio:强制画面比例(如 16:9)resizeMode:是否允许浏览器裁剪画面
const constraints = {
video: {
facingMode: { exact: 'environment' }, // 强制后置摄像头
aspectRatio: { ideal: 16/9 },
resizeMode: 'crop-and-scale'
}
};
ideal,少用 exact,给浏览器留出降级空间。这样你的 WebRTC 应用才能在各种设备上稳定运行。
exact: 1920x1080,结果用户的老旧笔记本直接黑屏。后来改成 ideal 配合 min: 640x480,问题解决。记住:兼容性比画质更重要。