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

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

Issue 2562893003: Limit target encoder bitrate change frequency in the frame scheduler. (Closed)
Patch Set: . Created 4 years 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 "remoting/protocol/frame_stats.h" 9 #include "remoting/protocol/frame_stats.h"
10 #include "remoting/protocol/webrtc_dummy_video_encoder.h" 10 #include "remoting/protocol/webrtc_dummy_video_encoder.h"
(...skipping 27 matching lines...) Expand all
38 // ensure that they get delivered to the client as soon as possible, in exchange 38 // ensure that they get delivered to the client as soon as possible, in exchange
39 // for lower-quality image. 39 // for lower-quality image.
40 const int kBigFrameThresholdPixels = 300000; 40 const int kBigFrameThresholdPixels = 300000;
41 41
42 // Estimated size (in bytes per megapixel) of encoded frame at target quantizer 42 // Estimated size (in bytes per megapixel) of encoded frame at target quantizer
43 // value (see kTargetQuantizerForVp8TopOff). Compression ratio varies depending 43 // value (see kTargetQuantizerForVp8TopOff). Compression ratio varies depending
44 // on the image, so this is just a rough estimate. It's used to predict when 44 // on the image, so this is just a rough estimate. It's used to predict when
45 // encoded "big" frame may be too large to be delivered to the client quickly. 45 // encoded "big" frame may be too large to be delivered to the client quickly.
46 const int kEstimatedBytesPerMegapixel = 100000; 46 const int kEstimatedBytesPerMegapixel = 100000;
47 47
48 // Interval over which the bandwidth estimates is averaged to set target encoder
49 // bitrate.
50 constexpr base::TimeDelta kBandwidthAveragingInterval =
51 base::TimeDelta::FromSeconds(1);
52
53 // Only update encoder bitrate when bandwidth changes by more than 33%. This
54 // value is chosen such that the codec is notified about significant changes in
55 // bandwidth, while ignoring bandwidth estimate noise. This is necessary because
56 // the encoder drops quality every time it's being reconfigured. When using VP8
57 // encoder in realtime mode encoded frame size correlates very poorly with the
58 // target bitrate, so it's not necessary to set target bitrate to match
59 // bandwidth exactly. Send bitrate is controlled more precisely by adjusting
60 // time intervals between frames (i.e. FPS).
61 const int kEncoderBitrateChangePercentage = 33;
62
48 int64_t GetRegionArea(const webrtc::DesktopRegion& region) { 63 int64_t GetRegionArea(const webrtc::DesktopRegion& region) {
49 int64_t result = 0; 64 int64_t result = 0;
50 for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) { 65 for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) {
51 result += r.rect().width() * r.rect().height(); 66 result += r.rect().width() * r.rect().height();
52 } 67 }
53 return result; 68 return result;
54 } 69 }
55 70
56 } // namespace 71 } // namespace
57 72
73 WebrtcFrameSchedulerSimple::EncoderBitrateFilter::EncoderBitrateFilter() {}
74 WebrtcFrameSchedulerSimple::EncoderBitrateFilter::~EncoderBitrateFilter() {}
75
76 void WebrtcFrameSchedulerSimple::EncoderBitrateFilter::SetBandwidthEstimate(
77 int bandwidth_kbps,
78 base::TimeTicks now) {
79 while (!bandwidth_samples_.empty() &&
80 now - bandwidth_samples_.front().first > kBandwidthAveragingInterval) {
81 bandwidth_samples_sum_ -= bandwidth_samples_.front().second;
82 bandwidth_samples_.pop();
83 }
84
85 bandwidth_samples_.push(std::make_pair(now, bandwidth_kbps));
86 bandwidth_samples_sum_ += bandwidth_kbps;
87 }
88
89 int WebrtcFrameSchedulerSimple::EncoderBitrateFilter::GetTargetBitrateKbps(
90 webrtc::DesktopSize size,
91 base::TimeTicks now) {
92 DCHECK(!bandwidth_samples_.empty());
93
94 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for
95 // VP9.
96 int bandwidth_estimate = bandwidth_samples_sum_ / bandwidth_samples_.size();
97 int minimum_bitrate =
98 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) *
99 size.width() * size.height() / 1000000LL;
100 int target_bitrate = std::max(minimum_bitrate, bandwidth_estimate);
101
102 // Update encoder bitrate only when it changes by more than 30%. This is
103 // necessary because the encoder resets internal state when it's reconfigured
104 // and this causes visible drop in quality.
105 if (current_target_bitrate_ == 0 ||
106 std::abs(target_bitrate - current_target_bitrate_) >
107 current_target_bitrate_ * kEncoderBitrateChangePercentage / 100) {
108 current_target_bitrate_ = target_bitrate;
109 }
110 return current_target_bitrate_;
111 }
112
58 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() 113 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple()
59 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), 114 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0),
60 frame_processing_delay_us_(kStatsWindow), 115 frame_processing_delay_us_(kStatsWindow),
61 updated_region_area_(kStatsWindow), 116 updated_region_area_(kStatsWindow),
62 weak_factory_(this) {} 117 weak_factory_(this) {}
118
63 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} 119 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {}
64 120
65 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() { 121 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() {
66 DCHECK(thread_checker_.CalledOnValidThread()); 122 DCHECK(thread_checker_.CalledOnValidThread());
67 key_frame_request_ = true; 123 key_frame_request_ = true;
68 ScheduleNextFrame(base::TimeTicks::Now()); 124 ScheduleNextFrame(base::TimeTicks::Now());
69 } 125 }
70 126
71 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss, 127 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss,
72 base::TimeDelta rtt) { 128 base::TimeDelta rtt) {
73 DCHECK(thread_checker_.CalledOnValidThread()); 129 DCHECK(thread_checker_.CalledOnValidThread());
74 130
75 rtt_estimate_ = rtt; 131 rtt_estimate_ = rtt;
76 } 132 }
77 133
78 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bitrate_kbps) { 134 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bandwidth_kbps) {
79 DCHECK(thread_checker_.CalledOnValidThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
80 base::TimeTicks now = base::TimeTicks::Now(); 136 base::TimeTicks now = base::TimeTicks::Now();
81 pacing_bucket_.UpdateRate(bitrate_kbps * 1000 / 8, now); 137 pacing_bucket_.UpdateRate(bandwidth_kbps * 1000 / 8, now);
138 encoder_bitrate_.SetBandwidthEstimate(bandwidth_kbps, now);
82 ScheduleNextFrame(now); 139 ScheduleNextFrame(now);
83 } 140 }
84 141
85 void WebrtcFrameSchedulerSimple::Start( 142 void WebrtcFrameSchedulerSimple::Start(
86 WebrtcDummyVideoEncoderFactory* video_encoder_factory, 143 WebrtcDummyVideoEncoderFactory* video_encoder_factory,
87 const base::Closure& capture_callback) { 144 const base::Closure& capture_callback) {
88 DCHECK(thread_checker_.CalledOnValidThread()); 145 DCHECK(thread_checker_.CalledOnValidThread());
89 capture_callback_ = capture_callback; 146 capture_callback_ = capture_callback;
90 video_encoder_factory->SetVideoChannelStateObserver( 147 video_encoder_factory->SetVideoChannelStateObserver(
91 weak_factory_.GetWeakPtr()); 148 weak_factory_.GetWeakPtr());
(...skipping 17 matching lines...) Expand all
109 166
110 base::TimeTicks now = base::TimeTicks::Now(); 167 base::TimeTicks now = base::TimeTicks::Now();
111 168
112 if (frame.updated_region().is_empty() && !top_off_is_active_ && 169 if (frame.updated_region().is_empty() && !top_off_is_active_ &&
113 !key_frame_request_) { 170 !key_frame_request_) {
114 frame_pending_ = false; 171 frame_pending_ = false;
115 ScheduleNextFrame(now); 172 ScheduleNextFrame(now);
116 return false; 173 return false;
117 } 174 }
118 175
119 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9.
120 int minimum_bitrate =
121 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) *
122 frame.size().width() * frame.size().height() / 1000000LL;
123 params_out->bitrate_kbps = 176 params_out->bitrate_kbps =
124 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); 177 encoder_bitrate_.GetTargetBitrateKbps(frame.size(), now);
125 178
126 params_out->duration = kTargetFrameInterval; 179 params_out->duration = kTargetFrameInterval;
127 params_out->key_frame = key_frame_request_; 180 params_out->key_frame = key_frame_request_;
128 key_frame_request_ = false; 181 key_frame_request_ = false;
129 182
130 params_out->vpx_min_quantizer = 10; 183 params_out->vpx_min_quantizer = 10;
131 184
132 int64_t updated_area = params_out->key_frame 185 int64_t updated_area = params_out->key_frame
133 ? frame.size().width() * frame.size().height() 186 ? frame.size().width() * frame.size().height()
134 : GetRegionArea(frame.updated_region()); 187 : GetRegionArea(frame.updated_region());
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { 277 void WebrtcFrameSchedulerSimple::CaptureNextFrame() {
225 DCHECK(thread_checker_.CalledOnValidThread()); 278 DCHECK(thread_checker_.CalledOnValidThread());
226 DCHECK(!frame_pending_); 279 DCHECK(!frame_pending_);
227 last_capture_started_time_ = base::TimeTicks::Now(); 280 last_capture_started_time_ = base::TimeTicks::Now();
228 frame_pending_ = true; 281 frame_pending_ = true;
229 capture_callback_.Run(); 282 capture_callback_.Run();
230 } 283 }
231 284
232 } // namespace protocol 285 } // namespace protocol
233 } // namespace remoting 286 } // 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