3. 分辨率与帧率设置:平衡画质与带宽的艺术

分辨率与帧率,是 WebRTC 编码参数里最直观、也最容易被误解的两个参数。很多人一上来就追求 1080p、60fps,觉得参数越高越好。但实际项目中,这种想法往往会带来灾难性的后果。

我记得有一次,一个客户坚持要在移动端用 1080p 做视频会议。结果呢?画面卡成幻灯片,带宽全被吃光,用户体验极差。最后我们不得不把分辨率降到 720p,帧率降到 24fps,才勉强能用。所以,理解分辨率与帧率的本质,比盲目堆参数重要得多。

3.1 分辨率对带宽和画质的影响

分辨率,说白了就是视频画面的像素数量。720p 是 1280×720,1080p 是 1920×1080。像素越多,画面细节越丰富,但带宽消耗也越大。

这里有个简单的数学关系:分辨率每提升一倍,像素数量就增加四倍。比如从 480p 到 720p,像素数从 307,200 增加到 921,600,差不多三倍。这意味着,在相同码率下,分辨率越高,每个像素能分到的码率就越少,画质反而可能下降。

核心结论:分辨率不是越高越好,而是要在带宽和画质之间找到平衡点。对于大多数实时通信场景,720p 已经足够清晰,1080p 更适合演示或录制场景。

我在项目中做过一个测试:在 1Mbps 的带宽下,分别用 480p、720p、1080p 推流。结果很有意思——480p 画面清晰流畅,720p 略有瑕疵但可接受,1080p 则出现了明显的马赛克和卡顿。为什么?因为 1080p 需要的码率至少是 2-3Mbps,1Mbps 根本喂不饱它。

分辨率 像素数 推荐最低码率 典型场景
480p (640×480) 307,200 300-500 Kbps 低带宽、移动端
720p (1280×720) 921,600 800-1500 Kbps 通用视频会议
1080p (1920×1080) 2,073,600 2000-4000 Kbps 高清演示、录制
4K (3840×2160) 8,294,400 8000-16000 Kbps 专业直播、医疗

我的经验:实际项目中,我通常把 720p 作为默认分辨率。如果带宽充足(>2Mbps),再考虑升到 1080p。记住,流畅的 720p 永远比卡顿的 1080p 体验好。

3.2 帧率选择原则

帧率,就是每秒显示的画面数量。常见的帧率有 15fps、24fps、30fps、60fps。帧率越高,画面越流畅,但带宽消耗也越大。

你想想看,电影通常用 24fps,电视用 30fps,游戏才用 60fps。为什么?因为不同场景对流畅度的要求不一样。视频会议中,人的面部动作和手势变化,30fps 已经足够。60fps 更多用于体育直播或游戏画面。

我个人习惯把帧率选择分成三类:

  • 15fps:低带宽场景,比如 3G 网络或信号不好的地方。画面会有轻微卡顿,但至少能保持通信。
  • 24-30fps:通用场景,适合大多数视频会议、在线教育、远程医疗。这是我最推荐的区间。
  • 60fps:高动态场景,比如游戏直播、体育赛事。带宽消耗大,慎用。

这里有个常见的误区:很多人觉得帧率越高越好,其实不然。帧率增加一倍,码率也要增加一倍左右。如果你带宽有限,强行上高帧率只会导致画面模糊或卡顿。

避坑指南:我曾经在一个项目中,为了追求流畅度,把帧率设成了 60fps。结果带宽不够,编码器自动降低了分辨率,画面变得模糊不清。后来我改成 30fps,分辨率稳定在 720p,用户体验反而更好。所以,帧率和分辨率要一起考虑,不能单独优化。

3.3 动态分辨率调整策略

网络环境是动态变化的,不可能一直保持稳定。所以,我们需要一种机制,让编码器根据当前网络状况自动调整分辨率。这就是动态分辨率调整策略。

WebRTC 本身提供了带宽估计(Bandwidth Estimation)机制,可以实时检测网络带宽。我们可以利用这个信息,动态调整分辨率。具体怎么做呢?

