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

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
48 int64_t GetRegionArea(const webrtc::DesktopRegion& region) { 53 int64_t GetRegionArea(const webrtc::DesktopRegion& region) {
49 int64_t result = 0; 54 int64_t result = 0;
50 for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) { 55 for (webrtc::DesktopRegion::Iterator r(region); !r.IsAtEnd(); r.Advance()) {
51 result += r.rect().width() * r.rect().height(); 56 result += r.rect().width() * r.rect().height();
52 } 57 }
53 return result; 58 return result;
54 } 59 }
55 60
56 } // namespace 61 } // namespace
57 62
63 WebrtcFrameSchedulerSimple::EncoderBitrateFilter::EncoderBitrateFilter() {}
64 WebrtcFrameSchedulerSimple::EncoderBitrateFilter::~EncoderBitrateFilter() {}
65
66 void WebrtcFrameSchedulerSimple::EncoderBitrateFilter::SetBandwidthEstimate(
67 int bandwidth_kbps,
68 base::TimeTicks now) {
69 bandwidth_samples_.push(std::make_pair(now, bandwidth_kbps));
70 bandwidth_samples_sum_ += bandwidth_kbps;
71
72 while (bandwidth_samples_.size() > 1 &&
Jamie 2016/12/09 23:39:18 It took me a while to work out why you needed at l
Sergey Ulanov 2016/12/10 01:22:57 Done.
73 now - bandwidth_samples_.front().first > kBandwidthAveragingInterval) {
74 bandwidth_samples_sum_ -= bandwidth_samples_.front().second;
75 bandwidth_samples_.pop();
76 }
77 }
78
79 int WebrtcFrameSchedulerSimple::EncoderBitrateFilter::GetTargetBitrateKbps(
80 webrtc::DesktopSize size,
81 base::TimeTicks now) {
82 DCHECK(!bandwidth_samples_.empty());
83
84 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for
85 // VP9.
86 int bandwidth_estimate = bandwidth_samples_sum_ / bandwidth_samples_.size();
87 int minimum_bitrate =
88 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) *
89 size.width() * size.height() / 1000000LL;
90 int target_bitrate = std::max(minimum_bitrate, bandwidth_estimate);
91
92 // Update encoder bitrate only when it changes by more than 30%. This is
93 // necessary because the encoder resets internal state it's reconfigured and
Jamie 2016/12/09 23:39:18 s/it's/when it's/
Sergey Ulanov 2016/12/10 01:22:57 Done.
94 // this causes visible drop in quality.
95 if (current_target_bitrate_ == 0 ||
96 std::abs(target_bitrate - current_target_bitrate_) >
97 current_target_bitrate_ / 3) {
Jamie 2016/12/09 23:39:18 Add a named constant with rationale to explain why
Sergey Ulanov 2016/12/10 01:22:56 Done.
98 current_target_bitrate_ = target_bitrate;
99 }
100 return current_target_bitrate_;
101 }
102
58 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() 103 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple()
59 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), 104 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0),
60 frame_processing_delay_us_(kStatsWindow), 105 frame_processing_delay_us_(kStatsWindow),
61 updated_region_area_(kStatsWindow), 106 updated_region_area_(kStatsWindow),
62 weak_factory_(this) {} 107 weak_factory_(this) {}
108
63 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} 109 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {}
64 110
65 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() { 111 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() {
66 DCHECK(thread_checker_.CalledOnValidThread()); 112 DCHECK(thread_checker_.CalledOnValidThread());
67 key_frame_request_ = true; 113 key_frame_request_ = true;
68 ScheduleNextFrame(base::TimeTicks::Now()); 114 ScheduleNextFrame(base::TimeTicks::Now());
69 } 115 }
70 116
71 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss, 117 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss,
72 base::TimeDelta rtt) { 118 base::TimeDelta rtt) {
73 DCHECK(thread_checker_.CalledOnValidThread()); 119 DCHECK(thread_checker_.CalledOnValidThread());
74 120
75 rtt_estimate_ = rtt; 121 rtt_estimate_ = rtt;
76 } 122 }
77 123
78 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bitrate_kbps) { 124 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bandwidth_kbps) {
79 DCHECK(thread_checker_.CalledOnValidThread()); 125 DCHECK(thread_checker_.CalledOnValidThread());
80 base::TimeTicks now = base::TimeTicks::Now(); 126 base::TimeTicks now = base::TimeTicks::Now();
81 pacing_bucket_.UpdateRate(bitrate_kbps * 1000 / 8, now); 127 pacing_bucket_.UpdateRate(bandwidth_kbps * 1000 / 8, now);
128 encoder_bitrate_.SetBandwidthEstimate(bandwidth_kbps, now);
82 ScheduleNextFrame(now); 129 ScheduleNextFrame(now);
83 } 130 }
84 131
85 void WebrtcFrameSchedulerSimple::Start( 132 void WebrtcFrameSchedulerSimple::Start(
86 WebrtcDummyVideoEncoderFactory* video_encoder_factory, 133 WebrtcDummyVideoEncoderFactory* video_encoder_factory,
87 const base::Closure& capture_callback) { 134 const base::Closure& capture_callback) {
88 DCHECK(thread_checker_.CalledOnValidThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
89 capture_callback_ = capture_callback; 136 capture_callback_ = capture_callback;
90 video_encoder_factory->SetVideoChannelStateObserver( 137 video_encoder_factory->SetVideoChannelStateObserver(
91 weak_factory_.GetWeakPtr()); 138 weak_factory_.GetWeakPtr());
(...skipping 17 matching lines...) Expand all
109 156
110 base::TimeTicks now = base::TimeTicks::Now(); 157 base::TimeTicks now = base::TimeTicks::Now();
111 158
112 if (frame.updated_region().is_empty() && !top_off_is_active_ && 159 if (frame.updated_region().is_empty() && !top_off_is_active_ &&
113 !key_frame_request_) { 160 !key_frame_request_) {
114 frame_pending_ = false; 161 frame_pending_ = false;
115 ScheduleNextFrame(now); 162 ScheduleNextFrame(now);
116 return false; 163 return false;
117 } 164 }
118 165
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 = 166 params_out->bitrate_kbps =
124 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); 167 encoder_bitrate_.GetTargetBitrateKbps(frame.size(), now);
125 168
126 params_out->duration = kTargetFrameInterval; 169 params_out->duration = kTargetFrameInterval;
127 params_out->key_frame = key_frame_request_; 170 params_out->key_frame = key_frame_request_;
128 key_frame_request_ = false; 171 key_frame_request_ = false;
129 172
130 params_out->vpx_min_quantizer = 10; 173 params_out->vpx_min_quantizer = 10;
131 174
132 int64_t updated_area = params_out->key_frame 175 int64_t updated_area = params_out->key_frame
133 ? frame.size().width() * frame.size().height() 176 ? frame.size().width() * frame.size().height()
134 : GetRegionArea(frame.updated_region()); 177 : GetRegionArea(frame.updated_region());
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { 267 void WebrtcFrameSchedulerSimple::CaptureNextFrame() {
225 DCHECK(thread_checker_.CalledOnValidThread()); 268 DCHECK(thread_checker_.CalledOnValidThread());
226 DCHECK(!frame_pending_); 269 DCHECK(!frame_pending_);
227 last_capture_started_time_ = base::TimeTicks::Now(); 270 last_capture_started_time_ = base::TimeTicks::Now();
228 frame_pending_ = true; 271 frame_pending_ = true;
229 capture_callback_.Run(); 272 capture_callback_.Run();
230 } 273 }
231 274
232 } // namespace protocol 275 } // namespace protocol
233 } // namespace remoting 276 } // 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