| Index: remoting/protocol/webrtc_frame_scheduler_simple.cc
|
| diff --git a/remoting/protocol/webrtc_frame_scheduler_simple.cc b/remoting/protocol/webrtc_frame_scheduler_simple.cc
|
| index 6f6d94895cdd46ca8c16d4c97150423a4e3fc5e4..910018c88b632d0118b1f2c6b51ab8b146268b23 100644
|
| --- a/remoting/protocol/webrtc_frame_scheduler_simple.cc
|
| +++ b/remoting/protocol/webrtc_frame_scheduler_simple.cc
|
| @@ -23,16 +23,40 @@ constexpr base::TimeDelta kTargetFrameInterval =
|
| // Target quantizer at which stop the encoding top-off.
|
| const int kTargetQuantizerForVp8TopOff = 30;
|
|
|
| +const int64_t kPixelsPerMegapixel = 1000000;
|
| +
|
| // Minimum target bitrate per megapixel. The value is chosen experimentally such
|
| // that when screen is not changing the codec converges to the target quantizer
|
| // above in less than 10 frames.
|
| const int kVp8MinimumTargetBitrateKbpsPerMegapixel = 2500;
|
|
|
| +// Threshold in number of updated pixels used to detect "big" frames. These
|
| +// frames update significant portion of the screen compared to the preceding
|
| +// frames. For these frames min quantizer may need to be adjusted in order to
|
| +// ensure that they get delivered to the client as soon as possible, in exchange
|
| +// for lower-quality image.
|
| +const int kBigFrameThresholdPixels = 300000;
|
| +
|
| +// Estimated size (in bytes per megapixel) of encoded frame at target quantizer
|
| +// value (see kTargetQuantizerForVp8TopOff). Compression ratio varies depending
|
| +// on the image, so this is just a rough estimate. It's used to predict when
|
| +// encoded "big" frame may be too large to be delivered to the client quickly.
|
| +const int kEstimatedBytesPerMegapixel = 100000;
|
| +
|
| +int64_t GetRegionArea(const webrtc::DesktopRegion& region) {
|
| + int64_t result = 0;
|
| + for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) {
|
| + result += r.rect().width() * r.rect().height();
|
| + }
|
| + return result;
|
| +}
|
| +
|
| } // namespace
|
|
|
| WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple()
|
| : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0),
|
| - frame_processing_delay_us_(kStatsWindow) {}
|
| + frame_processing_delay_us_(kStatsWindow),
|
| + updated_region_area_(kStatsWindow) {}
|
| WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {}
|
|
|
| void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) {
|
| @@ -72,19 +96,37 @@ bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams(
|
|
|
| // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9.
|
| int minimum_bitrate =
|
| - static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) *
|
| + static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) *
|
| frame.size().width() * frame.size().height() / 1000000LL;
|
| params_out->bitrate_kbps =
|
| std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000);
|
|
|
| - // TODO(sergeyu): Currently duration is always set to 1/15 of a second.
|
| - // Experiment with different values, and try changing it dynamically.
|
| - params_out->duration = base::TimeDelta::FromSeconds(1) / 15;
|
| -
|
| + params_out->duration = kTargetFrameInterval;
|
| params_out->key_frame = key_frame_request_;
|
| key_frame_request_ = false;
|
|
|
| params_out->vpx_min_quantizer = 10;
|
| +
|
| + int64_t updated_area = params_out->key_frame
|
| + ? frame.size().width() * frame.size().height()
|
| + : GetRegionArea(frame.updated_region());
|
| +
|
| + // If bandwidth is being underutilized then libvpx is likely to choose the
|
| + // minimum allowed quantizer value, which means that encoded frame size may be
|
| + // significantly bigger than the bandwidth allows. Detect this case and set
|
| + // vpx_min_quantizer to 60. The quality will be topped off later.
|
| + if (updated_area - updated_region_area_.Max() > kBigFrameThresholdPixels) {
|
| + int expected_frame_size = updated_area *
|
| + kEstimatedBytesPerMegapixel / kPixelsPerMegapixel;
|
| + base::TimeDelta expected_send_delay = base::TimeDelta::FromMicroseconds(
|
| + base::Time::kMicrosecondsPerSecond * expected_frame_size /
|
| + pacing_bucket_.rate());
|
| + if (expected_send_delay > kTargetFrameInterval)
|
| + params_out->vpx_min_quantizer = 60;
|
| + }
|
| +
|
| + updated_region_area_.Record(updated_area);
|
| +
|
| params_out->vpx_max_quantizer = 63;
|
|
|
| params_out->clear_active_map = !top_off_is_active_;
|
|
|