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/webrtc_dummy_video_encoder.h" | 9 #include "remoting/protocol/webrtc_dummy_video_encoder.h" |
| 10 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 10 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() | 57 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() |
| 58 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), | 58 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), |
| 59 frame_processing_delay_us_(kStatsWindow), | 59 frame_processing_delay_us_(kStatsWindow), |
| 60 updated_region_area_(kStatsWindow), | 60 updated_region_area_(kStatsWindow), |
| 61 weak_factory_(this) {} | 61 weak_factory_(this) {} |
| 62 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 62 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
| 63 | 63 |
| 64 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() { | 64 void WebrtcFrameSchedulerSimple::OnKeyFrameRequested() { |
| 65 DCHECK(thread_checker_.CalledOnValidThread()); | 65 DCHECK(thread_checker_.CalledOnValidThread()); |
| 66 key_frame_request_ = true; | 66 key_frame_request_ = true; |
| 67 if (!capture_timer_.IsRunning()) | 67 ScheduleNextFrame(base::TimeTicks::Now()); |
| 68 ScheduleNextFrame(base::TimeTicks::Now()); | |
| 69 } | 68 } |
| 70 | 69 |
| 71 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss, | 70 void WebrtcFrameSchedulerSimple::OnChannelParameters(int packet_loss, |
| 72 base::TimeDelta rtt) { | 71 base::TimeDelta rtt) { |
| 73 DCHECK(thread_checker_.CalledOnValidThread()); | 72 DCHECK(thread_checker_.CalledOnValidThread()); |
| 74 } | 73 } |
| 75 | 74 |
| 76 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bitrate_kbps) { | 75 void WebrtcFrameSchedulerSimple::OnTargetBitrateChanged(int bitrate_kbps) { |
| 77 DCHECK(thread_checker_.CalledOnValidThread()); | 76 DCHECK(thread_checker_.CalledOnValidThread()); |
| 78 base::TimeTicks now = base::TimeTicks::Now(); | 77 base::TimeTicks now = base::TimeTicks::Now(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 102 | 101 |
| 103 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( | 102 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( |
| 104 const webrtc::DesktopFrame& frame, | 103 const webrtc::DesktopFrame& frame, |
| 105 WebrtcVideoEncoder::FrameParams* params_out) { | 104 WebrtcVideoEncoder::FrameParams* params_out) { |
| 106 DCHECK(thread_checker_.CalledOnValidThread()); | 105 DCHECK(thread_checker_.CalledOnValidThread()); |
| 107 | 106 |
| 108 base::TimeTicks now = base::TimeTicks::Now(); | 107 base::TimeTicks now = base::TimeTicks::Now(); |
| 109 | 108 |
| 110 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 109 if (frame.updated_region().is_empty() && !top_off_is_active_ && |
| 111 !key_frame_request_) { | 110 !key_frame_request_) { |
| 111 frame_pending_ = false; | |
| 112 ScheduleNextFrame(now); | 112 ScheduleNextFrame(now); |
| 113 return false; | 113 return false; |
| 114 } | 114 } |
| 115 | 115 |
| 116 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. | 116 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. |
| 117 int minimum_bitrate = | 117 int minimum_bitrate = |
| 118 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * | 118 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * |
| 119 frame.size().width() * frame.size().height() / 1000000LL; | 119 frame.size().width() * frame.size().height() / 1000000LL; |
| 120 params_out->bitrate_kbps = | 120 params_out->bitrate_kbps = |
| 121 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); | 121 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 150 | 150 |
| 151 params_out->clear_active_map = !top_off_is_active_; | 151 params_out->clear_active_map = !top_off_is_active_; |
| 152 | 152 |
| 153 return true; | 153 return true; |
| 154 } | 154 } |
| 155 | 155 |
| 156 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 156 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
| 157 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 157 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
| 158 const webrtc::EncodedImageCallback::Result& send_result) { | 158 const webrtc::EncodedImageCallback::Result& send_result) { |
| 159 DCHECK(thread_checker_.CalledOnValidThread()); | 159 DCHECK(thread_checker_.CalledOnValidThread()); |
| 160 DCHECK(frame_pending_); | |
| 161 frame_pending_ = false; | |
| 160 | 162 |
| 161 base::TimeTicks now = base::TimeTicks::Now(); | 163 base::TimeTicks now = base::TimeTicks::Now(); |
| 162 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); | 164 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); |
| 163 | 165 |
| 164 if (encoded_frame.data.empty()) { | 166 if (encoded_frame.data.empty()) { |
| 165 top_off_is_active_ = false; | 167 top_off_is_active_ = false; |
| 166 } else { | 168 } else { |
| 167 frame_processing_delay_us_.Record( | 169 frame_processing_delay_us_.Record( |
| 168 (now - last_capture_started_time_).InMicroseconds()); | 170 (now - last_capture_started_time_).InMicroseconds()); |
| 169 | 171 |
| 170 // Top-off until the target quantizer value is reached. | 172 // Top-off until the target quantizer value is reached. |
| 171 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; | 173 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; |
| 172 } | 174 } |
| 173 | 175 |
| 174 ScheduleNextFrame(now); | 176 ScheduleNextFrame(now); |
| 175 } | 177 } |
| 176 | 178 |
| 177 void WebrtcFrameSchedulerSimple::ScheduleNextFrame(base::TimeTicks now) { | 179 void WebrtcFrameSchedulerSimple::ScheduleNextFrame(base::TimeTicks now) { |
| 178 DCHECK(thread_checker_.CalledOnValidThread()); | 180 DCHECK(thread_checker_.CalledOnValidThread()); |
| 179 | 181 |
| 180 // 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 |
| 181 // no capture callback set. | 183 // no capture callback set. |
|
Jamie
2016/10/18 22:40:26
Update this comment. As written now, it's just an
Sergey Ulanov
2016/10/18 23:11:02
Removed it.
| |
| 182 if (paused_ || pacing_bucket_.rate() == 0 || capture_callback_.is_null()) | 184 if (paused_ || pacing_bucket_.rate() == 0 || capture_callback_.is_null() || |
| 185 frame_pending_) { | |
| 183 return; | 186 return; |
| 187 } | |
| 184 | 188 |
| 185 // If this is not the first frame then capture next frame after the previous | 189 // If this is not the first frame then capture next frame after the previous |
| 186 // one has finished sending. | 190 // one has finished sending. |
| 187 base::TimeDelta expected_processing_time = | 191 base::TimeDelta expected_processing_time = |
| 188 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); | 192 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); |
| 189 base::TimeTicks target_capture_time = | 193 base::TimeTicks target_capture_time = |
| 190 pacing_bucket_.GetEmptyTime() - expected_processing_time; | 194 pacing_bucket_.GetEmptyTime() - expected_processing_time; |
| 191 | 195 |
| 192 // Cap interval between frames to kTargetFrameInterval. | 196 // Cap interval between frames to kTargetFrameInterval. |
| 193 if (!last_capture_started_time_.is_null()) { | 197 if (!last_capture_started_time_.is_null()) { |
| 194 target_capture_time = std::max( | 198 target_capture_time = std::max( |
| 195 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); | 199 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); |
| 196 } | 200 } |
| 197 | 201 |
| 198 if (target_capture_time < now) | 202 if (target_capture_time < now) |
| 199 target_capture_time = now; | 203 target_capture_time = now; |
| 200 | 204 |
| 201 capture_timer_.Start(FROM_HERE, target_capture_time - now, | 205 capture_timer_.Start(FROM_HERE, target_capture_time - now, |
| 202 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, | 206 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, |
| 203 base::Unretained(this))); | 207 base::Unretained(this))); |
| 204 } | 208 } |
| 205 | 209 |
| 206 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 210 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
| 207 DCHECK(thread_checker_.CalledOnValidThread()); | 211 DCHECK(thread_checker_.CalledOnValidThread()); |
| 208 | 212 DCHECK(!frame_pending_); |
| 209 last_capture_started_time_ = base::TimeTicks::Now(); | 213 last_capture_started_time_ = base::TimeTicks::Now(); |
| 214 frame_pending_ = true; | |
| 210 capture_callback_.Run(); | 215 capture_callback_.Run(); |
| 211 } | 216 } |
| 212 | 217 |
| 213 } // namespace protocol | 218 } // namespace protocol |
| 214 } // namespace remoting | 219 } // namespace remoting |
| OLD | NEW |