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