WebRtc性能自适应

1、基本流程


WebRTC中提供了一个根据CPU占用动态调整编码能力的策略,其中CPU占用率没有从系统读取,而是使用编码时长相对采集间隔的占比来估计。主要流程如下:

流程

上述的流程运行于编码线程,由VideoStreamEncoder每隔5s触发一次检查(前3次不做任何处理)。OveruseFrameDetector是一个根据编码时长和采集间隔估计当前性能的管理类,ProcessingUsage是性能估计类,输出编码时长与采集间隔的比值。OveruseFrameDetector检测到overuse或者underuse会回调到VideoStreamEncoder,做AdaptDown或者AdaptUp。

2、编码占用率计算


编码占用率计算接口为OveruseFrameDetector::ProcessingUsage,实现类SendProcessingUsage1。大概原理:占用率=编码时长/采集间隔,通过编码时长估计当期性能,如果编码时长超过采集间隔,那么当前性能肯定存在瓶颈。这里的编码时长和采集间隔使用指数滤波平滑。 详细实现可以见源码,这里没有必要过多介绍了。

3、Overuse和Underuse的检测


如何获取性能的指标usage_percent我们先按下不表,先看下如何得到overuse和uderuse这两个输出信号。OveruseFrameDetector根据当前编码占用率判断是否为overuse或者underuse,再根据这两个信号AdaptDown或者AdaptUp。

判断为Overuse的条件:

boolOveruseFrameDetector::IsOverusing(intusage_percent) {

// 使用率超过overuse的阈值,一般为90

if (usage_percent>=options_.high_encode_usage_threshold_percent) {

++checks_above_threshold_;

} else {

checks_above_threshold_=0;

}

// 连续2次超过阈值才认为是overuse

returnchecks_above_threshold_>=options_.high_threshold_consecutive_count;

}

判断为Underuse的条件:

boolOveruseFrameDetector::IsUnderusing(intusage_percent, int64_ttime_now) {

// 当前performance上升(ramp up),需要超过一定时长,否则不认为已经是underuse

intdelay=in_quick_rampup_?kQuickRampUpDelayMs : current_rampup_delay_ms_;

if (time_now<last_rampup_time_ms_+delay)

returnfalse;

// 低于阈值(一般overuse阈值的一半)就是underuse

returnusage_percent<options_.low_encode_usage_threshold_percent;

}

上面uderuse中,ramp up有一个delay,这个delay不是固定不变的,需要根据实际情况调整。这称作overuse退避,为了避免频繁在overuse和underuse之间切换,所以需要对上升做限制,需要满足一定的时长。

  • Quick ramp up时的阈值为kQuickRampUpDelayMs(10s)

  • 非quick ramp up时,需要做退避。

  • overuse->underuse->overuse时,如果距离最后一次ramp up时间小于40s或者连续4次检测overuse,为了避免频繁变换或者避免容易进入overuse,需要对ramp up的时长做x2退避,限制最大ramp up delay为240s。

  • 检测到overuse时,后续ramp up需要做退避;检测到underuse时,后续ramp up做quick ramp up。

退避相关算法如下:

boolcheck_for_backoff=last_rampup_time_ms_>last_overuse_time_ms_;

if (check_for_backoff) {

if (now_ms-last_rampup_time_ms_<kStandardRampUpDelayMs||

num_overuse_detections_>kMaxOverusesBeforeApplyRampupDelay) {

// Going up was not ok for very long, back off.

current_rampup_delay_ms_*=kRampUpBackoffFactor;

if (current_rampup_delay_ms_>kMaxRampUpDelayMs)

current_rampup_delay_ms_=kMaxRampUpDelayMs;

} else {

// Not currently backing off, reset rampup delay.

current_rampup_delay_ms_=kStandardRampUpDelayMs;

}

}

另外,overuse、underuser检测阈值可以配置,主要使用CpuOveruseOptions来配置。比如针对单核、双核系统overuse阈值可以降低到20、40,阈值调整到100以上可以disable自适应功能。

4、AdaptDown


当性能不足时需要做视频降级,视频降级有几种策略:

  • BALANCED,帧率和分辨率之间平衡

  • MAINTAIN_FRAMERATE,保帧率,调整分辨率

  • MAINTAIN_RESOLUTION,保分辨率,调整帧率

4.1MAINTAIN_FRAMERATE

这次adapt down的分辨率需要比上次请求的小(否则就是ramp up了),否则不调整。

分辨率选择通过VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan实现:

