Index: webrtc/video/vie_encoder.cc |
diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc |
index 1458af266f68efb6692756205f2296b6cd217e20..c147440b8fa8bdb5ab5d4930da4cb94eda164ad6 100644 |
--- a/webrtc/video/vie_encoder.cc |
+++ b/webrtc/video/vie_encoder.cc |
@@ -43,6 +43,7 @@ const int kMinPixelsPerFrame = 320 * 180; |
#else |
const int kMinPixelsPerFrame = 120 * 90; |
#endif |
+const int kMinFramerateFps = 2; |
// The maximum number of frames to drop at beginning of stream |
// to try and achieve desired bitrate. |
@@ -162,10 +163,23 @@ class ViEEncoder::VideoSourceProxy { |
rtc::VideoSinkWants wants; |
{ |
rtc::CritScope lock(&crit_); |
+ wants = sink_wants_; |
+ // If changing degradation preference, clear any constraints from the |
+ // current sink wants that will no longer apply. |
+ if (degradation_preference_ != degradation_preference) { |
+ switch (degradation_preference) { |
+ case DegradationPreference::kBalanced: |
+ wants.max_framerate_fps_.reset(); |
+ break; |
+ case DegradationPreference::kMaintainResolution: |
+ wants.max_pixel_count.reset(); |
+ wants.target_pixel_count.reset(); |
+ break; |
+ } |
+ } |
+ degradation_preference_ = degradation_preference; |
old_source = source_; |
source_ = source; |
- degradation_preference_ = degradation_preference; |
- wants = current_wants(); |
} |
if (old_source != source && old_source != nullptr) { |
@@ -182,10 +196,8 @@ class ViEEncoder::VideoSourceProxy { |
void SetWantsRotationApplied(bool rotation_applied) { |
rtc::CritScope lock(&crit_); |
sink_wants_.rotation_applied = rotation_applied; |
- disabled_scaling_sink_wants_.rotation_applied = rotation_applied; |
- if (source_) { |
- source_->AddOrUpdateSink(vie_encoder_, current_wants()); |
- } |
+ if (source_) |
+ source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
} |
void RequestResolutionLowerThan(int pixel_count) { |
@@ -209,6 +221,24 @@ class ViEEncoder::VideoSourceProxy { |
source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
} |
+ void RequestFramerateLowerThan(int framerate_fps) { |
+ // Called on the encoder task queue. |
+ rtc::CritScope lock(&crit_); |
+ if (!IsFramerateScalingEnabledLocked()) { |
+ // This can happen since |degradation_preference_| is set on |
+ // libjingle's worker thread but the adaptation is done on the encoder |
+ // task queue. |
+ return; |
+ } |
+ // The input video frame rate will be scaled down to |
+ const int framerate_wanted = (framerate_fps * 2) / 3; |
+ if (framerate_fps < kMinFramerateFps) |
magjed_webrtc
2017/02/27 09:30:35
Shouldn't it be 'framerate_wanted < kMinFramerateF
sprang_webrtc
2017/02/27 12:51:49
I think I intended it to be framerate_fps, but pla
magjed_webrtc
2017/02/28 14:21:55
Hmm, maybe just do:
framerate_wanted = max(kMinFra
sprang_webrtc
2017/02/28 15:15:30
Done.
|
+ return; |
+ sink_wants_.max_framerate_fps_.emplace(framerate_wanted); |
+ if (source_) |
+ source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
+ } |
+ |
void RequestHigherResolutionThan(int pixel_count) { |
rtc::CritScope lock(&crit_); |
if (!IsResolutionScalingEnabledLocked()) { |
@@ -229,6 +259,22 @@ class ViEEncoder::VideoSourceProxy { |
source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
} |
+ void RequestHigherFramerateThan(int framerate_fps) { |
+ // Called on the encoder task queue. |
+ rtc::CritScope lock(&crit_); |
+ if (!IsFramerateScalingEnabledLocked()) { |
+ // This can happen since |degradation_preference_| is set on |
+ // libjingle's worker thread but the adaptation is done on the encoder |
+ // task queue. |
+ return; |
+ } |
+ // The input video frame rate will be scaled up to |
+ const int framerate_wanted = (framerate_fps * 3) / 2; |
+ sink_wants_.max_framerate_fps_.emplace(framerate_wanted); |
+ if (source_) |
+ source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
+ } |
+ |
private: |
bool IsResolutionScalingEnabledLocked() const |
EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
@@ -236,17 +282,16 @@ class ViEEncoder::VideoSourceProxy { |
DegradationPreference::kMaintainResolution; |
} |
- const rtc::VideoSinkWants& current_wants() const |
+ bool IsFramerateScalingEnabledLocked() const |
EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
- return IsResolutionScalingEnabledLocked() ? sink_wants_ |
- : disabled_scaling_sink_wants_; |
+ return degradation_preference_ == |
+ DegradationPreference::kMaintainResolution; |
} |
rtc::CriticalSection crit_; |
rtc::SequencedTaskChecker main_checker_; |
ViEEncoder* const vie_encoder_; |
rtc::VideoSinkWants sink_wants_ GUARDED_BY(&crit_); |
- rtc::VideoSinkWants disabled_scaling_sink_wants_ GUARDED_BY(&crit_); |
DegradationPreference degradation_preference_ GUARDED_BY(&crit_); |
rtc::VideoSourceInterface<VideoFrame>* source_ GUARDED_BY(&crit_); |
@@ -285,7 +330,6 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
has_received_rpsi_(false), |
picture_id_rpsi_(0), |
clock_(Clock::GetRealTimeClock()), |
- scale_counter_(kScaleReasonSize, 0), |
degradation_preference_(DegradationPreference::kMaintainResolution), |
last_captured_timestamp_(0), |
delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() - |
@@ -302,6 +346,9 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
video_sender_.RegisterExternalEncoder( |
settings_.encoder, settings_.payload_type, settings_.internal_source); |
}); |
+ |
+ for (size_t i = 0; i < VideoSendStream::kNumDegradationPreferences; ++i) |
+ scale_counter_[i].resize(kScaleReasonSize); |
} |
ViEEncoder::~ViEEncoder() { |
@@ -476,9 +523,11 @@ void ViEEncoder::ConfigureQualityScaler() { |
quality_scaler_.reset(nullptr); |
initial_rampup_ = kMaxInitialFramedrop; |
} |
+ const std::vector<int>& scale_counter = |
+ scale_counter_[static_cast<size_t>(degradation_preference_)]; |
stats_proxy_->SetResolutionRestrictionStats( |
- degradation_preference_allows_scaling, scale_counter_[kCpu] > 0, |
- scale_counter_[kQuality]); |
+ degradation_preference_allows_scaling, scale_counter[kCpu] > 0, |
+ scale_counter[kQuality]); |
} |
void ViEEncoder::OnFrame(const VideoFrame& video_frame) { |
@@ -741,77 +790,132 @@ void ViEEncoder::OnBitrateUpdated(uint32_t bitrate_bps, |
void ViEEncoder::AdaptDown(AdaptReason reason) { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- if (degradation_preference_ != DegradationPreference::kBalanced) |
- return; |
- RTC_DCHECK(static_cast<bool>(last_frame_info_)); |
- int current_pixel_count = last_frame_info_->pixel_count(); |
+ AdaptationRequest adaptation_request = { |
+ last_frame_info_->pixel_count(), |
+ stats_proxy_->GetStats().input_frame_rate, |
+ AdaptationRequest::Mode::kAdaptDown}; |
+ |
if (last_adaptation_request_ && |
- last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown && |
- current_pixel_count >= last_adaptation_request_->input_pixel_count_) { |
- // Don't request lower resolution if the current resolution is not lower |
- // than the last time we asked for the resolution to be lowered. |
- return; |
+ last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown) { |
+ switch (degradation_preference_) { |
+ case DegradationPreference::kBalanced: |
+ if (adaptation_request.input_pixel_count_ >= |
+ last_adaptation_request_->input_pixel_count_) { |
+ // Don't request lower resolution if the current resolution is not |
magjed_webrtc
2017/02/27 09:30:35
Reflow comment.
sprang_webrtc
2017/02/27 12:51:49
Done.
|
+ // lower |
+ // than the last time we asked for the resolution to be lowered. |
+ return; |
+ } |
+ break; |
+ case DegradationPreference::kMaintainResolution: |
+ if (adaptation_request.framerate_fps_ <= 1) { |
+ // Don't request lower framerate if we don't have a valid frame rate. |
+ // Since framerate, unlike resolution, is a measure we have to |
+ // estimate, and can fluctuate naturally over time, don't make the |
+ // same kind of limitations as for resolution, but trust the overuse |
+ // detector to not trigger too often. |
+ return; |
+ } |
+ break; |
+ } |
} |
- last_adaptation_request_.emplace(AdaptationRequest{ |
- current_pixel_count, AdaptationRequest::Mode::kAdaptDown}); |
+ |
+ last_adaptation_request_.emplace(adaptation_request); |
+ std::vector<int>* scale_counter = |
+ &scale_counter_[static_cast<size_t>(degradation_preference_)]; |
switch (reason) { |
case kQuality: |
stats_proxy_->OnQualityRestrictedResolutionChanged( |
- scale_counter_[reason] + 1); |
+ (*scale_counter)[reason] + 1); |
break; |
case kCpu: |
- if (scale_counter_[reason] >= kMaxCpuDowngrades) |
+ if ((*scale_counter)[reason] >= kMaxCpuDowngrades) |
return; |
// Update stats accordingly. |
stats_proxy_->OnCpuRestrictedResolutionChanged(true); |
break; |
} |
- ++scale_counter_[reason]; |
- source_proxy_->RequestResolutionLowerThan(current_pixel_count); |
+ ++(*scale_counter)[reason]; |
+ |
+ switch (degradation_preference_) { |
+ case DegradationPreference::kBalanced: |
+ source_proxy_->RequestResolutionLowerThan( |
+ adaptation_request.input_pixel_count_); |
+ LOG(LS_INFO) << "Scaling down resolution."; |
+ break; |
+ case DegradationPreference::kMaintainResolution: |
+ source_proxy_->RequestFramerateLowerThan( |
+ adaptation_request.framerate_fps_); |
+ LOG(LS_INFO) << "Scaling down framerate."; |
+ break; |
+ } |
+ |
LOG(LS_INFO) << "Scaling down resolution."; |
for (size_t i = 0; i < kScaleReasonSize; ++i) { |
- LOG(LS_INFO) << "Scaled " << scale_counter_[i] |
+ LOG(LS_INFO) << "Scaled " << (*scale_counter)[i] |
<< " times for reason: " << (i ? "cpu" : "quality"); |
} |
} |
void ViEEncoder::AdaptUp(AdaptReason reason) { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- if (scale_counter_[reason] == 0 || |
- degradation_preference_ != DegradationPreference::kBalanced) { |
+ std::vector<int>* scale_counter = |
+ &scale_counter_[static_cast<size_t>(degradation_preference_)]; |
+ if ((*scale_counter)[reason] == 0) |
return; |
- } |
- // Only scale if resolution is higher than last time we requested higher |
- // resolution. |
- RTC_DCHECK(static_cast<bool>(last_frame_info_)); |
- int current_pixel_count = last_frame_info_->pixel_count(); |
+ AdaptationRequest adaptation_request = { |
+ last_frame_info_->pixel_count(), |
+ stats_proxy_->GetStats().input_frame_rate, |
+ AdaptationRequest::Mode::kAdaptUp}; |
+ |
if (last_adaptation_request_ && |
- last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp && |
- current_pixel_count <= last_adaptation_request_->input_pixel_count_) { |
- // Don't request higher resolution if the current resolution is not higher |
- // than the last time we asked for the resolution to be higher. |
- return; |
+ last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp) { |
+ switch (degradation_preference_) { |
+ case DegradationPreference::kBalanced: |
+ if (adaptation_request.input_pixel_count_ <= |
+ last_adaptation_request_->input_pixel_count_) { |
+ // Don't request higher resolution if the current resolution is not |
+ // higher than the last time we asked for the resolution to be higher. |
+ return; |
+ } |
+ break; |
+ case DegradationPreference::kMaintainResolution: |
+ // TODO(sprang): Don't request higher framerate if we are already at |
+ // max requested fps? |
+ break; |
+ } |
} |
- last_adaptation_request_.emplace(AdaptationRequest{ |
- current_pixel_count, AdaptationRequest::Mode::kAdaptUp}); |
switch (reason) { |
case kQuality: |
stats_proxy_->OnQualityRestrictedResolutionChanged( |
- scale_counter_[reason] - 1); |
+ (*scale_counter)[reason] - 1); |
break; |
case kCpu: |
// Update stats accordingly. |
- stats_proxy_->OnCpuRestrictedResolutionChanged(scale_counter_[reason] > |
+ stats_proxy_->OnCpuRestrictedResolutionChanged((*scale_counter)[reason] > |
1); |
break; |
} |
- --scale_counter_[reason]; |
- source_proxy_->RequestHigherResolutionThan(current_pixel_count); |
+ --(*scale_counter)[reason]; |
+ |
+ switch (degradation_preference_) { |
+ case DegradationPreference::kBalanced: |
+ source_proxy_->RequestHigherResolutionThan( |
+ adaptation_request.input_pixel_count_); |
+ LOG(LS_INFO) << "Scaling up resolution."; |
+ break; |
+ case DegradationPreference::kMaintainResolution: |
+ source_proxy_->RequestHigherFramerateThan( |
+ adaptation_request.framerate_fps_); |
+ LOG(LS_INFO) << "Scaling up framerate."; |
+ break; |
+ } |
+ |
LOG(LS_INFO) << "Scaling up resolution."; |
for (size_t i = 0; i < kScaleReasonSize; ++i) { |
- LOG(LS_INFO) << "Scaled " << scale_counter_[i] |
+ LOG(LS_INFO) << "Scaled " << (*scale_counter)[i] |
<< " times for reason: " << (i ? "cpu" : "quality"); |
} |
} |