webrtc 资源自适应方法概览
参考:
https://www.nxrte.com/jishu/webrtc/15471.html
webrtc 资源自适应策略,是 webrtc 内部通过实时检查多种资源情况,决策出输入源应该采取哪些动作来自适应资源变化的一种方法。
自适应仅针对视频流。
1. 开启自适应
在 media/base/media_config.h::MediaConfig::Video 结构体中,enable_cpu_adaptation 即开启自适应总开关,默认开启。
需要注意的是,不要被 enable_cpu_adaptation 这个名字迷惑,事实上从后面就能看到,资源自适应检查不只是检查 cpu 使用,还有其他项。
2. 配置适应动作
在 api/media_stream_interface.h::VideoTrackInterface 类中,定义了如下枚举:
enum class ContentHint { kNone, kFluid, kDetailed, kText };
这是开发者可以设置的枚举项,对应 webrtc 内部:
enum class DegradationPreference {
// Don't take any actions based on over-utilization signals. Not part of the
// web API.
DISABLED,
// On over-use, request lower resolution, possibly causing down-scaling.
MAINTAIN_FRAMERATE,
// On over-use, request lower frame rate, possibly causing frame drops.
MAINTAIN_RESOLUTION,
// Try to strike a "pleasing" balance between frame rate or resolution.
BALANCED,
};
这几项分别是不采取动作、保持帧率、保持分辨率、平衡 4种。在 media/engine/webrtc_video_engine.cc::WebRtcVideoSendStream::GetDegradationPreference()() 函数中,会将 ContentHint 转换为 DegradationPreference
3. 资源检测流程
视频被采集后,最终都会来到 VideoStreamEncoder 类来进行编码,资源检测可以看做由 VideoStreamEncoder 类开始:
VideoStreamEncoder
|
|
V
VideoStreamEncoderResourceManager
|
|
V
----------------------------------------------------------------------------
| | | |
| | | |
V V V V
EncodeUsageResource QualityScalerResource PixelLimitResource BandwidthQualityScalerResouce
| | | |
| | | |
V V V V
----------------------------------------------------------------------------
|
|
V
ResourceAdaptationProcessor
|
|
V
VideoStreamAdapter
如上:
- VideoStreamEncoderResourceManager 类是一个管理类,管理下面 4 种资源检测对象的创建和释放,提供一些设置到下面对象的接口,不做具体资源检测工作
- EncodeUsageResource 类用于检测编码 CPU 使用情况,实际委托 OveruseFrameDetector 类来完成
- QualityScalerResource 类用于检测编码后的 QP 值(编码量化参数)与开发者设定阈值的差别。QP 值太小,表明编码为了维持码率,将图像编码质量拉得很高,这时可以考虑提高分辨率或帧率;QP 值太大,表明编码为了维持码率,将图像编码质量拉得很低,这时可以考虑降低分辨率或者帧率。其中开发者设定码率可以编写一个自定义编码器,然后覆盖 VideoEncoder::GetEncoderInfo() 函数来完成
- PixelLimitResource 类用于检测送入编码器分辨率与开发者设定分辨率的差别,逻辑较简单,默认关闭
- BandwidthQualityScalerResouce 类用于检测当前编码后的码率与开发者设定的码率的差别,逻辑较简单,实际委托 BandwidthQualityScaler 类来完成。其中开发者设定码率可以编写一个自定义编码器,然后覆盖 VideoEncoder::GetEncoderInfo() 函数来完成
- 如上 4 种资源检测器检测到异常后,会向 ResourceAdaptationProcessor 类报告检查出 overuse 或underuse 情况,参看 ResourceAdaptationProcessor::OnResourceUsageStateMeasured() 函数
- ResourceAdaptationProcessor 类接收到资源异常报告后,首先会调用 VideoStreamAdapter::GetAdaptationDown() 函数决策出一个适应策略,比如是改变分辨率还是改变帧率,然后通过 VideoStreamAdapter::ApplyAdaptation() 函数传递出去
更具体的细节可以参考:https://www.nxrte.com/jishu/webrtc/15471.html
4. 动作执行
动作的执行可以从开发者创建 VideoTrackSource 开始说起
开发者如果想要创建一条视频轨道,可以继承自 AdaptedVideoTrackSource 父类,trackSource 创建后,会一路创建并关联到 VideoStreamAdapter 对象,VideoStreamAdapter 对象会将最终的资源适应动作封装为一个 SinkWant,而开发者自定义的 TrackSource 对象就是 source,会接收到这个 SinkWant
AdaptedVideoTrackSource 父类持有一个 VideoAdapter 对象,SinkWant 会被转给 VideoAdapter,后者会做如下两个动作:
- 根据 SinkWant 想要的分辨率和当前采集帧分辨率,计算图像具体需要缩放和裁剪的期望值
- 根据 SinkWant 想要的帧率和当前帧率,判断当前帧是否需要丢弃
但是需要注意的是,以上两个动作,需要开发者主动调用父类的 AdaptFrame() 函数:
bool AdaptedVideoTrackSource::AdaptFrame(int width,
int height,
int64_t time_us,
int* out_width,
int* out_height,
int* crop_width,
int* crop_height,
int* crop_x,
int* crop_y);
此函数会返回分辨率修改后的期望值和指示是否需要丢弃,开发者可以根据这些信息,自行丢弃帧或者修改分辨率
所以可以看到,webrtc 资源自适应方法并不是强制性的,而是将期望反馈给开发者,由开发者自行处理
另外有几点需要注意:
- 移动端(Android、IOS) 封装的 API 里面,已经实现了丢帧或修改分辨率操作,Native API 没有封装那么多,所以没有实现
- 如果修改了分辨率,编码器需要重新配置,见 VideoStreamEncoder::pending_encoder_reconfiguration_ 变量
- webrtc 还有一个丢帧模块 FrameDropper,此模块的作用是模拟一个水池算法,检查编码后输出码率是否匹配目标码率,如果发生上溢,则执行丢帧。此模块的丢帧可以看作是强制性的(除非显式关闭),与这里所说的自适应不太一样