boolRequestResolutionLowerThan(intpixel_count,

intmin_pixels_per_frame,

bool*min_pixels_reached) {

...

// MAINTAIN_FRAMERATE或者BALANCED时才能调整分辨率

if (!source_||!IsResolutionScalingEnabled(degradation_preference_)) {

returnfalse;

}

// 根据像素个数来做分辨率选择,像素个数变为原来的3/5

constintpixels_wanted= (pixel_count*3) /5;

if (pixels_wanted>=sink_wants_.max_pixel_count) {

returnfalse;

}

// 分辨率降低有限制

if (pixels_wanted<min_pixels_per_frame) {

*min_pixels_reached=true;

returnfalse;

}

// 更新sink wants到source

sink_wants_.max_pixel_count=pixels_wanted;

sink_wants_.target_pixel_count=absl::nullopt;

source_->AddOrUpdateSink(video_stream_encoder_,

GetActiveSinkWantsInternal());

returntrue;

}

4.2MAINTAIN_RESOLUTION

帧率不能低于降低到2帧以下。

分辨率选择通过VideoStreamEncoder::VideoSourceProxy::RequestFramerateLowerThan实现:

webrtc:

intRequestFramerateLowerThan(intfps) {

// 帧率降低到2/3

intframerate_wanted= (fps*2) /3;

returnRestrictFramerate(framerate_wanted) ?framerate_wanted : -1;

}

boolRestrictFramerate(intfps) {

...

// MAINTAIN_RESOLUTION或BALANCED时才能降低帧率

if (!source_||!IsFramerateScalingEnabled(degradation_preference_))

returnfalse;

// 帧率不能降低到2fps

constintfps_wanted=std::max(kMinFramerateFps, fps);

if (fps_wanted>=sink_wants_.max_framerate_fps)

returnfalse;

// 更新sink wants到source

sink_wants_.max_framerate_fps=fps_wanted;

source_->AddOrUpdateSink(video_stream_encoder_,

GetActiveSinkWantsInternal());

returntrue;

}

4.3 BALANCED

有时候需要在帧率和分辨率之间找一个平衡点(最新的WebRTC代码中使用BalancedDegradationSettings来实现,这里以老代码为例)。balace采取先降帧率,再降分辨率的策略,即先RestrictFramerate,再走MAINTAIN_FRAMERATE逻辑。

先限制帧率:

intMinFps(intpixels) {

if (pixels<=320*240) {

return7;

} elseif (pixels<=480*270) {

return10;

} elseif (pixels<=640*480) {

return15;

} else {

returnstd::numeric_limits<int>::max();

}

}

再走再走MAINTAIN_FRAMERATE逻辑调整分辨率。

5、AdaptUp


当检测性能处于underuse的时候,视频能力需要升级。和AdaptDown一样,也有三种方式,BALANCED、MAINTAIN_FRAMERATE、MAINTAIN_RESOLUTION。

这里对向上调整做了限制,只有向下调整过才能向上调整。

5.1MAINTAIN_FRAMERATE

boolRequestHigherResolutionThan(intpixel_count) {

...

// MAINTAIN_FRAMERATE或者BALANCED时才能调整分辨率

if (!source_||!IsResolutionScalingEnabled(degradation_preference_)) {

returnfalse;

}

// 像素x4上调

intmax_pixels_wanted=pixel_count;

if (max_pixels_wanted!=std::numeric_limits<int>::max())

max_pixels_wanted=pixel_count*4;

if (max_pixels_wanted<=sink_wants_.max_pixel_count)

returnfalse;

sink_wants_.max_pixel_count=max_pixels_wanted;

if (max_pixels_wanted==std::numeric_limits<int>::max()) {

// Remove any constraints.

sink_wants_.target_pixel_count.reset();

} else {

sink_wants_.target_pixel_count=GetHigherResolutionThan(pixel_count);

}

// 更新sink wants到source

source_->AddOrUpdateSink(video_stream_encoder_,

GetActiveSinkWantsInternal());

returntrue;

}

5.2MAINTAIN_RESOLUTION

和AdaptUp类似,也是按照固定倍数上调。

intRequestHigherFramerateThan(intfps) {

// 调整速率,down是2/3,up是3/2

intframerate_wanted=fps;

if (fps!=std::numeric_limits<int>::max())

framerate_wanted= (fps*3) /2;

returnIncreaseFramerate(framerate_wanted) ?framerate_wanted : -1;

}

5.3 BALANCED

先升分辨率,再升帧率(走MAINTAIN_FRAMERATE逻辑)。

intMaxFps(intpixels) {

if (pixels<=320*240) {

return10;

} elseif (pixels<=480*270) {

return15;

} else {

returnstd::numeric_limits<int>::max();

}

}

6、总结


总结一下,性能自适应代码逻辑也不是很负载,主要的思想也就几点:

  • 采取编码时长占采集间隔的比例得到性能的估计

  • 根据性能估计得到overuse、underuse信号做adapt down和adapt up

  • 从overuse到underuse需要谨慎,避免频繁切换

  • 向上调整和向下调整策略主要有三个:保帧率、保分辨率、帧率和分辨率平衡。

原文https://zhuanlan.zhihu.com/p/352435623

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值