| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/webrtc_frame_scheduler_simple.h" | 5 #include "remoting/protocol/webrtc_frame_scheduler_simple.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 9 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 10 | 10 |
| 11 namespace remoting { | 11 namespace remoting { |
| 12 namespace protocol { | 12 namespace protocol { |
| 13 | 13 |
| 14 namespace { | 14 namespace { |
| 15 | 15 |
| 16 // Number of samples used to estimate processing time for the next frame. | 16 // Number of samples used to estimate processing time for the next frame. |
| 17 const int kStatsWindow = 5; | 17 const int kStatsWindow = 5; |
| 18 | 18 |
| 19 const int kTargetFrameRate = 30; | 19 const int kTargetFrameRate = 30; |
| 20 constexpr base::TimeDelta kTargetFrameInterval = | 20 constexpr base::TimeDelta kTargetFrameInterval = |
| 21 base::TimeDelta::FromMilliseconds(1000 / kTargetFrameRate); | 21 base::TimeDelta::FromMilliseconds(1000 / kTargetFrameRate); |
| 22 | 22 |
| 23 // Target quantizer at which stop the encoding top-off. | 23 // Target quantizer at which stop the encoding top-off. |
| 24 const int kTargetQuantizerForVp8TopOff = 30; | 24 const int kTargetQuantizerForVp8TopOff = 30; |
| 25 | 25 |
| 26 const int64_t kPixelsPerMegapixel = 1000000; |
| 27 |
| 26 // Minimum target bitrate per megapixel. The value is chosen experimentally such | 28 // Minimum target bitrate per megapixel. The value is chosen experimentally such |
| 27 // that when screen is not changing the codec converges to the target quantizer | 29 // that when screen is not changing the codec converges to the target quantizer |
| 28 // above in less than 10 frames. | 30 // above in less than 10 frames. |
| 29 const int kVp8MinimumTargetBitrateKbpsPerMegapixel = 2500; | 31 const int kVp8MinimumTargetBitrateKbpsPerMegapixel = 2500; |
| 30 | 32 |
| 33 // Threshold in number of updated pixels used to detect "big" frames. These |
| 34 // frames update significant portion of the screen compared to the preceding |
| 35 // frames. For these frames min quantizer may need to be adjusted in order to |
| 36 // ensure that they get delivered to the client as soon as possible, in exchange |
| 37 // for lower-quality image. |
| 38 const int kBigFrameThresholdPixels = 300000; |
| 39 |
| 40 // Estimated size (in bytes per megapixel) of encoded frame at target quantizer |
| 41 // value (see kTargetQuantizerForVp8TopOff). Compression ratio varies depending |
| 42 // on the image, so this is just a rough estimate. It's used to predict when |
| 43 // encoded "big" frame may be too large to be delivered to the client quickly. |
| 44 const int kEstimatedBytesPerMegapixel = 100000; |
| 45 |
| 46 int64_t GetRegionArea(const webrtc::DesktopRegion& region) { |
| 47 int64_t result = 0; |
| 48 for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) { |
| 49 result += r.rect().width() * r.rect().height(); |
| 50 } |
| 51 return result; |
| 52 } |
| 53 |
| 31 } // namespace | 54 } // namespace |
| 32 | 55 |
| 33 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() | 56 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() |
| 34 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), | 57 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), |
| 35 frame_processing_delay_us_(kStatsWindow) {} | 58 frame_processing_delay_us_(kStatsWindow), |
| 59 updated_region_area_(kStatsWindow) {} |
| 36 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 60 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
| 37 | 61 |
| 38 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { | 62 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { |
| 39 capture_callback_ = capture_callback; | 63 capture_callback_ = capture_callback; |
| 40 ScheduleNextFrame(base::TimeTicks::Now()); | 64 ScheduleNextFrame(base::TimeTicks::Now()); |
| 41 } | 65 } |
| 42 | 66 |
| 43 void WebrtcFrameSchedulerSimple::Pause(bool pause) { | 67 void WebrtcFrameSchedulerSimple::Pause(bool pause) { |
| 44 paused_ = pause; | 68 paused_ = pause; |
| 45 if (paused_) { | 69 if (paused_) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 65 base::TimeTicks now = base::TimeTicks::Now(); | 89 base::TimeTicks now = base::TimeTicks::Now(); |
| 66 | 90 |
| 67 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 91 if (frame.updated_region().is_empty() && !top_off_is_active_ && |
| 68 !key_frame_request_) { | 92 !key_frame_request_) { |
| 69 ScheduleNextFrame(now); | 93 ScheduleNextFrame(now); |
| 70 return false; | 94 return false; |
| 71 } | 95 } |
| 72 | 96 |
| 73 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. | 97 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. |
| 74 int minimum_bitrate = | 98 int minimum_bitrate = |
| 75 static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * | 99 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * |
| 76 frame.size().width() * frame.size().height() / 1000000LL; | 100 frame.size().width() * frame.size().height() / 1000000LL; |
| 77 params_out->bitrate_kbps = | 101 params_out->bitrate_kbps = |
| 78 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); | 102 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); |
| 79 | 103 |
| 80 // TODO(sergeyu): Currently duration is always set to 1/15 of a second. | 104 params_out->duration = kTargetFrameInterval; |
| 81 // Experiment with different values, and try changing it dynamically. | |
| 82 params_out->duration = base::TimeDelta::FromSeconds(1) / 15; | |
| 83 | |
| 84 params_out->key_frame = key_frame_request_; | 105 params_out->key_frame = key_frame_request_; |
| 85 key_frame_request_ = false; | 106 key_frame_request_ = false; |
| 86 | 107 |
| 87 params_out->vpx_min_quantizer = 10; | 108 params_out->vpx_min_quantizer = 10; |
| 109 |
| 110 int64_t updated_area = params_out->key_frame |
| 111 ? frame.size().width() * frame.size().height() |
| 112 : GetRegionArea(frame.updated_region()); |
| 113 |
| 114 // If bandwidth is being underutilized then libvpx is likely to choose the |
| 115 // minimum allowed quantizer value, which means that encoded frame size may be |
| 116 // significantly bigger than the bandwidth allows. Detect this case and set |
| 117 // vpx_min_quantizer to 60. The quality will be topped off later. |
| 118 if (updated_area - updated_region_area_.Max() > kBigFrameThresholdPixels) { |
| 119 int expected_frame_size = updated_area * |
| 120 kEstimatedBytesPerMegapixel / kPixelsPerMegapixel; |
| 121 base::TimeDelta expected_send_delay = base::TimeDelta::FromMicroseconds( |
| 122 base::Time::kMicrosecondsPerSecond * expected_frame_size / |
| 123 pacing_bucket_.rate()); |
| 124 if (expected_send_delay > kTargetFrameInterval) |
| 125 params_out->vpx_min_quantizer = 60; |
| 126 } |
| 127 |
| 128 updated_region_area_.Record(updated_area); |
| 129 |
| 88 params_out->vpx_max_quantizer = 63; | 130 params_out->vpx_max_quantizer = 63; |
| 89 | 131 |
| 90 params_out->clear_active_map = !top_off_is_active_; | 132 params_out->clear_active_map = !top_off_is_active_; |
| 91 | 133 |
| 92 return true; | 134 return true; |
| 93 } | 135 } |
| 94 | 136 |
| 95 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 137 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
| 96 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 138 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
| 97 const webrtc::EncodedImageCallback::Result& send_result) { | 139 const webrtc::EncodedImageCallback::Result& send_result) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 base::Unretained(this))); | 179 base::Unretained(this))); |
| 138 } | 180 } |
| 139 | 181 |
| 140 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 182 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
| 141 last_capture_started_time_ = base::TimeTicks::Now(); | 183 last_capture_started_time_ = base::TimeTicks::Now(); |
| 142 capture_callback_.Run(); | 184 capture_callback_.Run(); |
| 143 } | 185 } |
| 144 | 186 |
| 145 } // namespace protocol | 187 } // namespace protocol |
| 146 } // namespace remoting | 188 } // namespace remoting |
| OLD | NEW |