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

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 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
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
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
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