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,此模块的作用是模拟一个水池算法,检查编码后输出码率是否匹配目标码率,如果发生上溢,则执行丢帧。此模块的丢帧可以看作是强制性的(除非显式关闭),与这里所说的自适应不太一样
posted @ 2024-04-29 14:42  小夕nike  阅读(239)  评论(0编辑  收藏  举报