OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/host/video_scheduler.h" | 5 #include "remoting/host/video_scheduler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 23 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
24 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_shape.h" | 24 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_shape.h" |
25 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" | 25 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" |
26 | 26 |
27 namespace remoting { | 27 namespace remoting { |
28 | 28 |
29 // Maximum number of frames that can be processed simultaneously. | 29 // Maximum number of frames that can be processed simultaneously. |
30 // TODO(hclam): Move this value to CaptureScheduler. | 30 // TODO(hclam): Move this value to CaptureScheduler. |
31 static const int kMaxPendingFrames = 2; | 31 static const int kMaxPendingFrames = 2; |
32 | 32 |
| 33 // Interval between empty keep-alive frames. These frames are sent only |
| 34 // when there are no real video frames being sent. |
| 35 static const int kKeepAlivePacketIntervalMs = 500; |
| 36 |
33 VideoScheduler::VideoScheduler( | 37 VideoScheduler::VideoScheduler( |
34 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, | 38 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, |
35 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, | 39 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, |
36 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, | 40 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, |
37 scoped_ptr<webrtc::ScreenCapturer> capturer, | 41 scoped_ptr<webrtc::ScreenCapturer> capturer, |
38 scoped_ptr<VideoEncoder> encoder, | 42 scoped_ptr<VideoEncoder> encoder, |
39 protocol::CursorShapeStub* cursor_stub, | 43 protocol::CursorShapeStub* cursor_stub, |
40 protocol::VideoStub* video_stub) | 44 protocol::VideoStub* video_stub) |
41 : capture_task_runner_(capture_task_runner), | 45 : capture_task_runner_(capture_task_runner), |
42 encode_task_runner_(encode_task_runner), | 46 encode_task_runner_(encode_task_runner), |
(...skipping 18 matching lines...) Expand all Loading... |
61 | 65 |
62 webrtc::SharedMemory* VideoScheduler::CreateSharedMemory(size_t size) { | 66 webrtc::SharedMemory* VideoScheduler::CreateSharedMemory(size_t size) { |
63 return NULL; | 67 return NULL; |
64 } | 68 } |
65 | 69 |
66 void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) { | 70 void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) { |
67 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 71 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
68 | 72 |
69 capture_pending_ = false; | 73 capture_pending_ = false; |
70 | 74 |
| 75 if (!frame) { |
| 76 LOG(ERROR) << "Capture failed."; |
| 77 return; |
| 78 } |
| 79 |
71 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); | 80 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); |
72 | 81 |
73 if (frame) { | 82 scheduler_.RecordCaptureTime( |
74 scheduler_.RecordCaptureTime( | 83 base::TimeDelta::FromMilliseconds(frame->capture_time_ms())); |
75 base::TimeDelta::FromMilliseconds(frame->capture_time_ms())); | 84 |
| 85 // Encode and send only non-empty frames. |
| 86 if (!frame->updated_region().is_empty()) { |
| 87 encode_task_runner_->PostTask( |
| 88 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, |
| 89 base::Passed(&owned_frame), sequence_number_)); |
76 } | 90 } |
77 | 91 |
78 encode_task_runner_->PostTask( | |
79 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, | |
80 base::Passed(&owned_frame), sequence_number_)); | |
81 | |
82 // If a frame was skipped, try to capture it again. | 92 // If a frame was skipped, try to capture it again. |
83 if (did_skip_frame_) { | 93 if (did_skip_frame_) { |
84 capture_task_runner_->PostTask( | 94 capture_task_runner_->PostTask( |
85 FROM_HERE, base::Bind(&VideoScheduler::CaptureNextFrame, this)); | 95 FROM_HERE, base::Bind(&VideoScheduler::CaptureNextFrame, this)); |
86 } | 96 } |
87 } | 97 } |
88 | 98 |
89 void VideoScheduler::OnCursorShapeChanged( | 99 void VideoScheduler::OnCursorShapeChanged( |
90 webrtc::MouseCursorShape* cursor_shape) { | 100 webrtc::MouseCursorShape* cursor_shape) { |
91 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 101 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
(...skipping 24 matching lines...) Expand all Loading... |
116 FROM_HERE, base::Bind(&VideoScheduler::StartOnCaptureThread, this)); | 126 FROM_HERE, base::Bind(&VideoScheduler::StartOnCaptureThread, this)); |
117 } | 127 } |
118 | 128 |
119 void VideoScheduler::Stop() { | 129 void VideoScheduler::Stop() { |
120 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 130 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
121 | 131 |
122 // Clear stubs to prevent further updates reaching the client. | 132 // Clear stubs to prevent further updates reaching the client. |
123 cursor_stub_ = NULL; | 133 cursor_stub_ = NULL; |
124 video_stub_ = NULL; | 134 video_stub_ = NULL; |
125 | 135 |
126 capture_task_runner_->PostTask(FROM_HERE, | 136 keep_alive_timer_.reset(); |
127 base::Bind(&VideoScheduler::StopOnCaptureThread, this)); | 137 |
| 138 capture_task_runner_->PostTask( |
| 139 FROM_HERE, base::Bind(&VideoScheduler::StopOnCaptureThread, this)); |
128 } | 140 } |
129 | 141 |
130 void VideoScheduler::Pause(bool pause) { | 142 void VideoScheduler::Pause(bool pause) { |
131 if (!capture_task_runner_->BelongsToCurrentThread()) { | 143 if (!capture_task_runner_->BelongsToCurrentThread()) { |
132 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 144 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
133 capture_task_runner_->PostTask( | 145 capture_task_runner_->PostTask( |
134 FROM_HERE, base::Bind(&VideoScheduler::Pause, this, pause)); | 146 FROM_HERE, base::Bind(&VideoScheduler::Pause, this, pause)); |
135 return; | 147 return; |
136 } | 148 } |
137 | 149 |
(...skipping 27 matching lines...) Expand all Loading... |
165 | 177 |
166 void VideoScheduler::StartOnCaptureThread() { | 178 void VideoScheduler::StartOnCaptureThread() { |
167 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 179 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
168 DCHECK(!capture_timer_); | 180 DCHECK(!capture_timer_); |
169 | 181 |
170 // Start the capturer and let it notify us if cursor shape changes. | 182 // Start the capturer and let it notify us if cursor shape changes. |
171 capturer_->SetMouseShapeObserver(this); | 183 capturer_->SetMouseShapeObserver(this); |
172 capturer_->Start(this); | 184 capturer_->Start(this); |
173 | 185 |
174 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); | 186 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); |
| 187 keep_alive_timer_.reset(new base::DelayTimer<VideoScheduler>( |
| 188 FROM_HERE, base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs), |
| 189 this, &VideoScheduler::SendKeepAlivePacket)); |
175 | 190 |
176 // Capture first frame immedately. | 191 // Capture first frame immedately. |
177 CaptureNextFrame(); | 192 CaptureNextFrame(); |
178 } | 193 } |
179 | 194 |
180 void VideoScheduler::StopOnCaptureThread() { | 195 void VideoScheduler::StopOnCaptureThread() { |
181 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 196 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
182 | 197 |
183 // This doesn't deleted already captured frames, so encoder can keep using the | 198 // This doesn't deleted already captured frames, so encoder can keep using the |
184 // frames that were captured previously. | 199 // frames that were captured previously. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 | 257 |
243 // Network thread -------------------------------------------------------------- | 258 // Network thread -------------------------------------------------------------- |
244 | 259 |
245 void VideoScheduler::SendVideoPacket(scoped_ptr<VideoPacket> packet) { | 260 void VideoScheduler::SendVideoPacket(scoped_ptr<VideoPacket> packet) { |
246 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 261 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
247 | 262 |
248 if (!video_stub_) | 263 if (!video_stub_) |
249 return; | 264 return; |
250 | 265 |
251 video_stub_->ProcessVideoPacket( | 266 video_stub_->ProcessVideoPacket( |
252 packet.Pass(), base::Bind(&VideoScheduler::VideoFrameSentCallback, this)); | 267 packet.Pass(), base::Bind(&VideoScheduler::OnVideoPacketSent, this)); |
253 } | 268 } |
254 | 269 |
255 void VideoScheduler::VideoFrameSentCallback() { | 270 void VideoScheduler::OnVideoPacketSent() { |
256 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 271 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
257 | 272 |
258 if (!video_stub_) | 273 if (!video_stub_) |
259 return; | 274 return; |
260 | 275 |
| 276 keep_alive_timer_->Reset(); |
| 277 |
261 capture_task_runner_->PostTask( | 278 capture_task_runner_->PostTask( |
262 FROM_HERE, base::Bind(&VideoScheduler::FrameCaptureCompleted, this)); | 279 FROM_HERE, base::Bind(&VideoScheduler::FrameCaptureCompleted, this)); |
263 } | 280 } |
264 | 281 |
| 282 void VideoScheduler::SendKeepAlivePacket() { |
| 283 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 284 |
| 285 if (!video_stub_) |
| 286 return; |
| 287 |
| 288 video_stub_->ProcessVideoPacket( |
| 289 scoped_ptr<VideoPacket>(new VideoPacket()), |
| 290 base::Bind(&VideoScheduler::OnKeepAlivePacketSent, this)); |
| 291 } |
| 292 |
| 293 void VideoScheduler::OnKeepAlivePacketSent() { |
| 294 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 295 |
| 296 if (keep_alive_timer_) |
| 297 keep_alive_timer_->Reset(); |
| 298 } |
| 299 |
265 void VideoScheduler::SendCursorShape( | 300 void VideoScheduler::SendCursorShape( |
266 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { | 301 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { |
267 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 302 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
268 | 303 |
269 if (!cursor_stub_) | 304 if (!cursor_stub_) |
270 return; | 305 return; |
271 | 306 |
272 cursor_stub_->SetCursorShape(*cursor_shape); | 307 cursor_stub_->SetCursorShape(*cursor_shape); |
273 } | 308 } |
274 | 309 |
275 // Encoder thread -------------------------------------------------------------- | 310 // Encoder thread -------------------------------------------------------------- |
276 | 311 |
277 void VideoScheduler::EncodeFrame( | 312 void VideoScheduler::EncodeFrame( |
278 scoped_ptr<webrtc::DesktopFrame> frame, | 313 scoped_ptr<webrtc::DesktopFrame> frame, |
279 int64 sequence_number) { | 314 int64 sequence_number) { |
280 DCHECK(encode_task_runner_->BelongsToCurrentThread()); | 315 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
281 | 316 DCHECK(!frame->updated_region().is_empty()); |
282 // If there is nothing to encode then send an empty keep-alive packet. | |
283 if (!frame || frame->updated_region().is_empty()) { | |
284 scoped_ptr<VideoPacket> packet(new VideoPacket()); | |
285 packet->set_client_sequence_number(sequence_number); | |
286 network_task_runner_->PostTask( | |
287 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, | |
288 base::Passed(&packet))); | |
289 capture_task_runner_->DeleteSoon(FROM_HERE, frame.release()); | |
290 return; | |
291 } | |
292 | 317 |
293 scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame); | 318 scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame); |
294 packet->set_client_sequence_number(sequence_number); | 319 packet->set_client_sequence_number(sequence_number); |
295 | 320 |
296 // Destroy the frame before sending |packet| because SendVideoPacket() may | 321 // Destroy the frame before sending |packet| because SendVideoPacket() may |
297 // trigger another frame to be captured, and the screen capturer expects the | 322 // trigger another frame to be captured, and the screen capturer expects the |
298 // old frame to be freed by then. | 323 // old frame to be freed by then. |
299 frame.reset(); | 324 frame.reset(); |
300 | 325 |
301 scheduler_.RecordEncodeTime( | 326 scheduler_.RecordEncodeTime( |
302 base::TimeDelta::FromMilliseconds(packet->encode_time_ms())); | 327 base::TimeDelta::FromMilliseconds(packet->encode_time_ms())); |
303 network_task_runner_->PostTask( | 328 network_task_runner_->PostTask( |
304 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, | 329 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, |
305 base::Passed(&packet))); | 330 base::Passed(&packet))); |
306 } | 331 } |
307 | 332 |
308 } // namespace remoting | 333 } // namespace remoting |
OLD | NEW |