媒体约束精讲:视频分辨率与帧率设置

媒体约束,说白了就是告诉浏览器:「我要什么样的摄像头和麦克风」。

我个人习惯把 getUserMedia 的约束参数分成三块:视频、音频、高级选项。今天我们先啃最硬的那块骨头——视频约束。

分辨率:不是越大越好

很多新手一上来就写 width: 1920, height: 1080,结果发现手机摄像头不支持,直接报错。

我建议你这样做:

const constraints = {
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 }
  }
};

看到 ideal 了吗?它表示「理想值」,浏览器会尽量满足,但不行就降级。还有 minmaxexact 三个关键字:

关键字 含义 使用场景
exact 精确匹配,不满足就报错 必须用 4K 录制时
ideal 理想值,允许降级 日常推荐
min 最小值下限 保证清晰度底线
max 最大值上限 限制带宽占用
注意: 不要同时使用 exactideal,它们会冲突。我见过有人这样写,结果浏览器直接抛 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 应用才能在各种设备上稳定运行。
媒体约束知识体系 getUserMedia 约束 视频约束 width / height (分辨率) frameRate (帧率) facingMode / deviceId 音频约束 sampleRate (采样率) channelCount (声道数) noiseSuppression / echoCancellation 高级约束 aspectRatio / resizeMode autoGainControl / latency 核心原则:多用 ideal,少用 exact
避坑指南: 我曾经在项目中直接用了 exact: 1920x1080,结果用户的老旧笔记本直接黑屏。后来改成 ideal 配合 min: 640x480,问题解决。记住:兼容性比画质更重要。
公众号:蓝海资料掘金营,微信deep3321