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

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

Issue 13983010: Use webrtc::DesktopCapturer for screen capturer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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') | remoting/host/video_scheduler_unittest.cc » ('j') | 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"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop_proxy.h" 13 #include "base/message_loop_proxy.h"
14 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "base/sys_info.h" 15 #include "base/sys_info.h"
16 #include "base/time.h" 16 #include "base/time.h"
17 #include "media/video/capture/screen/mouse_cursor_shape.h" 17 #include "media/video/capture/screen/mouse_cursor_shape.h"
18 #include "media/video/capture/screen/screen_capture_data.h"
19 #include "media/video/capture/screen/screen_capturer.h" 18 #include "media/video/capture/screen/screen_capturer.h"
20 #include "remoting/proto/control.pb.h" 19 #include "remoting/proto/control.pb.h"
21 #include "remoting/proto/internal.pb.h" 20 #include "remoting/proto/internal.pb.h"
22 #include "remoting/proto/video.pb.h" 21 #include "remoting/proto/video.pb.h"
23 #include "remoting/protocol/cursor_shape_stub.h" 22 #include "remoting/protocol/cursor_shape_stub.h"
24 #include "remoting/protocol/message_decoder.h" 23 #include "remoting/protocol/message_decoder.h"
25 #include "remoting/protocol/video_stub.h" 24 #include "remoting/protocol/video_stub.h"
26 #include "remoting/protocol/util.h" 25 #include "remoting/protocol/util.h"
26 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
27 27
28 namespace remoting { 28 namespace remoting {
29 29
30 // Maximum number of frames that can be processed simultaneously. 30 // Maximum number of frames that can be processed simultaneously.
31 // TODO(hclam): Move this value to CaptureScheduler. 31 // TODO(hclam): Move this value to CaptureScheduler.
32 static const int kMaxPendingCaptures = 2; 32 static const int kMaxPendingFrames = 2;
33 33
34 VideoScheduler::VideoScheduler( 34 VideoScheduler::VideoScheduler(
35 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, 35 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner,
36 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, 36 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
37 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, 37 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
38 scoped_ptr<media::ScreenCapturer> capturer, 38 scoped_ptr<media::ScreenCapturer> capturer,
39 scoped_ptr<VideoEncoder> encoder, 39 scoped_ptr<VideoEncoder> encoder,
40 protocol::CursorShapeStub* cursor_stub, 40 protocol::CursorShapeStub* cursor_stub,
41 protocol::VideoStub* video_stub) 41 protocol::VideoStub* video_stub)
42 : capture_task_runner_(capture_task_runner), 42 : capture_task_runner_(capture_task_runner),
43 encode_task_runner_(encode_task_runner), 43 encode_task_runner_(encode_task_runner),
44 network_task_runner_(network_task_runner), 44 network_task_runner_(network_task_runner),
45 capturer_(capturer.Pass()), 45 capturer_(capturer.Pass()),
46 encoder_(encoder.Pass()), 46 encoder_(encoder.Pass()),
47 cursor_stub_(cursor_stub), 47 cursor_stub_(cursor_stub),
48 video_stub_(video_stub), 48 video_stub_(video_stub),
49 pending_captures_(0), 49 pending_frames_(0),
50 capture_pending_(false),
50 did_skip_frame_(false), 51 did_skip_frame_(false),
51 is_paused_(false), 52 is_paused_(false),
52 sequence_number_(0) { 53 sequence_number_(0) {
53 DCHECK(network_task_runner_->BelongsToCurrentThread()); 54 DCHECK(network_task_runner_->BelongsToCurrentThread());
54 DCHECK(capturer_); 55 DCHECK(capturer_);
55 DCHECK(encoder_); 56 DCHECK(encoder_);
56 DCHECK(cursor_stub_); 57 DCHECK(cursor_stub_);
57 DCHECK(video_stub_); 58 DCHECK(video_stub_);
58 } 59 }
59 60
60 // Public methods -------------------------------------------------------------- 61 // Public methods --------------------------------------------------------------
61 62
62 void VideoScheduler::OnCaptureCompleted( 63 webrtc::SharedMemory* VideoScheduler::CreateSharedMemory(size_t size) {
63 scoped_refptr<media::ScreenCaptureData> capture_data) { 64 return NULL;
65 }
66
67 void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
64 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 68 DCHECK(capture_task_runner_->BelongsToCurrentThread());
65 69
66 // Do nothing if the scheduler is being stopped. 70 capture_pending_ = false;
67 if (!capturer_)
68 return;
69 71
70 if (capture_data) { 72 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
73
74 if (frame) {
71 scheduler_.RecordCaptureTime( 75 scheduler_.RecordCaptureTime(
72 base::TimeDelta::FromMilliseconds(capture_data->capture_time_ms())); 76 base::TimeDelta::FromMilliseconds(frame->capture_time_ms()));
73
74 // The best way to get this value is by binding the sequence number to
75 // the callback when calling CaptureInvalidRects(). However the callback
76 // system doesn't allow this. Reading from the member variable is
77 // accurate as long as capture is synchronous as the following statement
78 // will obtain the most recent sequence number received.
79 capture_data->set_client_sequence_number(sequence_number_);
80 } 77 }
81 78
82 encode_task_runner_->PostTask( 79 encode_task_runner_->PostTask(
83 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data)); 80 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this,
81 base::Passed(&owned_frame), sequence_number_));
82
83 // If a frame was skipped, try to capture it again.
84 if (did_skip_frame_) {
85 capture_task_runner_->PostTask(
86 FROM_HERE, base::Bind(&VideoScheduler::CaptureNextFrame, this));
87 }
84 } 88 }
85 89
86 void VideoScheduler::OnCursorShapeChanged( 90 void VideoScheduler::OnCursorShapeChanged(
87 scoped_ptr<media::MouseCursorShape> cursor_shape) { 91 scoped_ptr<media::MouseCursorShape> cursor_shape) {
88 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 92 DCHECK(capture_task_runner_->BelongsToCurrentThread());
89 93
90 // Do nothing if the scheduler is being stopped. 94 // Do nothing if the scheduler is being stopped.
91 if (!capturer_) 95 if (!capturer_)
92 return; 96 return;
93 97
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 VideoScheduler::~VideoScheduler() { 160 VideoScheduler::~VideoScheduler() {
157 } 161 }
158 162
159 // Capturer thread ------------------------------------------------------------- 163 // Capturer thread -------------------------------------------------------------
160 164
161 void VideoScheduler::StartOnCaptureThread() { 165 void VideoScheduler::StartOnCaptureThread() {
162 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 166 DCHECK(capture_task_runner_->BelongsToCurrentThread());
163 DCHECK(!capture_timer_); 167 DCHECK(!capture_timer_);
164 168
165 // Start the capturer and let it notify us if cursor shape changes. 169 // Start the capturer and let it notify us if cursor shape changes.
170 capturer_->SetMouseShapeObserver(this);
166 capturer_->Start(this); 171 capturer_->Start(this);
167 172
168 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); 173 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>());
169 174
170 // Capture first frame immedately. 175 // Capture first frame immedately.
171 CaptureNextFrame(); 176 CaptureNextFrame();
172 } 177 }
173 178
174 void VideoScheduler::StopOnCaptureThread() { 179 void VideoScheduler::StopOnCaptureThread() {
175 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 180 DCHECK(capture_task_runner_->BelongsToCurrentThread());
176 181
182 // This doesn't deleted already captured frames, so encoder can keep using the
183 // frames that were captured previously.
184 capturer_.reset();
185
177 // |capture_timer_| must be destroyed on the thread on which it is used. 186 // |capture_timer_| must be destroyed on the thread on which it is used.
178 capture_timer_.reset(); 187 capture_timer_.reset();
179
180 // Schedule deletion of |capturer_| once the encode thread is no longer
181 // processing capture data. See http://crbug.com/163641. This also clears
182 // |capturer_| pointer to prevent pending tasks from using it.
183 // TODO(wez): Make it safe to tear down capturer while buffers remain, and
184 // remove this work-around.
185 encode_task_runner_->PostTask(
186 FROM_HERE, base::Bind(&VideoScheduler::StopOnEncodeThread, this,
187 base::Passed(&capturer_)));
188 } 188 }
189 189
190 void VideoScheduler::ScheduleNextCapture() { 190 void VideoScheduler::ScheduleNextCapture() {
191 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 191 DCHECK(capture_task_runner_->BelongsToCurrentThread());
192 192
193 capture_timer_->Start(FROM_HERE, 193 capture_timer_->Start(FROM_HERE,
194 scheduler_.NextCaptureDelay(), 194 scheduler_.NextCaptureDelay(),
195 this, 195 this,
196 &VideoScheduler::CaptureNextFrame); 196 &VideoScheduler::CaptureNextFrame);
197 } 197 }
198 198
199 void VideoScheduler::CaptureNextFrame() { 199 void VideoScheduler::CaptureNextFrame() {
200 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 200 DCHECK(capture_task_runner_->BelongsToCurrentThread());
201 201
202 // If we are stopping (|capturer_| is NULL), or paused, then don't capture. 202 // If we are stopping (|capturer_| is NULL), or paused, then don't capture.
203 if (!capturer_ || is_paused_) 203 if (!capturer_ || is_paused_)
204 return; 204 return;
205 205
206 // Make sure we have at most two oustanding recordings. We can simply return 206 // Make sure we have at most two outstanding recordings. We can simply return
207 // if we can't make a capture now, the next capture will be started by the 207 // if we can't make a capture now, the next capture will be started by the
208 // end of an encode operation. 208 // end of an encode operation.
209 if (pending_captures_ >= kMaxPendingCaptures) { 209 if (pending_frames_ >= kMaxPendingFrames || capture_pending_) {
210 did_skip_frame_ = true; 210 did_skip_frame_ = true;
211 return; 211 return;
212 } 212 }
213 213
214 did_skip_frame_ = false; 214 did_skip_frame_ = false;
215 215
216 // At this point we are going to perform one capture so save the current time. 216 // At this point we are going to perform one capture so save the current time.
217 pending_captures_++; 217 pending_frames_++;
218 DCHECK_LE(pending_captures_, kMaxPendingCaptures); 218 DCHECK_LE(pending_frames_, kMaxPendingFrames);
219 219
220 // Before doing a capture schedule for the next one. 220 // Before doing a capture schedule for the next one.
221 ScheduleNextCapture(); 221 ScheduleNextCapture();
222 222
223 capture_pending_ = true;
224
223 // And finally perform one capture. 225 // And finally perform one capture.
224 capturer_->CaptureFrame(); 226 capturer_->Capture(webrtc::DesktopRegion());
225 } 227 }
226 228
227 void VideoScheduler::FrameCaptureCompleted() { 229 void VideoScheduler::FrameCaptureCompleted() {
228 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 230 DCHECK(capture_task_runner_->BelongsToCurrentThread());
229 231
230 // Decrement the pending capture count. 232 // Decrement the pending capture count.
231 pending_captures_--; 233 pending_frames_--;
232 DCHECK_GE(pending_captures_, 0); 234 DCHECK_GE(pending_frames_, 0);
233 235
234 // If we've skipped a frame capture because too we had too many captures 236 // If we've skipped a frame capture because too we had too many captures
235 // pending then schedule one now. 237 // pending then schedule one now.
236 if (did_skip_frame_) 238 if (did_skip_frame_)
237 CaptureNextFrame(); 239 CaptureNextFrame();
238 } 240 }
239 241
240 // Network thread -------------------------------------------------------------- 242 // Network thread --------------------------------------------------------------
241 243
242 void VideoScheduler::SendVideoPacket(scoped_ptr<VideoPacket> packet) { 244 void VideoScheduler::SendVideoPacket(scoped_ptr<VideoPacket> packet) {
(...skipping 25 matching lines...) Expand all
268 270
269 if (!cursor_stub_) 271 if (!cursor_stub_)
270 return; 272 return;
271 273
272 cursor_stub_->SetCursorShape(*cursor_shape); 274 cursor_stub_->SetCursorShape(*cursor_shape);
273 } 275 }
274 276
275 // Encoder thread -------------------------------------------------------------- 277 // Encoder thread --------------------------------------------------------------
276 278
277 void VideoScheduler::EncodeFrame( 279 void VideoScheduler::EncodeFrame(
278 scoped_refptr<media::ScreenCaptureData> capture_data) { 280 scoped_ptr<webrtc::DesktopFrame> frame,
281 int sequence_number) {
279 DCHECK(encode_task_runner_->BelongsToCurrentThread()); 282 DCHECK(encode_task_runner_->BelongsToCurrentThread());
280 283
281 // If there is nothing to encode then send an empty keep-alive packet. 284 // If there is nothing to encode then send an empty keep-alive packet.
282 if (!capture_data || capture_data->dirty_region().isEmpty()) { 285 if (!frame || frame->updated_region().is_empty()) {
283 scoped_ptr<VideoPacket> packet(new VideoPacket()); 286 scoped_ptr<VideoPacket> packet(new VideoPacket());
284 packet->set_flags(VideoPacket::LAST_PARTITION); 287 packet->set_flags(VideoPacket::LAST_PARTITION);
288 packet->set_sequence_number(sequence_number);
285 network_task_runner_->PostTask( 289 network_task_runner_->PostTask(
286 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, 290 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this,
287 base::Passed(&packet))); 291 base::Passed(&packet)));
292 capture_task_runner_->DeleteSoon(FROM_HERE, frame.release());
288 return; 293 return;
289 } 294 }
290 295
291 encoder_->Encode( 296 encoder_->Encode(
292 capture_data, false, 297 frame.get(), base::Bind(&VideoScheduler::EncodedDataAvailableCallback,
293 base::Bind(&VideoScheduler::EncodedDataAvailableCallback, this)); 298 this, sequence_number));
299 capture_task_runner_->DeleteSoon(FROM_HERE, frame.release());
294 } 300 }
295 301
296 void VideoScheduler::EncodedDataAvailableCallback( 302 void VideoScheduler::EncodedDataAvailableCallback(
303 int sequence_number,
297 scoped_ptr<VideoPacket> packet) { 304 scoped_ptr<VideoPacket> packet) {
298 DCHECK(encode_task_runner_->BelongsToCurrentThread()); 305 DCHECK(encode_task_runner_->BelongsToCurrentThread());
299 306
307 packet->set_sequence_number(sequence_number);
308
300 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0; 309 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
301 if (last) { 310 if (last) {
302 scheduler_.RecordEncodeTime( 311 scheduler_.RecordEncodeTime(
303 base::TimeDelta::FromMilliseconds(packet->encode_time_ms())); 312 base::TimeDelta::FromMilliseconds(packet->encode_time_ms()));
304 } 313 }
305 314
306 network_task_runner_->PostTask( 315 network_task_runner_->PostTask(
307 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, 316 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this,
308 base::Passed(&packet))); 317 base::Passed(&packet)));
309 } 318 }
310 319
311 void VideoScheduler::StopOnEncodeThread(
312 scoped_ptr<media::ScreenCapturer> capturer) {
313 DCHECK(encode_task_runner_->BelongsToCurrentThread());
314
315 // This is posted by StopOnCaptureThread, so we know that by the time we
316 // process it there are no more encode tasks queued. Pass |capturer| for
317 // deletion on the capture thread.
318 capture_task_runner_->DeleteSoon(FROM_HERE, capturer.release());
319 }
320
321 } // namespace remoting 320 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/video_scheduler.h ('k') | remoting/host/video_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698