一、信心满满的开局
上一篇文章确定了技术选型:RTMP推流 + SRS转发 + FLV拉流 + WebSocket信令。
但我当时想得有点美:既然SRS 5.0支持WHIP协议,是不是可以写一个简单的网页,让主播打开浏览器就能推流,不用装OBS?
理论上行得通:
-
getUserMedia获取摄像头画面,几行代码的事 -
创建
RTCPeerConnection,SDP offer发给SRS的WHIP端点 -
SRS返回answer,连接建立,开始推流
代码很快就写好了,SRS也跑起来了。摄像头画面确实推上去了,SRS后台也能看到流。
然后问题就来了。
二、码率诡异被压:设置4000kbps,实际只有136kbps
我设置的是:
javascript
const params = videoSender.getParameters();
params.encodings[0].maxBitrate = 4000000; // 4Mbps
videoSender.setParameters(params);
去SRS后台一看:
text
bitrate: 136 kbps
136kbps。一帧1080P的关键帧可能都比这个大。
画面什么样?糊成一团,比马赛克强不了多少。
排查过程
先确认是不是SRS的问题。用OBS推一路RTMP流到同一个SRS实例:
-
OBS NVENC硬编码,码率设置2000kbps
-
SRS后台显示:1950kbps,非常稳定
-
播放端画面:清晰流畅,1080P 60fps
结论:播放链路没问题,SRS没问题,问题出在浏览器推流这一端。
三、锁定真凶:Windows MediaFoundation H.264硬编码的已知Bug
打开 chrome://webrtc-internals,找到推流的 VideoSendStream,一看:
text
codecId: H264 hardware
bitrate: 136kbps
用的是H.264硬件编码,不是软件编码。
顺着这个线索搜了一圈,结果让我哭笑不得------这是一个被多家RTC厂商明确记录的已知Bug:
"在所有使用 AMD 芯片和部分使用 Intel 芯片的 Windows 设备上,Chrome 使用 H.264 编码时,发送码率可能达不到设定值。"------即构科技官方文档
Flashphoner的文档说得更直接:
"在Windows 10/8上Chrome浏览器开启硬件加速时,码率问题可能出现。症状:画面质量低、模糊,chrome://webrtc-internals中显示的码率低于100kbps。"
Stack Overflow上也有开发者遇到了同样的问题。不是SRS的锅,不是WHIP的锅,不是浏览器的锅------是Windows的锅。
为什么会这样?
根本原因在于整条编码链路:
text
Chrome WebRTC → Windows MediaFoundation H.264 编码器 → GPU驱动 → 硬件编码单元
Chrome为了降低CPU占用,默认调用Windows的MediaFoundation框架进行H.264硬编码。MediaFoundation再调用GPU(AMD/Intel/NVIDIA)的硬件编码单元。问题就出在GPU驱动层------部分GPU厂商对视频编码的码率做了上限限制,导致无论你设置多大的码率,实际输出都被卡在很低的水平。
四、第一个尝试:强制使用VP8软件编码
既然H.264硬编码有问题,那就绕过它。VP8是Google主推的编码格式,Chrome用的是libvpx软件编码器,完全不经过MediaFoundation。
做法是强制指定VP8为首选编码:
javascript
const videoTransceiver = pc.getTransceivers().find(
t => t.sender.track?.kind === 'video'
);
const caps = RTCRtpSender.getCapabilities('video');
const vp8Codecs = caps.codecs.filter(c => c.mimeType === 'video/VP8');
videoTransceiver.setCodecPreferences(vp8Codecs);
推流,看SRS后台------
码率上去了!2000kbps稳稳的!
还没来得及高兴,问题又来了。
画面开始一顿一顿的,帧率从30fps掉到10-15fps。打开任务管理器一看:
CPU占用:85%+
VP8软件编码正在用CPU死磕视频压缩,把浏览器进程直接拉满了。
五、第二个尝试:关闭浏览器硬件加速
Flashphoner文档里还提了另一个方案:关闭Chrome硬件加速。
原理很简单------强制H.264也走软件编码,绕开GPU驱动的限制。
Chrome设置 → 系统 → 关闭"使用硬件加速模式" → 重启浏览器。
再推流,码率正常了,但画面还是比OBS推的差一些。而且这个方案有个致命问题:你不可能要求每个用户去改浏览器设置。产品化完全走不通。
六、第三个尝试:降低参数勉强妥协
最后试了降分辨率、降帧率、降码率------VP8跑720P、1000kbps,CPU占用降到50%左右,勉强能用。但画质跟OBS推的同码率流比起来,差距明显。
七、回过头看:B站、抖音为什么不用浏览器推流?
踩完这些坑,我回头看B站的直播方案,突然就理解了。
B站直播有两种方式:
-
直播姬:B站自研的客户端。本质是OBS套壳,直接调用系统硬件编码器
-
OBS等第三方工具:获取推流地址后手动配置
两种方式的共同点是:都用原生客户端,不用浏览器。
抖音更严格:根据平台规则,推流分辨率必须≥1080P、码率要达到6-8Mbps,否则会被限流。用浏览器VP8软件编码跑1080P 6Mbps,基本上是在开玩笑。
所以并不是这些大厂"做不到"浏览器推流,而是权衡之后主动选择了不用:
| 方案 | 编码方式 | CPU占用 | 画质 | 码率稳定性 | 适合场景 |
|---|---|---|---|---|---|
| OBS推流 | GPU硬编码 (NVENC/QSV等) | 极低 | 高 | 稳定 | 正式直播 |
| 浏览器+VP8 | CPU软编码 (libvpx) | 极高 | 中 | 一般 | 临时测试 |
| 浏览器+H.264 | Windows硬编码 | 低 | 低 | 被卡 | 不推荐 |
八、最终结论:浏览器推流的定位
经过这一番折腾,我对"浏览器推流"这件事有了清晰的认识:
-
Windows上浏览器推流有硬伤:MediaFoundation H.264硬编码的码率限制Bug是GPU驱动层面的问题,浏览器和应用层代码都绕不过去
-
VP8软件编码能绕过限制,但性能代价太大:高清场景下CPU直接拉满,画面卡顿
-
浏览器推流适合的场景:快速测试、低分辨率应急开播、对画质要求不高的内部工具
-
正式直播还是乖乖用OBS:B站、抖音的选择不是没道理的
所以这个推流网页,我保留了,但定位改了------快速开播测试页,而不是正式的直播工具。主播正式开播时,引导他们用OBS。
技术选型有时候不是找到"最好的方案",而是找到"最适合你场景的方案"。浏览器推流这条路,我走了一遍,踩了坑,也摸清了边界。希望这篇记录能让你少踩几个坑。