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 |