WebRTC 系列之视频辅流
导读:近几年,实时音视频领域越来越热,业界很多音视频引擎都是基于 WebRTC 进行实现的。本文主要介绍 WebRTC 在视频辅流上的需求背景以及相关技术实现。
文|陶金亮
网易云信资深客户端开发工程师
WebRTC 中的 SDP 支持两种方案:PlanB 方案 和 Unified Plan 方案。早期我们使用多PeerConnection的 Plan B 方案中只支持一条视频流发送,这条视频流,我们称之为”主流”。目前我们使用单 PeerConnection 的 Unified Plan 方案,新增一条视频辅流,何为视频”辅流”?视频辅流是指第二条视频流,一般用于屏幕共享。
需求背景
随着业务的发展,一路视频流满足不了更多实际业务场景的需求,例如在多人视频聊天、网易会议以及其他在线教育场景下,需要同时发送两路视频流:一路是摄像头流,另一路是屏幕共享流。
但是,目前使用 SDK 分享屏幕时,采用的是从摄像头采集通道进行屏幕分享。在该方案下,分享者只有一路上行视频流,该场景中要么上行摄像头画面,要么上行屏幕画面,两者是互斥的。
除非实例一个新的 SDK 专门采集并发送屏幕画面,但实例两个 SDK 的方案在业务层处理起来十分麻烦且会存在许多问题,例如如何处理两个流间的关系等。
在 WebRTC 场景中,还存在一种可以单独为屏幕分享开启一路上行视频流的方案,并称之为“辅流(Substream)”。辅流分享即共享者同时发布摄像头画面和屏幕画面两路画面。
另外,有了这个辅流的通道,当设备为新版本 iPhone(新版本 iPhone 具有同时开启前后摄像头的能力)时,也为支持前后2路摄像头发送视频数据奠定了基础。
技术背景
前期 SDK 的架构设计是一个多 PeerConnection 的模型,即:一个 PeerConnection 对应一路音视频流。随着新的 SDP(Session Description Protocol)格式(UnifyPlan)的推出和支持,一个 PeerConnection 可以对应多路音视频流,即单 PeerConnection 模型,即基于单 PC 的架构,允许创建多个 Transceiver,用于发送多条视频流。
技术实现
目前视频流主要分为三类:Camera 流、屏幕共享流、自定义输入视频流,分别有不同属性:
将 Camera 流作为主流,支持 Simulcast;
将自定义视频输入(非屏幕共享)作为主流,不支持 Simulcast;
将屏幕共享作为辅流,不支持 Simulcast,有单独的屏幕共享编码策略;
由于 iOS 屏幕共享的特殊性,其需要通过自定义视频输入的方式来获取视频数据,因此存在如下图所示的流程图:
综上所述:iOS 的自定义输入既可以使用主流的通道发送视频(非屏幕共享),也可以使用辅流的通道发送视频(屏幕共享)。
如果是其他平台,例如 Mac、Win、Aos 等,则会相对简单,摄像头数据和屏幕共享的数据都来自于 SDK 内部,外部自定义视频输入的数据才来自于外部。
关键类图
上述提到的单 PC 架构,目前会有2个 RtpTransceiver,一个是 AudioTransceiver,一个是 VideoTransceiver,而辅流的屏幕共享会在新增一个 RtpTransceiver。一个 VideoRtpSender 会包含一个 VideoMediaChannel。
辅流改动
实现辅流需要对不同层面都做一些调整以及重构,具体如下:
信令层面需要支持多路视频流,使用 mediaType 用于区分上述的 Camera 流(Video)、屏幕共享流(ScreenShare)、自定义视频输入流(externalVideo);
重构跨平台层的 Capture 和 Source 的管理;
重构用户和渲染画布的管理,从一个 UID 对应一个 render,过渡到一个 UID 的 sourceId 对应一个 render,每个 UID 可能会包含2个 sourceId;
互动直播的服务器推流和录制需要支持主流和辅流的合流录制;
主流和辅流的拥塞控制方案的落地;
主流和辅流的码率分配方案的落地;
主流和辅流的编码器性能优化;
PacedSender 发送策略、音画同步等方案的调整;
服务器 Qos 下行码率的分配方案的调整;
辅流相关的统计数据的汇总;
下面介绍在整个过程中,比较重要的几个技术点的实现。
带宽分配
在弱网情况下,需要视频辅流的时候,我们会优先把码率分配给音频流,其次是辅流,最后再分配给主流,整体策略为保辅流。
带宽分配的主要流程如下:
WebRTC 的拥塞控制算法 GCC(下文简称 CC) 评估出来的总带宽分配会分给音频流、主流、辅流;
主流内部再由 Simulcast 模块分配大小流的码率,不开 Simulcast 时就直接给大流;
具体过程如图所示:
辅流会在上图的基础上再新增一个 VideoSendStream。
码率分配
目前关于码率分配的流程如下图所示,概括起来有一下几步:
CC 的码率通过 transport controller 传递到 Call 中;
然后经过 BitrateAllocator 分配到各个注册的流中 (目前就是视频模块);
视频模块拿到分配的码率,分配给 fec 和重传,剩下来的分配给 video encoder bitrate;
视频编码器模块拿到 video encoder bitrate,按照我们的策略,分配给大流、小流使用;
拥塞控制
为了实现视频辅流的功能,我们需要对拥塞控制进行相关的改动,主要通过以下四个方面的改动来实现:
SDP 信令改动
按照 RFC 2327,使用 "b=<modifier>:<bandwidth-value>" 的方式来指定建议带宽,有两种 modifier(修饰符):
AS:单一媒体带宽;
CT:会话总带宽,表示所有媒体的总带宽;
(RFC 2327:https://tools.ietf.org/html/rfc2327)
目前 SDK 使用 b=AS: 的方式指定摄像头码流或屏幕共享码流的建议带宽,并把这个值作为 CC 模块的估计值上限。
新的需求要求在同一会话中,可同时发送摄像头码流和屏幕共享码流,因此应把两路媒体的建议带宽值相加得到整个会话的建议带宽值,作为 CC 模块的估计值上限。
WebRTC 支持 b=AS: 方式(单路媒体),在 WebRTC 内部对多路媒体进行相加处理即可满足需求,而 WebRTC 目前不支持 b=CT: 方式,所以建议使用 b=AS: 方式,改动相对较少。
CC 总码率更新策略
Pub 码流能力更新,通过 SDP 方式 (b=AS:) 同步设置"最大带宽"到 CC 模块,当新增一路媒体流时,通过启动 probe 快速探测的方式,迅速上探到可用带宽:
快速带宽评估
突然增加一路媒体流时,需要能够很快上探到真实带宽值,使用 probe 快速探测算法实现这一目标:
如果探测成功,CC 估计值迅速收敛,在带宽充足场景中收敛为 CC 上限,带宽受限场景中为真实带宽;
如果探测失败(如高丢包率场景),CC 估计值缓慢收敛,在带宽充足场景中最终收敛为 CC 上限, 带宽受限场景中为真实带宽;
Paced Sender 处理
辅流与主流的视频大小流的发送优先级一致,所有视频媒体数据,使用预算和 pacing multiplier 的方式做平滑发送处理;
增加一个视频码流类型,kVideoSubStream = 3,与主流的大小流视频数据区分开来;
Probe 快速探测期间,当编码数据不足的情况下,发送 padding 数据弥补,以保证发送码率满足要求;
下图为实际进行码率分配测试的结果展示:
统计上报
带宽的统计上报分为两个部分,分别是从 MediaInfo 获取以及 Bweinfo 获取。
1、发送端和接收端 MediaInfo 获取
当前 SDK 的带宽估计从 MediaInfo 获取逻辑为:
遍历当前所有 transceiver,获取每个 transceiver 的 video_channel 和 voice_channel,从而获取到 video_media_channel 和 voice_media_channel;
根据 media_channel 的 getstats 获取当前 channel 的 MediaInfo;
将获取的 MediaInfo 放在 vertor media_infos 中,便于上报;
主流和辅流同时发送场景,只是增加了一个 transceiver,因此此逻辑适用于主流和辅流同时发送的场景,如下图:
2、带宽估计信息获取
当前 SDK 的带宽估计从 Bweinfo 获取逻辑:
获取 gcc、probe 探测等表示总体带宽信息;
获取每个 transceiver 的 voiceChanel 和 videoChannel 相关的带宽估计信息(类似于 MediaInfo 的获取);
主流和辅流同时发送的场景只是增加了 transceiver,因此此逻辑适用主流加辅流同时发送场景,如下图:
总结
以上就是关于 WebRTC 中视频辅流的分享,主要从业务需求出发,通过技术背景以及关键技术类图,详细分享了关于视频辅流的技术实现。也欢迎留言与我们交流关于 WebRTC 以及音视频相关技术。
推荐阅读
WebRTC 系列之音频的那些事
从入门到进阶|如何基于WebRTC搭建一个视频会议
WebRTC 之ICE浅谈
【入门】WebRTC知识点概览 | 内有技术干货免费下载
WebRTC 系列之视频辅流相关推荐
- Android端WebRTC本地音视频采集流程源码分析
WebRTC源码版本为:org.webrtc:google-webrtc:1.0.32006 本文仅分析Java层源码,在分析之前,先说明一下一些重要类的基本概念. MediaSource:WebRT ...
- WebRTC系列--多路视频拼接及录制MP4
文章目录 1. 数据获取介绍 1.1 一些概念 1.2 实现数据获取类 1.2.1 使用的类介绍 1.2.2 onFrame中使用工具介绍 2. 添加数据源source 2.1 peerConnect ...
- WebRTC系列 -- iOS 视频采集(1)
文章目录 1. iOS端视频数据采集 1.1 采集控制 1.2 采集输出 1.3 开始停止 2. 视频数据处理 `ObjCVideoTrackSource`类 2.1 采集时间戳处理 2.2 帧率及分 ...
- WebRTC 系列之音频会话管理
导读:WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音对话或视频对话的 API.W3C 和 IETF 在2021年1月26日共同宣布 WebRTC ...
- WebRTC系列--视频编码控制之BALANCED(分辨率与帧率平衡模式)
文章目录 1. 触发流程及流开始 2. 平衡模式流程详细分析 2.1 BalancedDegradationSettings的MinFps方法调用流程 2.2 source_proxy_的Restri ...
- javacpp-FFmpeg系列之2:通用拉流解码器,支持视频拉流解码并转换为YUV、BGR24或RGB24等图像像素数据...
javacpp-ffmpeg系列: javacpp-FFmpeg系列之1:视频拉流解码成YUVJ420P,并保存为jpg图片 javacpp-FFmpeg系列之2:通用拉流解码器,支持视频拉流解码并转 ...
- TI高精度实验室ADC系列培训视频学习笔记 第1章 直流参数和交流参数:输入电容、输入漏电流、输入阻抗、参考电压值、参考电流值、差分非线性DNL、积分非线性INL、失调误差与增益误差
TI高精度实验室ADC系列培训视频(B站) TI高精度实验室ADC系列培训视频(21ic) 第一章:直流参数和交流参数 输入电容 寄生电容 采样电容 当进行采样时 ,S1开关闭合 ,采样电容与输入信号 ...
- FFmpeg系列(二)—— 音视频裸流转换:mp3转pcm、h264转YUV
文章目录 1.总流程 2.解析流程 3.解码流程 4.完整代码 1.总流程 创建解析器.解码器.AVPacket和AVFrame 打开文件,将mp3数据读入缓冲区 解析mp3数据(在 main 函数中 ...
- 使用WebRTC搭建前端视频聊天室系列文章
- 使用WebRTC搭建前端视频聊天室--入门篇 - 使用WebRTC搭建前端视频聊天室--信令篇 - 使用WebRTC搭建前端视频聊天室--点对点通信篇 -使用WebRTC搭建前端视频聊天室--数据 ...
最新文章
- 121个人电脑搭建微生物组分析平台(Win/Mac)
- [密码学] DES(二)
- tomcat 启动异常 The web application [ROOT] registered the JDBC driver [xxx] but failed to unregister it
- CSS多列布局(实例)
- 经济专业为什么学python_既然有了会计学专业,为什么还要有税收学专业?
- DDD-Mapper
- Integrated Security = True和Integrated Security = SSPI有什么区别?
- OSPF1-5类LSA
- 小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_6、SpringBoot2.xHTTP请求配置讲解...
- mini_magick
- CAN控制器和收发器
- 今日金融词汇---股价复权,是什么?
- 夜莺(Nightingale)企业级监控平台
- Hausdorff 距离
- 第二次·2020-09-21
- 1024程序员节活动勋章获取方式
- C++之 system(“pause“); 与 getchar(); 防止控制台闪退
- Python实用案例
- Java8 Zip 压缩与解压缩
- 【腾讯TMQ】穿山甲系列之老司机的千里眼——穿山甲SDK
热门文章
- 4.1 使用STM32控制MC20拨打电话
- DefaultSingletonBeanRegistry源码解析
- 解决VC6中error LNK2001 _WinMain@16错误
- python 元类的call_python3 全栈开发 - 内置函数补充, 反射, 元类,__str__,__del__,exec,type,__call__方法...
- Graphpad Prism 9绘制子列图与柱状图
- suparc服务器没信号,[SupARC平台常见问题帮助](2012-09-19更新)
- 光流 | OpenCV中的Lucas-Kanade光流与稠密光流:基于Opencv+Python(附代码)
- Qt学习(一):两个独立窗口的信号通信
- 如何激发孩子的想象力_如何激发孩子的想象力?这4个方面要了解,让孩子快乐成长...
- linux 怎么配置apache,在Linux下配置Apache Web服务