Index: webrtc/video/vie_encoder.cc |
diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc |
index e1cd40dc98bbe2bd20ef24a2d93965fe22af661f..7cc799a644058291dd577927b47af91e6cf5c85c 100644 |
--- a/webrtc/video/vie_encoder.cc |
+++ b/webrtc/video/vie_encoder.cc |
@@ -226,6 +226,8 @@ class ViEEncoder::EncodeTask : public rtc::QueuedTask { |
bool Run() override { |
RTC_DCHECK_RUN_ON(&vie_encoder_->encoder_queue_); |
RTC_DCHECK_GT(vie_encoder_->posted_frames_waiting_for_encode_.Value(), 0); |
+ vie_encoder_->stats_proxy_->OnIncomingFrame(frame_.width(), |
+ frame_.height()); |
++vie_encoder_->captured_frame_count_; |
if (--vie_encoder_->posted_frames_waiting_for_encode_ == 0) { |
vie_encoder_->EncodeVideoFrame(frame_, time_when_posted_ms_); |
@@ -253,21 +255,30 @@ class ViEEncoder::EncodeTask : public rtc::QueuedTask { |
}; |
// VideoSourceProxy is responsible ensuring thread safety between calls to |
-// ViEEncoder::SetSource that will happen on libjingles worker thread when a |
+// ViEEncoder::SetSource that will happen on libjingle's worker thread when a |
// video capturer is connected to the encoder and the encoder task queue |
// (encoder_queue_) where the encoder reports its VideoSinkWants. |
class ViEEncoder::VideoSourceProxy { |
public: |
explicit VideoSourceProxy(ViEEncoder* vie_encoder) |
- : vie_encoder_(vie_encoder), source_(nullptr) {} |
- |
- void SetSource(rtc::VideoSourceInterface<VideoFrame>* source) { |
+ : vie_encoder_(vie_encoder), |
+ degradation_preference_( |
+ VideoSendStream::DegradationPreference::kMaintainResolution), |
+ source_(nullptr) {} |
+ |
+ void SetSource( |
+ rtc::VideoSourceInterface<VideoFrame>* source, |
+ const VideoSendStream::DegradationPreference& degradation_preference) { |
+ // Called on libjingle's worker thread. |
RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_); |
rtc::VideoSourceInterface<VideoFrame>* old_source = nullptr; |
+ rtc::VideoSinkWants wants; |
{ |
rtc::CritScope lock(&crit_); |
old_source = source_; |
source_ = source; |
+ degradation_preference_ = degradation_preference; |
+ wants = current_wants(); |
} |
if (old_source != source && old_source != nullptr) { |
@@ -278,16 +289,74 @@ class ViEEncoder::VideoSourceProxy { |
return; |
} |
- // TODO(perkj): Let VideoSourceProxy implement LoadObserver and truly send |
- // CPU load as sink wants. |
- rtc::VideoSinkWants wants; |
source->AddOrUpdateSink(vie_encoder_, wants); |
} |
+ 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()); |
+ } |
+ } |
+ |
+ void RequestResolutionLowerThan(int pixel_count) { |
+ // Called on the encoder task queue. |
+ rtc::CritScope lock(&crit_); |
+ if (!IsResolutionScalingEnabledLocked()) { |
+ // 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 size will have a resolution with less than or |
+ // equal to |max_pixel_count| depending on how the source can scale the |
+ // input frame size. |
+ sink_wants_.max_pixel_count = rtc::Optional<int>((pixel_count * 3) / 5); |
+ sink_wants_.max_pixel_count_step_up = rtc::Optional<int>(); |
+ if (source_) |
+ source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
+ } |
+ |
+ void RequestHigherResolutionThan(int pixel_count) { |
+ rtc::CritScope lock(&crit_); |
+ if (!IsResolutionScalingEnabledLocked()) { |
+ // 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 size will have a resolution with "one step up" |
+ // pixels than |max_pixel_count_step_up| where "one step up" depends on |
+ // how the source can scale the input frame size. |
+ sink_wants_.max_pixel_count = rtc::Optional<int>(); |
+ sink_wants_.max_pixel_count_step_up = rtc::Optional<int>(pixel_count); |
+ if (source_) |
+ source_->AddOrUpdateSink(vie_encoder_, sink_wants_); |
+ } |
+ |
private: |
+ bool IsResolutionScalingEnabledLocked() const |
+ EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
+ return degradation_preference_ != |
+ VideoSendStream::DegradationPreference::kMaintainResolution; |
+ } |
+ |
+ const rtc::VideoSinkWants& current_wants() const |
+ EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
+ return IsResolutionScalingEnabledLocked() ? sink_wants_ |
+ : disabled_scaling_sink_wants_; |
+ } |
+ |
rtc::CriticalSection crit_; |
rtc::SequencedTaskChecker main_checker_; |
- ViEEncoder* vie_encoder_; |
+ ViEEncoder* const vie_encoder_; |
+ rtc::VideoSinkWants sink_wants_ GUARDED_BY(&crit_); |
+ rtc::VideoSinkWants disabled_scaling_sink_wants_ GUARDED_BY(&crit_); |
+ VideoSendStream::DegradationPreference degradation_preference_ |
+ GUARDED_BY(&crit_); |
rtc::VideoSourceInterface<VideoFrame>* source_ GUARDED_BY(&crit_); |
RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy); |
@@ -297,7 +366,6 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
SendStatisticsProxy* stats_proxy, |
const VideoSendStream::Config::EncoderSettings& settings, |
rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback, |
- LoadObserver* overuse_callback, |
EncodedFrameObserver* encoder_timing) |
: shutdown_event_(true /* manual_reset */, false), |
number_of_cores_(number_of_cores), |
@@ -311,7 +379,6 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
this, |
encoder_timing, |
stats_proxy), |
- load_observer_(overuse_callback), |
stats_proxy_(stats_proxy), |
pre_encode_callback_(pre_encode_callback), |
module_process_thread_(nullptr), |
@@ -325,6 +392,11 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
has_received_rpsi_(false), |
picture_id_rpsi_(0), |
clock_(Clock::GetRealTimeClock()), |
+ degradation_preference_( |
+ VideoSendStream::DegradationPreference::kBalanced), |
+ cpu_restricted_counter_(0), |
+ last_frame_width_(0), |
+ last_frame_height_(0), |
last_captured_timestamp_(0), |
delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() - |
clock_->TimeInMilliseconds()), |
@@ -332,11 +404,11 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
captured_frame_count_(0), |
dropped_frame_count_(0), |
encoder_queue_("EncoderQueue") { |
- encoder_queue_.PostTask([this, encoder_timing] { |
+ encoder_queue_.PostTask([this] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
+ overuse_detector_.StartCheckForOveruse(); |
video_sender_.RegisterExternalEncoder( |
settings_.encoder, settings_.payload_type, settings_.internal_source); |
- overuse_detector_.StartCheckForOveruse(); |
}); |
} |
@@ -348,12 +420,12 @@ ViEEncoder::~ViEEncoder() { |
void ViEEncoder::Stop() { |
RTC_DCHECK_RUN_ON(&thread_checker_); |
- source_proxy_->SetSource(nullptr); |
+ source_proxy_->SetSource(nullptr, VideoSendStream::DegradationPreference()); |
encoder_queue_.PostTask([this] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
+ overuse_detector_.StopCheckForOveruse(); |
video_sender_.RegisterExternalEncoder(nullptr, settings_.payload_type, |
false); |
- overuse_detector_.StopCheckForOveruse(); |
shutdown_event_.Set(); |
}); |
@@ -373,12 +445,29 @@ void ViEEncoder::DeRegisterProcessThread() { |
module_process_thread_->DeRegisterModule(&video_sender_); |
} |
-void ViEEncoder::SetSource(rtc::VideoSourceInterface<VideoFrame>* source) { |
+void ViEEncoder::SetSource( |
+ rtc::VideoSourceInterface<VideoFrame>* source, |
+ const VideoSendStream::DegradationPreference& degradation_preference) { |
RTC_DCHECK_RUN_ON(&thread_checker_); |
- source_proxy_->SetSource(source); |
+ source_proxy_->SetSource(source, degradation_preference); |
+ encoder_queue_.PostTask([this, degradation_preference] { |
+ RTC_DCHECK_RUN_ON(&encoder_queue_); |
+ degradation_preference_ = degradation_preference; |
+ // Set the stats for if we are currently CPU restricted. We are CPU |
+ // restricted depending on degradation preference and |
+ // if the overusedetector has currently detected overuse which is counted in |
+ // |cpu_restricted_counter_| |
+ // We do this on the encoder task queue to avoid a race with the stats set |
+ // in ViEEncoder::NormalUsage and ViEEncoder::OveruseDetected. |
+ stats_proxy_->SetCpuRestrictedResolution( |
+ degradation_preference_ != |
+ VideoSendStream::DegradationPreference::kMaintainResolution && |
+ cpu_restricted_counter_ != 0); |
+ }); |
} |
-void ViEEncoder::SetSink(EncoderSink* sink) { |
+void ViEEncoder::SetSink(EncoderSink* sink, bool rotation_applied) { |
+ source_proxy_->SetWantsRotationApplied(rotation_applied); |
encoder_queue_.PostTask([this, sink] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
sink_ = sink; |
@@ -462,9 +551,6 @@ void ViEEncoder::ReconfigureEncoder() { |
void ViEEncoder::OnFrame(const VideoFrame& video_frame) { |
RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_); |
- if (stats_proxy_) { |
- stats_proxy_->OnIncomingFrame(video_frame.width(), video_frame.height()); |
- } |
VideoFrame incoming_frame = video_frame; |
// Local time in webrtc time base. |
@@ -565,6 +651,9 @@ void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame, |
} |
TraceFrameDropEnd(); |
+ last_frame_height_ = video_frame.height(); |
+ last_frame_width_ = video_frame.width(); |
+ |
TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), |
"Encode"); |
@@ -616,10 +705,12 @@ EncodedImageCallback::Result ViEEncoder::OnEncodedImage( |
int64_t time_sent = clock_->TimeInMilliseconds(); |
uint32_t timestamp = encoded_image._timeStamp; |
+ |
encoder_queue_.PostTask([this, timestamp, time_sent] { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
overuse_detector_.FrameSent(timestamp, time_sent); |
}); |
+ |
return result; |
} |
@@ -697,17 +788,46 @@ void ViEEncoder::OnBitrateUpdated(uint32_t bitrate_bps, |
void ViEEncoder::OveruseDetected() { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- // TODO(perkj): When ViEEncoder inherit rtc::VideoSink instead of |
- // VideoCaptureInput |load_observer_| should be removed and overuse be |
- // expressed as rtc::VideoSinkWants instead. |
- if (load_observer_) |
- load_observer_->OnLoadUpdate(LoadObserver::kOveruse); |
+ if (degradation_preference_ == |
+ VideoSendStream::DegradationPreference::kMaintainResolution || |
+ cpu_restricted_counter_ >= kMaxCpuDowngrades) { |
+ return; |
+ } |
+ LOG(LS_INFO) << "CPU overuse detected. Requesting lower resolution."; |
+ // Request lower resolution if the current resolution is lower than last time |
+ // we asked for the resolution to be lowered. |
+ // Update stats accordingly. |
+ int current_pixel_count = last_frame_height_ * last_frame_width_; |
+ if (!max_pixel_count_ || current_pixel_count < *max_pixel_count_) { |
+ max_pixel_count_ = rtc::Optional<int>(current_pixel_count); |
+ max_pixel_count_step_up_ = rtc::Optional<int>(); |
+ stats_proxy_->OnCpuRestrictedResolutionChanged(true); |
+ ++cpu_restricted_counter_; |
+ source_proxy_->RequestResolutionLowerThan(current_pixel_count); |
+ } |
} |
void ViEEncoder::NormalUsage() { |
RTC_DCHECK_RUN_ON(&encoder_queue_); |
- if (load_observer_) |
- load_observer_->OnLoadUpdate(LoadObserver::kUnderuse); |
+ if (degradation_preference_ == |
+ VideoSendStream::DegradationPreference::kMaintainResolution || |
+ cpu_restricted_counter_ == 0) { |
+ return; |
+ } |
+ |
+ LOG(LS_INFO) << "CPU underuse detected. Requesting higher resolution."; |
+ int current_pixel_count = last_frame_height_ * last_frame_width_; |
+ // Request higher resolution if we are CPU restricted and the the current |
+ // resolution is higher than last time we requested higher resolution. |
+ // Update stats accordingly. |
+ if (!max_pixel_count_step_up_ || |
+ current_pixel_count > *max_pixel_count_step_up_) { |
+ max_pixel_count_ = rtc::Optional<int>(); |
+ max_pixel_count_step_up_ = rtc::Optional<int>(current_pixel_count); |
+ --cpu_restricted_counter_; |
+ stats_proxy_->OnCpuRestrictedResolutionChanged(cpu_restricted_counter_ > 0); |
+ source_proxy_->RequestHigherResolutionThan(current_pixel_count); |
+ } |
} |
} // namespace webrtc |