WebCodecs 刚出来,正是为了补全 Web 在音视频处理上的短板,按理说视频会议这类应用应该如鱼得水。但现实中,一些团队反而在考虑把核心处理移出 Web,为什么呢
2023年开始,VideoEncoder 和 VideoDecoder 在 Chrome 等现代浏览器里陆续落地,他们是浏览器封装的视频处理api,而这些api天然和webrtc等media功能共存。有了 WebCodecs,意味着我们不再需要把 YUV 数据传到服务器才能处理,也不用忍受 WASM 软解带来的功耗和性能损耗。在官网介绍里,WebCodecs API 直接点名了它的适用场景:视频会议(Video Conferencing)。
按常理出牌,接下来应该是 Web 端在线剪辑、AI 生成视频、低延迟直播全面开花,视频会议这种“纯实时交互”应用应该彻底 Web 化才对。
然而,如果你关注过一些底层技术论坛或者参与过大型 WebRTC 应用的选型,可能会发现一个微妙的趋势:对于那些对延迟、稳定性和码率控制极其苛刻的视频会议场景,一些团队不但没有全面拥抱 WebCodecs,反而在考虑将编码、解码甚至整个媒体处理管道“踢”出浏览器,交给 Wasm 或者 Native 客户端去做。 我们之前对接的某康实现方案里,甚至开发了浏览器插件/托盘,将rtsp/私有流解码出来,贴在浏览器上面,作为模拟的实现。
在我看来,这更像是传统音视频公司对自己经营生态的一种保护,这其实不利于生产力提升。
所以我自己搞了一个非常简单的基于webcodec的私有协议,并基于此实现了视频会议, 供大家学习参考。
https://github.com/shiqifeng2000/Webtalk
起初,这只是一个webrtc的实现,webrtc 是udp连接,在阿里云这种以api为中心的供应商中,udp端口往往很不友好,首先就有安全扫描,其次端口管控等等。我们团队的运维就经常吐槽我的webrtc要开50个端口,别人只需要开2个tcp端口就可以。
所以webrtc的确部署很重,既然如此,我们能不能换一个方案呢。
如果不考虑webrtc提供的防抖,缓存,异或等功能,我们可以有很多选择,比如mp4dash, hls。但是HLS、Dash都是需要至少缓存一个gop的,放在常用的安防领域,一个gop=50帧,25fps下大约2秒。 所以我开始考虑用webcodec实现一套轻量型视频会议,http/websocket为媒介, 当然tcp模式下,可能会议阻塞,传输方法回头换quic也可以,也可以通过其他方式防止阻塞,进行保活,这里也不展开讨论了。
使用webcodec,那我们就不得不考虑如何封装私有协议,这里我设计了一个ESStream
Camera/Mic ──▶ Video/AudioEncoder ──▶ HTTP/WS Streaming ──▶ RFC6381 Wrapping ──▶ HTTP/WS Streaming ──▶ Video/AudioDecoder ──▶ Frames ──▶ Video/Audio WritableStream ──▶ Video/Audios
我们的 ESBox 协议设计得相当简洁——只有四种 Box 类型:acnf(音频配置)、afrm(音频帧)、vcnf(视频配置)、vfrm(视频帧)。配合自定义分隔符机制,理论上可以轻松实现 WebRTC 与 HTTP 生态的互通。
具体实现上,以SFU的模式实现,推流端创建“频道”,拉流端消费“频道数据”。纯http模式下E2E测试因为没有webrtc的各种握手机制,所以反而首帧上来更快,这是出乎我意料的。首帧之后,延迟稳定在<100ms左右(网络下)
美中不足就是音视频必须分离,就像webcodec设计的那样,DecodedVideo和DecodedAudio属于不同的webworker.js,所以是分开喂数据的
关于多播: 因为是自研协议,所以编码端的参数(码率帧率)和解码端的webworker是可以随时切的。所以不需要多路发留。SVC 依赖浏览器上的实现。 所以现在我们就有了一个非常简单方便的一个视频会议框架,我们用类似whip/whep的方式开启一个频道,将webcodec生成的chunk发送到基于tokio搭建的web框架中,如果我们需要多媒体处理,我们可以再这一层做很多事情,如果我们只是需要转发,那我们只需要拷贝一下,封装为ES流,发送给频道注册的端。
由于这里没有GOP缓存,所以首帧几乎是秒开的,即便是其他消费者(中途进入),也会在一个GOP时间内至少得到一个I帧,经测试延迟和webrtc基本一致。小型音视频没有webrtc灵活,大型视频类(2k+)反而比webrtc更稳定。
评论区
写评论还没有评论