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 kVp8MinimumTargetBitrateBytesPerMegapixel = 300000; |
Irfan
2016/10/03 20:21:49
"BytesPerMegapixel" sounds like size. I do not und
Sergey Ulanov
2016/10/06 21:54:34
The correct units would be bytes/(megapixel*second
| |
32 | |
33 // Estimated size in bytes per megapixel of encoded frame at target quality | |
34 // level. | |
35 const int kEstimatedBytesPerMegapixel = 150000; | |
Irfan
2016/10/03 20:21:49
Clarify what is "target quality" here ?
Sergey Ulanov
2016/10/06 21:54:34
Done.
| |
36 | |
37 int64_t GetRegionArea(const webrtc::DesktopRegion& region) { | |
38 int64_t result = 0; | |
39 for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) { | |
40 result += r.rect().width() * r.rect().height(); | |
41 } | |
42 return result; | |
43 } | |
30 | 44 |
31 } // namespace | 45 } // namespace |
32 | 46 |
33 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() | 47 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() |
34 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), | 48 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), |
35 frame_processing_delay_us_(kStatsWindow) {} | 49 frame_processing_delay_us_(kStatsWindow), |
50 encoded_frame_size_(kStatsWindow) {} | |
Irfan
2016/10/03 20:21:49
may be encoded_frame_size_bytes_ ?
Sergey Ulanov
2016/10/06 21:54:34
Removed it now and replaced with updated_region_ar
| |
36 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 51 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
37 | 52 |
38 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { | 53 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { |
39 capture_callback_ = capture_callback; | 54 capture_callback_ = capture_callback; |
40 ScheduleNextFrame(base::TimeTicks::Now()); | 55 ScheduleNextFrame(base::TimeTicks::Now()); |
41 } | 56 } |
42 | 57 |
43 void WebrtcFrameSchedulerSimple::Pause(bool pause) { | 58 void WebrtcFrameSchedulerSimple::Pause(bool pause) { |
44 paused_ = pause; | 59 paused_ = pause; |
45 if (paused_) { | 60 if (paused_) { |
(...skipping 18 matching lines...) Expand all Loading... | |
64 WebrtcVideoEncoder::FrameParams* params_out) { | 79 WebrtcVideoEncoder::FrameParams* params_out) { |
65 base::TimeTicks now = base::TimeTicks::Now(); | 80 base::TimeTicks now = base::TimeTicks::Now(); |
66 | 81 |
67 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 82 if (frame.updated_region().is_empty() && !top_off_is_active_ && |
68 !key_frame_request_) { | 83 !key_frame_request_) { |
69 ScheduleNextFrame(now); | 84 ScheduleNextFrame(now); |
70 return false; | 85 return false; |
71 } | 86 } |
72 | 87 |
73 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. | 88 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. |
74 int minimum_bitrate = | 89 int minimum_bitrate_bytes_per_second = |
75 static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * | 90 kVp8MinimumTargetBitrateBytesPerMegapixel * frame.size().width() * |
76 frame.size().width() * frame.size().height() / 1000000LL; | 91 frame.size().height() / kPixelsPerMegapixel; |
77 params_out->bitrate_kbps = | 92 int bitrate_bytes_per_second = |
78 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); | 93 std::max(minimum_bitrate_bytes_per_second, pacing_bucket_.rate()); |
94 params_out->bitrate_kbps = bitrate_bytes_per_second * 8 / 1000; | |
79 | 95 |
80 // TODO(sergeyu): Currently duration is always set to 1/15 of a second. | 96 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_; | 97 params_out->key_frame = key_frame_request_; |
85 key_frame_request_ = false; | 98 key_frame_request_ = false; |
86 | 99 |
87 params_out->vpx_min_quantizer = 10; | 100 params_out->vpx_min_quantizer = 10; |
101 | |
102 // If bandwidth is being underutilized then libvpx is likely to choose the | |
103 // minimum allowed quantizer value, which means that encoded frame size may be | |
104 // significantly bigger than the bandwidth allows. Detect this case and set | |
105 // vpx_min_quantizer to 60. The quality will be topped off later. | |
106 if (encoded_frame_size_.Average() * kTargetFrameRate < | |
Irfan
2016/10/03 20:21:49
Should we measure the frame rate to get real usage
Sergey Ulanov
2016/10/06 21:54:34
No. What matters here is the bitrate that libvpx o
| |
107 bitrate_bytes_per_second / 2) { | |
108 int expected_frame_size = GetRegionArea(frame.updated_region()) * | |
109 kEstimatedBytesPerMegapixel / kPixelsPerMegapixel; | |
110 base::TimeDelta expected_send_delay = base::TimeDelta::FromMicroseconds( | |
111 base::Time::kMicrosecondsPerSecond * expected_frame_size / | |
112 pacing_bucket_.rate()); | |
113 if (expected_send_delay > kTargetFrameInterval) | |
114 params_out->vpx_min_quantizer = 60; | |
115 } | |
116 | |
88 params_out->vpx_max_quantizer = 63; | 117 params_out->vpx_max_quantizer = 63; |
89 | 118 |
90 params_out->clear_active_map = !top_off_is_active_; | 119 params_out->clear_active_map = !top_off_is_active_; |
91 | 120 |
92 return true; | 121 return true; |
93 } | 122 } |
94 | 123 |
95 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 124 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
96 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 125 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
97 const webrtc::EncodedImageCallback::Result& send_result) { | 126 const webrtc::EncodedImageCallback::Result& send_result) { |
98 base::TimeTicks now = base::TimeTicks::Now(); | 127 base::TimeTicks now = base::TimeTicks::Now(); |
99 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); | 128 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); |
129 encoded_frame_size_.Record(encoded_frame.data.size()); | |
100 | 130 |
101 if (encoded_frame.data.empty()) { | 131 if (encoded_frame.data.empty()) { |
102 top_off_is_active_ = false; | 132 top_off_is_active_ = false; |
103 } else { | 133 } else { |
104 frame_processing_delay_us_.Record( | 134 frame_processing_delay_us_.Record( |
105 (now - last_capture_started_time_).InMicroseconds()); | 135 (now - last_capture_started_time_).InMicroseconds()); |
106 | 136 |
107 // Top-off until the target quantizer value is reached. | 137 // Top-off until the target quantizer value is reached. |
108 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; | 138 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; |
109 } | 139 } |
(...skipping 27 matching lines...) Expand all Loading... | |
137 base::Unretained(this))); | 167 base::Unretained(this))); |
138 } | 168 } |
139 | 169 |
140 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 170 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
141 last_capture_started_time_ = base::TimeTicks::Now(); | 171 last_capture_started_time_ = base::TimeTicks::Now(); |
142 capture_callback_.Run(); | 172 capture_callback_.Run(); |
143 } | 173 } |
144 | 174 |
145 } // namespace protocol | 175 } // namespace protocol |
146 } // namespace remoting | 176 } // namespace remoting |
OLD | NEW |