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 |