Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(762)

Side by Side Diff: remoting/host/video_scheduler.cc

Issue 292373002: More reliable keep-alive video packets. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/video_scheduler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « remoting/host/video_scheduler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698