Chromium Code Reviews| 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"); |
| } |
| } |