Index: webrtc/video/vie_encoder.cc |
diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc |
index 63b1c80fefbe9b0f0f8afaf95a83dd0f140a3540..d82e4fc7a2b2ef4fd6f9b4205a3c40f5263f3f45 100644 |
--- a/webrtc/video/vie_encoder.cc |
+++ b/webrtc/video/vie_encoder.cc |
@@ -44,24 +44,12 @@ const int64_t kFrameLogIntervalMs = 60000; |
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206 |
const int kMinPixelsPerFrame = 320 * 180; |
const int kMinFramerateFps = 2; |
+const int kMaxFramerateFps = 120; |
// The maximum number of frames to drop at beginning of stream |
// to try and achieve desired bitrate. |
const int kMaxInitialFramedrop = 4; |
-// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle |
-// pipelining encoders better (multiple input frames before something comes |
-// out). This should effectively turn off CPU adaptations for systems that |
-// remotely cope with the load right now. |
-CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) { |
- CpuOveruseOptions options; |
- if (full_overuse_time) { |
- options.low_encode_usage_threshold_percent = 150; |
- options.high_encode_usage_threshold_percent = 200; |
- } |
- return options; |
-} |
- |
uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) { |
if (kbps > 0) { |
if (kbps < 300 /* qvga */) { |
@@ -207,7 +195,7 @@ class ViEEncoder::VideoSourceProxy { |
degradation_preference_ = degradation_preference; |
old_source = source_; |
source_ = source; |
- wants = GetActiveSinkWants(); |
+ wants = GetActiveSinkWantsInternal(); |
} |
if (old_source != source && old_source != nullptr) { |
@@ -228,26 +216,9 @@ class ViEEncoder::VideoSourceProxy { |
source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
} |
- rtc::VideoSinkWants GetActiveSinkWants() EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
- rtc::VideoSinkWants wants = sink_wants_; |
- // Clear any constraints from the current sink wants that don't apply to |
- // the used degradation_preference. |
- switch (degradation_preference_) { |
- case VideoSendStream::DegradationPreference::kBalanced: |
- break; |
- case VideoSendStream::DegradationPreference::kMaintainFramerate: |
- wants.max_framerate_fps = std::numeric_limits<int>::max(); |
- break; |
- case VideoSendStream::DegradationPreference::kMaintainResolution: |
- wants.max_pixel_count = std::numeric_limits<int>::max(); |
- wants.target_pixel_count.reset(); |
- break; |
- case VideoSendStream::DegradationPreference::kDegradationDisabled: |
- wants.max_pixel_count = std::numeric_limits<int>::max(); |
- wants.target_pixel_count.reset(); |
- wants.max_framerate_fps = std::numeric_limits<int>::max(); |
- } |
- return wants; |
+ rtc::VideoSinkWants GetActiveSinkWants() { |
+ rtc::CritScope lock(&crit_); |
+ return GetActiveSinkWantsInternal(); |
} |
void ResetPixelFpsCount() { |
@@ -277,14 +248,15 @@ class ViEEncoder::VideoSourceProxy { |
LOG(LS_INFO) << "Scaling down resolution, max pixels: " << pixels_wanted; |
sink_wants_.max_pixel_count = pixels_wanted; |
sink_wants_.target_pixel_count = rtc::Optional<int>(); |
- source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
+ source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal()); |
return true; |
} |
- bool RequestFramerateLowerThan(int fps) { |
+ int RequestFramerateLowerThan(int fps) { |
// Called on the encoder task queue. |
// The input video frame rate will be scaled down to 2/3, rounding down. |
- return RestrictFramerate((fps * 2) / 3); |
+ int framerate_wanted = (fps * 2) / 3; |
+ return RestrictFramerate(framerate_wanted) ? framerate_wanted : -1; |
} |
bool RequestHigherResolutionThan(int pixel_count) { |
@@ -317,18 +289,22 @@ class ViEEncoder::VideoSourceProxy { |
rtc::Optional<int>((pixel_count * 5) / 3); |
} |
LOG(LS_INFO) << "Scaling up resolution, max pixels: " << max_pixels_wanted; |
- source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
+ source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal()); |
return true; |
} |
- bool RequestHigherFramerateThan(int fps) { |
+ // Request upgrade in framerate. Returns the new requested frame, or -1 if |
+ // no change requested. Note that maxint may be returned if limits due to |
+ // adaptation requests are removed completely. In that case, consider |
+ // |max_framerate_| to be the current limit (assuming the capturer complies). |
+ int RequestHigherFramerateThan(int fps) { |
// Called on the encoder task queue. |
// The input frame rate will be scaled up to the last step, with rounding. |
int framerate_wanted = fps; |
if (fps != std::numeric_limits<int>::max()) |
framerate_wanted = (fps * 3) / 2; |
- return IncreaseFramerate(framerate_wanted); |
+ return IncreaseFramerate(framerate_wanted) ? framerate_wanted : -1; |
} |
bool RestrictFramerate(int fps) { |
@@ -343,7 +319,7 @@ class ViEEncoder::VideoSourceProxy { |
LOG(LS_INFO) << "Scaling down framerate: " << fps_wanted; |
sink_wants_.max_framerate_fps = fps_wanted; |
- source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
+ source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal()); |
return true; |
} |
@@ -359,11 +335,34 @@ class ViEEncoder::VideoSourceProxy { |
LOG(LS_INFO) << "Scaling up framerate: " << fps_wanted; |
sink_wants_.max_framerate_fps = fps_wanted; |
- source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
+ source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal()); |
return true; |
} |
private: |
+ rtc::VideoSinkWants GetActiveSinkWantsInternal() |
+ EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
+ rtc::VideoSinkWants wants = sink_wants_; |
+ // Clear any constraints from the current sink wants that don't apply to |
+ // the used degradation_preference. |
+ switch (degradation_preference_) { |
+ case VideoSendStream::DegradationPreference::kBalanced: |
+ break; |
+ case VideoSendStream::DegradationPreference::kMaintainFramerate: |
+ wants.max_framerate_fps = std::numeric_limits<int>::max(); |
+ break; |
+ case VideoSendStream::DegradationPreference::kMaintainResolution: |
+ wants.max_pixel_count = std::numeric_limits<int>::max(); |
+ wants.target_pixel_count.reset(); |
+ break; |
+ case VideoSendStream::DegradationPreference::kDegradationDisabled: |
+ wants.max_pixel_count = std::numeric_limits<int>::max(); |
+ wants.target_pixel_count.reset(); |
+ wants.max_framerate_fps = std::numeric_limits<int>::max(); |
+ } |
+ return wants; |
+ } |
+ |
rtc::CriticalSection crit_; |
rtc::SequencedTaskChecker main_checker_; |
ViEEncoder* const vie_encoder_; |
@@ -379,7 +378,8 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
SendStatisticsProxy* stats_proxy, |
const VideoSendStream::Config::EncoderSettings& settings, |
rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback, |
- EncodedFrameObserver* encoder_timing) |
+ EncodedFrameObserver* encoder_timing, |
+ std::unique_ptr<OveruseFrameDetector> overuse_detector) |
: shutdown_event_(true /* manual_reset */, false), |
number_of_cores_(number_of_cores), |
initial_rampup_(0), |
@@ -389,13 +389,18 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
codec_type_(PayloadNameToCodecType(settings.payload_name) |
.value_or(VideoCodecType::kVideoCodecUnknown)), |
video_sender_(Clock::GetRealTimeClock(), this, this), |
- overuse_detector_(GetCpuOveruseOptions(settings.full_overuse_time), |
- this, |
- encoder_timing, |
- stats_proxy), |
+ overuse_detector_( |
+ overuse_detector.get() |
+ ? overuse_detector.release() |
+ : new OveruseFrameDetector( |
+ GetCpuOveruseOptions(settings.full_overuse_time), |
+ this, |
+ encoder_timing, |
+ stats_proxy)), |
stats_proxy_(stats_proxy), |
pre_encode_callback_(pre_encode_callback), |
module_process_thread_(nullptr), |
+ max_framerate_(-1), |
pending_encoder_reconfiguration_(false), |
encoder_start_bitrate_bps_(0), |
max_data_payload_length_(0), |
@@ -416,7 +421,7 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
RTC_DCHECK(stats_proxy); |
encoder_queue_.PostTask([this] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- overuse_detector_.StartCheckForOveruse(); |
+ overuse_detector_->StartCheckForOveruse(); |
video_sender_.RegisterExternalEncoder( |
settings_.encoder, settings_.payload_type, settings_.internal_source); |
}); |
@@ -428,12 +433,25 @@ ViEEncoder::~ViEEncoder() { |
<< "Must call ::Stop() before destruction."; |
} |
+// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle |
+// pipelining encoders better (multiple input frames before something comes |
+// out). This should effectively turn off CPU adaptations for systems that |
+// remotely cope with the load right now. |
+CpuOveruseOptions ViEEncoder::GetCpuOveruseOptions(bool full_overuse_time) { |
+ CpuOveruseOptions options; |
+ if (full_overuse_time) { |
+ options.low_encode_usage_threshold_percent = 150; |
+ options.high_encode_usage_threshold_percent = 200; |
+ } |
+ return options; |
+} |
+ |
void ViEEncoder::Stop() { |
RTC_DCHECK_RUN_ON(&thread_checker_); |
source_proxy_->SetSource(nullptr, VideoSendStream::DegradationPreference()); |
encoder_queue_.PostTask([this] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- overuse_detector_.StopCheckForOveruse(); |
+ overuse_detector_->StopCheckForOveruse(); |
rate_allocator_.reset(); |
bitrate_observer_ = nullptr; |
video_sender_.RegisterExternalEncoder(nullptr, settings_.payload_type, |
@@ -493,6 +511,12 @@ void ViEEncoder::SetSource( |
bool allow_scaling = IsResolutionScalingEnabled(degradation_preference_); |
initial_rampup_ = allow_scaling ? 0 : kMaxInitialFramedrop; |
ConfigureQualityScaler(); |
+ if (!IsFramerateScalingEnabled(degradation_preference) && |
+ max_framerate_ != -1) { |
+ // If frame rate scaling is no longer allowed, remove any potential |
+ // allowance for longer frame intervals. |
+ overuse_detector_->OnTargetFramerateUpdated(max_framerate_); |
+ } |
}); |
} |
@@ -562,6 +586,8 @@ void ViEEncoder::ReconfigureEncoder() { |
std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate); |
codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate); |
codec.expect_encode_from_texture = last_frame_info_->is_texture; |
+ max_framerate_ = codec.maxFramerate; |
+ RTC_DCHECK_LE(max_framerate_, kMaxFramerateFps); |
bool success = video_sender_.RegisterSendCodec( |
&codec, number_of_cores_, |
@@ -574,19 +600,31 @@ void ViEEncoder::ReconfigureEncoder() { |
video_sender_.UpdateChannelParemeters(rate_allocator_.get(), |
bitrate_observer_); |
- int framerate = stats_proxy_->GetSendFrameRate(); |
- if (framerate == 0) |
- framerate = codec.maxFramerate; |
+ // Get the current actual framerate, as measured by the stats proxy. This is |
+ // used to get the correct bitrate layer allocation. |
+ int current_framerate = stats_proxy_->GetSendFrameRate(); |
+ if (current_framerate == 0) |
+ current_framerate = codec.maxFramerate; |
stats_proxy_->OnEncoderReconfigured( |
- encoder_config_, rate_allocator_.get() |
- ? rate_allocator_->GetPreferredBitrateBps(framerate) |
- : codec.maxBitrate); |
+ encoder_config_, |
+ rate_allocator_.get() |
+ ? rate_allocator_->GetPreferredBitrateBps(current_framerate) |
+ : codec.maxBitrate); |
pending_encoder_reconfiguration_ = false; |
sink_->OnEncoderConfigurationChanged( |
std::move(streams), encoder_config_.min_transmit_bitrate_bps); |
+ // Get the current target framerate, ie the maximum framerate as specified by |
+ // the current codec configuration, or any limit imposed by cpu adaption in |
+ // maintain-resolution or balanced mode. This is used to make sure overuse |
+ // detection doesn't needlessly trigger in low and/or variable framerate |
+ // scenarios. |
+ int target_framerate = std::min( |
+ max_framerate_, source_proxy_->GetActiveSinkWants().max_framerate_fps); |
+ overuse_detector_->OnTargetFramerateUpdated(target_framerate); |
+ |
ConfigureQualityScaler(); |
} |
@@ -735,7 +773,7 @@ void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame, |
TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), |
"Encode"); |
- overuse_detector_.FrameCaptured(video_frame, time_when_posted_us); |
+ overuse_detector_->FrameCaptured(video_frame, time_when_posted_us); |
video_sender_.AddVideoFrame(video_frame, nullptr); |
} |
@@ -766,7 +804,7 @@ EncodedImageCallback::Result ViEEncoder::OnEncodedImage( |
const int qp = encoded_image.qp_; |
encoder_queue_.PostTask([this, timestamp, time_sent_us, qp] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- overuse_detector_.FrameSent(timestamp, time_sent_us); |
+ overuse_detector_->FrameSent(timestamp, time_sent_us); |
if (quality_scaler_ && qp >= 0) |
quality_scaler_->ReportQP(qp); |
}); |
@@ -901,14 +939,18 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { |
} |
GetAdaptCounter().IncrementResolution(reason); |
break; |
- case VideoSendStream::DegradationPreference::kMaintainResolution: |
+ case VideoSendStream::DegradationPreference::kMaintainResolution: { |
// Scale down framerate. |
- if (!source_proxy_->RequestFramerateLowerThan( |
- adaptation_request.framerate_fps_)) { |
+ const int requested_framerate = source_proxy_->RequestFramerateLowerThan( |
+ adaptation_request.framerate_fps_); |
+ if (requested_framerate == -1) |
return; |
- } |
+ RTC_DCHECK_NE(max_framerate_, -1); |
+ overuse_detector_->OnTargetFramerateUpdated( |
+ std::min(max_framerate_, requested_framerate)); |
GetAdaptCounter().IncrementFramerate(reason); |
break; |
+ } |
case VideoSendStream::DegradationPreference::kDegradationDisabled: |
RTC_NOTREACHED(); |
} |
@@ -985,8 +1027,15 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { |
LOG(LS_INFO) << "Removing framerate down-scaling setting."; |
fps = std::numeric_limits<int>::max(); |
} |
- if (!source_proxy_->RequestHigherFramerateThan(fps)) |
+ |
+ const int requested_framerate = |
+ source_proxy_->RequestHigherFramerateThan(fps); |
+ if (requested_framerate == -1) { |
+ overuse_detector_->OnTargetFramerateUpdated(max_framerate_); |
return; |
+ } |
+ overuse_detector_->OnTargetFramerateUpdated( |
+ std::min(max_framerate_, requested_framerate)); |
GetAdaptCounter().DecrementFramerate(reason); |
break; |
} |