| 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 "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 9 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 10 | 10 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 result += r.rect().width() * r.rect().height(); | 49 result += r.rect().width() * r.rect().height(); |
| 50 } | 50 } |
| 51 return result; | 51 return result; |
| 52 } | 52 } |
| 53 | 53 |
| 54 } // namespace | 54 } // namespace |
| 55 | 55 |
| 56 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() | 56 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() |
| 57 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), | 57 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), |
| 58 frame_processing_delay_us_(kStatsWindow), | 58 frame_processing_delay_us_(kStatsWindow), |
| 59 updated_region_area_(kStatsWindow) {} | 59 updated_region_area_(kStatsWindow), |
| 60 weak_factory_(this) {} |
| 60 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 61 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
| 61 | 62 |
| 63 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() { |
| 64 DCHECK(thread_checker_.CalledOnValidThread()); |
| 65 key_frame_request_ = true; |
| 66 if (!capture_timer_.IsRunning()) |
| 67 ScheduleNextFrame(base::TimeTicks::Now()); |
| 68 } |
| 69 |
| 70 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss, |
| 71 base::TimeDelta rtt) { |
| 72 DCHECK(thread_checker_.CalledOnValidThread()); |
| 73 } |
| 74 |
| 75 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bitrate_kbps) { |
| 76 DCHECK(thread_checker_.CalledOnValidThread()); |
| 77 base::TimeTicks now = base::TimeTicks::Now(); |
| 78 pacing_bucket_.UpdateRate(bitrate_kbps * 1000 / 8, now); |
| 79 ScheduleNextFrame(now); |
| 80 } |
| 81 |
| 82 base::WeakPtr<NetworkStateObserver> |
| 83 WebrtcFrameSchedulerSimple::GetNetworkStateObserver() { |
| 84 DCHECK(thread_checker_.CalledOnValidThread()); |
| 85 return weak_factory_.GetWeakPtr(); |
| 86 } |
| 87 |
| 62 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { | 88 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { |
| 89 DCHECK(thread_checker_.CalledOnValidThread()); |
| 63 capture_callback_ = capture_callback; | 90 capture_callback_ = capture_callback; |
| 64 ScheduleNextFrame(base::TimeTicks::Now()); | 91 ScheduleNextFrame(base::TimeTicks::Now()); |
| 65 } | 92 } |
| 66 | 93 |
| 67 void WebrtcFrameSchedulerSimple::Pause(bool pause) { | 94 void WebrtcFrameSchedulerSimple::Pause(bool pause) { |
| 95 DCHECK(thread_checker_.CalledOnValidThread()); |
| 96 |
| 68 paused_ = pause; | 97 paused_ = pause; |
| 69 if (paused_) { | 98 if (paused_) { |
| 70 capture_timer_.Stop(); | 99 capture_timer_.Stop(); |
| 71 } else { | 100 } else { |
| 72 ScheduleNextFrame(base::TimeTicks::Now()); | 101 ScheduleNextFrame(base::TimeTicks::Now()); |
| 73 } | 102 } |
| 74 } | 103 } |
| 75 | 104 |
| 76 void WebrtcFrameSchedulerSimple::SetKeyFrameRequest() { | |
| 77 key_frame_request_ = true; | |
| 78 } | |
| 79 | |
| 80 void WebrtcFrameSchedulerSimple::SetTargetBitrate(int bitrate_kbps) { | |
| 81 base::TimeTicks now = base::TimeTicks::Now(); | |
| 82 pacing_bucket_.UpdateRate(bitrate_kbps * 1000 / 8, now); | |
| 83 ScheduleNextFrame(now); | |
| 84 } | |
| 85 | |
| 86 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( | 105 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( |
| 87 const webrtc::DesktopFrame& frame, | 106 const webrtc::DesktopFrame& frame, |
| 88 WebrtcVideoEncoder::FrameParams* params_out) { | 107 WebrtcVideoEncoder::FrameParams* params_out) { |
| 108 DCHECK(thread_checker_.CalledOnValidThread()); |
| 109 |
| 89 base::TimeTicks now = base::TimeTicks::Now(); | 110 base::TimeTicks now = base::TimeTicks::Now(); |
| 90 | 111 |
| 91 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 112 if (frame.updated_region().is_empty() && !top_off_is_active_ && |
| 92 !key_frame_request_) { | 113 !key_frame_request_) { |
| 93 ScheduleNextFrame(now); | 114 ScheduleNextFrame(now); |
| 94 return false; | 115 return false; |
| 95 } | 116 } |
| 96 | 117 |
| 97 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. | 118 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. |
| 98 int minimum_bitrate = | 119 int minimum_bitrate = |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 params_out->vpx_max_quantizer = 63; | 151 params_out->vpx_max_quantizer = 63; |
| 131 | 152 |
| 132 params_out->clear_active_map = !top_off_is_active_; | 153 params_out->clear_active_map = !top_off_is_active_; |
| 133 | 154 |
| 134 return true; | 155 return true; |
| 135 } | 156 } |
| 136 | 157 |
| 137 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 158 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
| 138 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 159 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
| 139 const webrtc::EncodedImageCallback::Result& send_result) { | 160 const webrtc::EncodedImageCallback::Result& send_result) { |
| 161 DCHECK(thread_checker_.CalledOnValidThread()); |
| 162 |
| 140 base::TimeTicks now = base::TimeTicks::Now(); | 163 base::TimeTicks now = base::TimeTicks::Now(); |
| 141 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); | 164 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); |
| 142 | 165 |
| 143 if (encoded_frame.data.empty()) { | 166 if (encoded_frame.data.empty()) { |
| 144 top_off_is_active_ = false; | 167 top_off_is_active_ = false; |
| 145 } else { | 168 } else { |
| 146 frame_processing_delay_us_.Record( | 169 frame_processing_delay_us_.Record( |
| 147 (now - last_capture_started_time_).InMicroseconds()); | 170 (now - last_capture_started_time_).InMicroseconds()); |
| 148 | 171 |
| 149 // Top-off until the target quantizer value is reached. | 172 // Top-off until the target quantizer value is reached. |
| 150 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; | 173 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; |
| 151 } | 174 } |
| 152 | 175 |
| 153 ScheduleNextFrame(now); | 176 ScheduleNextFrame(now); |
| 154 } | 177 } |
| 155 | 178 |
| 156 void WebrtcFrameSchedulerSimple::ScheduleNextFrame(base::TimeTicks now) { | 179 void WebrtcFrameSchedulerSimple::ScheduleNextFrame(base::TimeTicks now) { |
| 180 DCHECK(thread_checker_.CalledOnValidThread()); |
| 181 |
| 157 // Don't capture frames when paused or target bitrate is 0 or there is | 182 // Don't capture frames when paused or target bitrate is 0 or there is |
| 158 // no capture callback set. | 183 // no capture callback set. |
| 159 if (paused_ || pacing_bucket_.rate() == 0 || capture_callback_.is_null()) | 184 if (paused_ || pacing_bucket_.rate() == 0 || capture_callback_.is_null()) |
| 160 return; | 185 return; |
| 161 | 186 |
| 162 // If this is not the first frame then capture next frame after the previous | 187 // If this is not the first frame then capture next frame after the previous |
| 163 // one has finished sending. | 188 // one has finished sending. |
| 164 base::TimeDelta expected_processing_time = | 189 base::TimeDelta expected_processing_time = |
| 165 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); | 190 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); |
| 166 base::TimeTicks target_capture_time = | 191 base::TimeTicks target_capture_time = |
| 167 pacing_bucket_.GetEmptyTime() - expected_processing_time; | 192 pacing_bucket_.GetEmptyTime() - expected_processing_time; |
| 168 | 193 |
| 169 // Cap interval between frames to kTargetFrameInterval. | 194 // Cap interval between frames to kTargetFrameInterval. |
| 170 if (!last_capture_started_time_.is_null()) { | 195 if (!last_capture_started_time_.is_null()) { |
| 171 target_capture_time = std::max( | 196 target_capture_time = std::max( |
| 172 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); | 197 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); |
| 173 } | 198 } |
| 174 | 199 |
| 175 if (target_capture_time < now) | 200 if (target_capture_time < now) |
| 176 target_capture_time = now; | 201 target_capture_time = now; |
| 177 | 202 |
| 178 capture_timer_.Start(FROM_HERE, target_capture_time - now, | 203 capture_timer_.Start(FROM_HERE, target_capture_time - now, |
| 179 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, | 204 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, |
| 180 base::Unretained(this))); | 205 base::Unretained(this))); |
| 181 } | 206 } |
| 182 | 207 |
| 183 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 208 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
| 209 DCHECK(thread_checker_.CalledOnValidThread()); |
| 210 |
| 184 last_capture_started_time_ = base::TimeTicks::Now(); | 211 last_capture_started_time_ = base::TimeTicks::Now(); |
| 185 capture_callback_.Run(); | 212 capture_callback_.Run(); |
| 186 } | 213 } |
| 187 | 214 |
| 188 } // namespace protocol | 215 } // namespace protocol |
| 189 } // namespace remoting | 216 } // namespace remoting |
| OLD | NEW |