Chromium Code Reviews| Index: webrtc/video/vie_encoder.cc |
| diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc |
| index a3b071ac00fb058cad52b3290d00d163550744df..f507b04a726f1732482ac410579cb7621b0e0f05 100644 |
| --- a/webrtc/video/vie_encoder.cc |
| +++ b/webrtc/video/vie_encoder.cc |
| @@ -73,6 +73,49 @@ uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) { |
| return std::numeric_limits<uint32_t>::max(); |
| } |
| +// Limits for kBalanced degradation preference. |
| +// >640x480: | max | |
| +// <=640x480: | 15fps | max | |
| +// <=480x270: | 10fps | 15fps | |
| +// <=320x240: | 7fps | 10fps | |
| +// ---------------------------------------------------------- |
| +// kbps: 0 60 130 500 | |
| + |
| +int MinFps(int pixels) { |
| + if (pixels <= 320 * 240) |
| + return 7; |
| + else if (pixels <= 480 * 270) |
| + return 10; |
| + else if (pixels <= 640 * 480) |
| + return 15; |
| + else |
| + return std::numeric_limits<int>::max(); |
| +} |
| + |
| +int MaxFps(int pixels) { |
| + if (pixels <= 320 * 240) |
| + return 10; |
| + else if (pixels <= 480 * 270) |
| + return 15; |
| + else |
| + return std::numeric_limits<int>::max(); |
| +} |
| + |
| +uint32_t BitrateLimit(int pixels) { |
| + if (pixels <= 320 * 240) |
| + return 60000; |
| + else if (pixels <= 480 * 270) |
| + return 130000; |
| + else if (pixels <= 640 * 480) |
| + return 500000; |
| + else |
| + return std::numeric_limits<uint32_t>::max(); |
| +} |
| + |
| +int MaxFpsForBitrateAndResolution(uint32_t bps, int pixels) { |
| + return (bps <= BitrateLimit(pixels)) ? MinFps(pixels) : MaxFps(pixels); |
| +} |
| + |
| bool IsResolutionScalingEnabled( |
| VideoSendStream::DegradationPreference degradation_preference) { |
| return degradation_preference == |
| @@ -211,7 +254,7 @@ class ViEEncoder::VideoSourceProxy { |
| // the used degradation_preference. |
| switch (degradation_preference_) { |
| case VideoSendStream::DegradationPreference::kBalanced: |
| - FALLTHROUGH(); |
| + break; |
| case VideoSendStream::DegradationPreference::kMaintainFramerate: |
| wants.max_framerate_fps = std::numeric_limits<int>::max(); |
| break; |
| @@ -230,54 +273,50 @@ class ViEEncoder::VideoSourceProxy { |
| bool RequestResolutionLowerThan(int pixel_count) { |
| // Called on the encoder task queue. |
| rtc::CritScope lock(&crit_); |
| - if (!IsResolutionScalingEnabledLocked()) { |
| + if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) { |
| // This can happen since |degradation_preference_| is set on libjingle's |
| // worker thread but the adaptation is done on the encoder task queue. |
| return false; |
| } |
| - // 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. |
| + // The input video frame size will have a resolution less than or equal to |
| + // |max_pixel_count| depending on how the source can scale the frame size. |
| const int pixels_wanted = (pixel_count * 3) / 5; |
| - if (pixels_wanted < kMinPixelsPerFrame) |
| + if (pixels_wanted < kMinPixelsPerFrame || |
| + pixels_wanted >= sink_wants_.max_pixel_count) { |
| return false; |
| - |
| + } |
| + LOG(LS_INFO) << "Scaling down resolution"; |
| sink_wants_.max_pixel_count = pixels_wanted; |
| sink_wants_.target_pixel_count = rtc::Optional<int>(); |
| - if (source_) |
| - source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| return true; |
| } |
| - void RequestFramerateLowerThan(int framerate_fps) { |
| + bool RequestFramerateLowerThan(int 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 2/3 of input fps, |
| - // rounding down. |
| - const int framerate_wanted = |
| - std::max(kMinFramerateFps, (framerate_fps * 2) / 3); |
| - sink_wants_.max_framerate_fps = framerate_wanted; |
| - if (source_) |
| - source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + // The input video frame rate will be scaled down to 2/3, rounding down. |
| + return RestrictFramerate((fps * 2) / 3); |
| } |
| - void RequestHigherResolutionThan(int pixel_count) { |
| + bool RequestHigherResolutionThan(int pixel_count) { |
| + // Called on the encoder task queue. |
| rtc::CritScope lock(&crit_); |
| - if (!IsResolutionScalingEnabledLocked()) { |
| + if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) { |
| // This can happen since |degradation_preference_| is set on libjingle's |
| // worker thread but the adaptation is done on the encoder task queue. |
| - return; |
| + return false; |
| } |
| + int max_pixels_wanted = pixel_count; |
| + if (max_pixels_wanted != std::numeric_limits<int>::max()) |
| + max_pixels_wanted = pixel_count * 4; |
| - if (pixel_count == std::numeric_limits<int>::max()) { |
| + if (max_pixels_wanted <= sink_wants_.max_pixel_count) |
| + return false; |
| + |
| + 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(); |
| - sink_wants_.max_pixel_count = std::numeric_limits<int>::max(); |
| } else { |
| // On step down we request at most 3/5 the pixel count of the previous |
| // resolution, so in order to take "one step up" we request a resolution |
| @@ -287,49 +326,55 @@ class ViEEncoder::VideoSourceProxy { |
| // most four time the current number of pixels. |
| sink_wants_.target_pixel_count = |
| rtc::Optional<int>((pixel_count * 5) / 3); |
| - sink_wants_.max_pixel_count = pixel_count * 4; |
| } |
| - if (source_) |
| - source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + LOG(LS_INFO) << "Scaling up resolution"; |
| + source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + return true; |
| } |
| - void RequestHigherFramerateThan(int framerate_fps) { |
| + bool RequestHigherFramerateThan(int 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; |
| - } |
| - if (framerate_fps == std::numeric_limits<int>::max()) { |
| - // Remove any restrains. |
| - sink_wants_.max_framerate_fps = std::numeric_limits<int>::max(); |
| - } else { |
| - // The input video frame rate will be scaled up to the last step, with |
| - // rounding. |
| - const int framerate_wanted = (framerate_fps * 3) / 2; |
| - sink_wants_.max_framerate_fps = framerate_wanted; |
| - } |
| - if (source_) |
| - source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + // 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); |
| } |
| - private: |
| - bool IsResolutionScalingEnabledLocked() const |
| - EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
| - return degradation_preference_ == |
| - VideoSendStream::DegradationPreference::kMaintainFramerate || |
| - degradation_preference_ == |
| - VideoSendStream::DegradationPreference::kBalanced; |
| + bool RestrictFramerate(int fps) { |
| + // Called on the encoder task queue. |
| + rtc::CritScope lock(&crit_); |
| + if (!source_ || !IsFramerateScalingEnabled(degradation_preference_)) |
| + return false; |
| + |
| + const int fps_wanted = std::max(kMinFramerateFps, fps); |
| + if (fps_wanted >= sink_wants_.max_framerate_fps) |
| + return false; |
| + |
| + LOG(LS_INFO) << "Scaling down framerate: " << fps_wanted; |
| + sink_wants_.max_framerate_fps = fps_wanted; |
| + source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + return true; |
| } |
| - bool IsFramerateScalingEnabledLocked() const |
| - EXCLUSIVE_LOCKS_REQUIRED(&crit_) { |
| - // TODO(sprang): Also accept kBalanced here? |
| - return degradation_preference_ == |
| - VideoSendStream::DegradationPreference::kMaintainResolution; |
| + bool IncreaseFramerate(int fps) { |
| + // Called on the encoder task queue. |
| + rtc::CritScope lock(&crit_); |
| + if (!source_ || !IsFramerateScalingEnabled(degradation_preference_)) |
| + return false; |
| + |
| + const int fps_wanted = std::max(kMinFramerateFps, fps); |
| + if (fps_wanted <= sink_wants_.max_framerate_fps) |
| + return false; |
| + |
| + LOG(LS_INFO) << "Scaling up framerate: " << fps_wanted; |
| + sink_wants_.max_framerate_fps = fps_wanted; |
| + source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants()); |
| + return true; |
| } |
| + private: |
| rtc::CriticalSection crit_; |
| rtc::SequencedTaskChecker main_checker_; |
| ViEEncoder* const vie_encoder_; |
| @@ -645,7 +690,6 @@ void ViEEncoder::TraceFrameDropStart() { |
| TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this); |
| } |
| encoder_paused_and_dropped_frame_ = true; |
| - return; |
| } |
| void ViEEncoder::TraceFrameDropEnd() { |
| @@ -817,7 +861,8 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { |
| int max_downgrades = 0; |
| switch (degradation_preference_) { |
| case VideoSendStream::DegradationPreference::kBalanced: |
| - FALLTHROUGH(); |
| + max_downgrades = kMaxCpuResolutionDowngrades; |
| + break; |
| case VideoSendStream::DegradationPreference::kMaintainFramerate: |
| max_downgrades = kMaxCpuResolutionDowngrades; |
| if (downgrade_requested && |
| @@ -852,21 +897,32 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { |
| } |
| switch (degradation_preference_) { |
| - case VideoSendStream::DegradationPreference::kBalanced: |
| + case VideoSendStream::DegradationPreference::kBalanced: { |
| + // Try scale down framerate, if lower. |
| + int max_fps = MaxFpsForBitrateAndResolution( |
| + last_observed_bitrate_bps_, last_frame_info_->pixel_count()); |
| + if (source_proxy_->RestrictFramerate(max_fps)) { |
| + GetAdaptCounter().IncrementFramerate(reason); |
| + break; |
| + } |
| + // Scale down resolution. |
| FALLTHROUGH(); |
| + } |
| case VideoSendStream::DegradationPreference::kMaintainFramerate: |
| + // Scale down resolution. |
| if (!source_proxy_->RequestResolutionLowerThan( |
| adaptation_request.input_pixel_count_)) { |
| return; |
| } |
| - LOG(LS_INFO) << "Scaling down resolution."; |
| - GetAdaptCounter().IncrementResolution(reason, 1); |
| + GetAdaptCounter().IncrementResolution(reason); |
| break; |
| case VideoSendStream::DegradationPreference::kMaintainResolution: |
| - source_proxy_->RequestFramerateLowerThan( |
| - adaptation_request.framerate_fps_); |
| - LOG(LS_INFO) << "Scaling down framerate."; |
| - GetAdaptCounter().IncrementFramerate(reason, 1); |
| + // Scale down framerate. |
| + if (!source_proxy_->RequestFramerateLowerThan( |
| + adaptation_request.framerate_fps_)) { |
| + return; |
| + } |
| + GetAdaptCounter().IncrementFramerate(reason); |
| break; |
| case VideoSendStream::DegradationPreference::kDegradationDisabled: |
| RTC_NOTREACHED(); |
| @@ -897,55 +953,54 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { |
| last_adaptation_request_ && |
| last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp; |
| - switch (degradation_preference_) { |
| - case VideoSendStream::DegradationPreference::kBalanced: |
| - FALLTHROUGH(); |
| - case VideoSendStream::DegradationPreference::kMaintainFramerate: |
| - if (adapt_up_requested && |
| - 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 VideoSendStream::DegradationPreference::kMaintainResolution: |
| - // TODO(sprang): Don't request higher framerate if we are already at |
| - // max requested fps? |
| - break; |
| - case VideoSendStream::DegradationPreference::kDegradationDisabled: |
| + if (degradation_preference_ == |
| + VideoSendStream::DegradationPreference::kMaintainFramerate) { |
| + if (adapt_up_requested && |
| + 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; |
| + } |
| } |
| switch (degradation_preference_) { |
| - case VideoSendStream::DegradationPreference::kBalanced: |
| + case VideoSendStream::DegradationPreference::kBalanced: { |
| + // Try scale up framerate, if higher. |
| + int fps = MaxFps(last_frame_info_->pixel_count()); |
| + if (source_proxy_->IncreaseFramerate(fps)) { |
| + GetAdaptCounter().DecrementFramerate(reason); |
| + break; |
| + } |
| + // Scale up resolution. |
| FALLTHROUGH(); |
| - case VideoSendStream::DegradationPreference::kMaintainFramerate: |
| - if (adapt_counter.TotalCount() == 1) { |
| + } |
| + case VideoSendStream::DegradationPreference::kMaintainFramerate: { |
| + // Scale up resolution. |
| + int pixel_count = adaptation_request.input_pixel_count_; |
| + if (adapt_counter.ResolutionCount() == 1) { |
| LOG(LS_INFO) << "Removing resolution down-scaling setting."; |
| - source_proxy_->RequestHigherResolutionThan( |
| - std::numeric_limits<int>::max()); |
| - } else { |
| - source_proxy_->RequestHigherResolutionThan( |
| - adaptation_request.input_pixel_count_); |
| - LOG(LS_INFO) << "Scaling up resolution."; |
| + pixel_count = std::numeric_limits<int>::max(); |
| } |
| - GetAdaptCounter().IncrementResolution(reason, -1); |
| + if (!source_proxy_->RequestHigherResolutionThan(pixel_count)) |
| + return; |
| + GetAdaptCounter().DecrementResolution(reason); |
| break; |
| - case VideoSendStream::DegradationPreference::kMaintainResolution: |
| - if (adapt_counter.TotalCount() == 1) { |
| + } |
| + case VideoSendStream::DegradationPreference::kMaintainResolution: { |
| + // Scale up framerate. |
| + int fps = adaptation_request.framerate_fps_; |
| + if (adapt_counter.FramerateCount() == 1) { |
| LOG(LS_INFO) << "Removing framerate down-scaling setting."; |
| - source_proxy_->RequestHigherFramerateThan( |
| - std::numeric_limits<int>::max()); |
| - } else { |
| - source_proxy_->RequestHigherFramerateThan( |
| - adaptation_request.framerate_fps_); |
| - LOG(LS_INFO) << "Scaling up framerate."; |
| + fps = std::numeric_limits<int>::max(); |
| } |
| - GetAdaptCounter().IncrementFramerate(reason, -1); |
| + if (!source_proxy_->RequestHigherFramerateThan(fps)) |
| + return; |
| + GetAdaptCounter().DecrementFramerate(reason); |
| break; |
| + } |
| case VideoSendStream::DegradationPreference::kDegradationDisabled: |
| - RTC_NOTREACHED(); |
| + return; |
| } |
| last_adaptation_request_.emplace(adaptation_request); |
| @@ -1003,6 +1058,8 @@ const ViEEncoder::AdaptCounter& ViEEncoder::GetConstAdaptCounter() { |
| ViEEncoder::AdaptCounter::AdaptCounter() { |
| fps_counters_.resize(kScaleReasonSize); |
| resolution_counters_.resize(kScaleReasonSize); |
| + RTC_DCHECK_EQ(fps_counters_.size(), 2) << "Update MoveCount()"; |
|
kthelgason
2017/05/30 11:17:06
Perhaps it would be better to add a `static_assert
åsapersson
2017/06/08 13:55:33
Done.
|
| + RTC_DCHECK_EQ(resolution_counters_.size(), 2) << "Update MoveCount()"; |
| } |
| ViEEncoder::AdaptCounter::~AdaptCounter() {} |
| @@ -1021,12 +1078,38 @@ ViEEncoder::AdaptCounts ViEEncoder::AdaptCounter::Counts(int reason) const { |
| return counts; |
| } |
| -void ViEEncoder::AdaptCounter::IncrementFramerate(int reason, int delta) { |
| - fps_counters_[reason] += delta; |
| +void ViEEncoder::AdaptCounter::IncrementFramerate(int reason) { |
| + ++(fps_counters_[reason]); |
| } |
| -void ViEEncoder::AdaptCounter::IncrementResolution(int reason, int delta) { |
| - resolution_counters_[reason] += delta; |
| +void ViEEncoder::AdaptCounter::IncrementResolution(int reason) { |
| + ++(resolution_counters_[reason]); |
| +} |
| + |
| +void ViEEncoder::AdaptCounter::DecrementFramerate(int reason) { |
| + if (fps_counters_[reason] == 0) { |
| + // Adapt up is in a different order, switch reason. |
| + // E.g. framerate adapt down: quality (2), framerate adapt up: cpu (3). |
| + // 1. Down resolution (cpu): res={quality:0,cpu:1}, fps={quality:0,cpu:0} |
| + // 2. Down fps (quality): res={quality:0,cpu:1}, fps={quality:1,cpu:0} |
| + // 3. Up fps (cpu): res={quality:1,cpu:0}, fps={quality:0,cpu:0} |
| + // 4. Up resolution (quality): res={quality:0,cpu:0}, fps={quality:0,cpu:0} |
| + MoveCount(&resolution_counters_, reason); |
| + MoveCount(&fps_counters_, (reason + 1) % kScaleReasonSize); |
| + } |
| + --(fps_counters_[reason]); |
| + RTC_DCHECK_GE(fps_counters_[reason], 0); |
| +} |
| + |
| +void ViEEncoder::AdaptCounter::DecrementResolution(int reason) { |
| + if (resolution_counters_[reason] == 0) { |
| + // Adapt up is in a different order, switch reason. |
| + // E.g. resolution adapt down: quality, resolution adapt up: cpu. |
| + MoveCount(&fps_counters_, reason); |
| + MoveCount(&resolution_counters_, (reason + 1) % kScaleReasonSize); |
| + } |
| + --(resolution_counters_[reason]); |
| + RTC_DCHECK_GE(resolution_counters_[reason], 0); |
| } |
| int ViEEncoder::AdaptCounter::FramerateCount() const { |
| @@ -1057,6 +1140,14 @@ int ViEEncoder::AdaptCounter::Count(const std::vector<int>& counters) const { |
| return std::accumulate(counters.begin(), counters.end(), 0); |
| } |
| +void ViEEncoder::AdaptCounter::MoveCount(std::vector<int>* counters, |
| + int from_reason) { |
| + int to_reason = (from_reason + 1) % kScaleReasonSize; |
| + ++((*counters)[to_reason]); |
| + --((*counters)[from_reason]); |
| + RTC_DCHECK_GE((*counters)[from_reason], 0); |
|
kthelgason
2017/05/30 11:17:06
This postcondition is not at all clear to me. If t
åsapersson
2017/06/08 13:55:33
Done.
|
| +} |
| + |
| std::string ViEEncoder::AdaptCounter::ToString( |
| const std::vector<int>& counters) const { |
| std::stringstream ss; |