我常用的策略有三种:

  1. 阶梯式降级:预设几个分辨率档位(比如 1080p → 720p → 480p → 360p),当带宽下降到某个阈值时,自动切换到下一档。这种方式简单可靠,但切换时会有明显的画面突变。
  2. 平滑降级:根据带宽变化,连续调整分辨率。比如带宽从 2Mbps 降到 1.5Mbps,分辨率从 1080p 逐渐降到 900p。这种方式更平滑,但实现复杂。
  3. 混合策略:结合帧率和分辨率一起调整。比如带宽下降时,先降低帧率(从 30fps 降到 24fps),如果还不够,再降低分辨率。这种方式能最大化利用带宽。

我个人比较推荐混合策略。为什么呢?因为人眼对帧率下降的敏感度低于分辨率下降。先降帧率,用户可能感觉不到;但直接降分辨率,画面变模糊,用户立刻就能察觉。

实战代码示例:下面是一个简单的动态分辨率调整逻辑,基于带宽估计结果自动切换分辨率。

// 动态分辨率调整示例
function adjustResolution(bandwidthKbps) {
  // 预设分辨率档位
  const profiles = [
    { width: 1920, height: 1080, minBandwidth: 2000 },
    { width: 1280, height: 720,  minBandwidth: 800 },
    { width: 640,  height: 480,  minBandwidth: 300 },
    { width: 320,  height: 240,  minBandwidth: 100 }
  ];

  // 根据带宽选择合适的分辨率
  let selected = profiles[profiles.length - 1];
  for (let profile of profiles) {
    if (bandwidthKbps >= profile.minBandwidth) {
      selected = profile;
      break;
    }
  }

  // 应用分辨率
  const constraints = {
    video: {
      width: { ideal: selected.width },
      height: { ideal: selected.height }
    }
  };

  return constraints;
}

// 监听带宽变化
pc.addEventListener('iceconnectionstatechange', () => {
  if (pc.iceConnectionState === 'connected') {
    // 获取当前带宽估计
    const stats = pc.getStats();
    stats.then(reports => {
      reports.forEach(report => {
        if (report.type === 'candidate-pair' && report.state === 'succeeded') {
          const bandwidth = report.availableOutgoingBitrate / 1000; // 转为 Kbps
          const constraints = adjustResolution(bandwidth);
          // 重新协商
          pc.getSenders().forEach(sender => {
            if (sender.track.kind === 'video') {
              sender.track.applyConstraints(constraints.video);
            }
          });
        }
      });
    });
  }
});

这段代码的核心逻辑是:根据带宽估计结果,从预设的分辨率档位中选择最合适的一个。带宽越高,分辨率越高;带宽下降,自动降级。注意,这里用了 applyConstraints 来动态调整分辨率,不需要重新创建 PeerConnection。

我的建议:实际项目中,不要只依赖带宽估计。还要考虑 CPU 负载、网络延迟、丢包率等因素。我通常会把多个指标综合起来,做一个加权评分,再决定是否调整分辨率。这样更稳健。

3.4 知识体系总览

为了让你更直观地理解分辨率与帧率的设置逻辑,我画了一张流程图。它展示了从网络状况到参数调整的完整链路。

分辨率与帧率调整流程 分辨率与帧率动态调整流程 网络状况监测 带宽充足? 是 保持高分辨率 (1080p / 30fps) 否 启动降级策略 (混合策略:先降帧率,再降分辨率) 步骤1:降低帧率 (30fps → 24fps) 步骤2:降低分辨率 (720p → 480p) 注意: 降级后持续监测 带宽恢复后自动升级

这张图展示了完整的调整链路:先监测网络状况,判断带宽是否充足;如果充足,保持高分辨率;如果不足,启动降级策略。降级时,我建议先降帧率,再降分辨率。这样用户感知最小。

3.5 总结与实战建议

好了,关于分辨率与帧率,我该说的都说完了。最后给你几个实战建议:

  • 默认用 720p + 30fps:这是最稳妥的组合,适合 90% 的场景。
  • 动态调整是必须的:不要写死分辨率,一定要根据网络状况动态调整。
  • 先降帧率,再降分辨率:人眼对帧率下降不敏感,但对分辨率下降很敏感。
  • 做好降级体验:切换分辨率时,尽量平滑过渡,避免画面突变。

最后提醒:我曾经见过一个团队,把动态分辨率调整做得太激进,导致画面频繁切换,用户投诉不断。所以,调整频率要控制好,建议每隔 5-10 秒评估一次,不要每秒都变。