Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Side by Side Diff: remoting/protocol/webrtc_frame_scheduler_simple.cc

Issue 2381213002: Use high quantizer value for "big" frames after a sequence of "small" frames. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/protocol/webrtc_frame_scheduler_simple.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « remoting/protocol/webrtc_frame_scheduler_simple.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698