Chromium Code Reviews| 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 "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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |