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

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
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 kMaxPendingCaptures = 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,
(...skipping 15 matching lines...) Expand all
52 sequence_number_(0) { 52 sequence_number_(0) {
53 DCHECK(network_task_runner_->BelongsToCurrentThread()); 53 DCHECK(network_task_runner_->BelongsToCurrentThread());
54 DCHECK(capturer_); 54 DCHECK(capturer_);
55 DCHECK(encoder_); 55 DCHECK(encoder_);
56 DCHECK(cursor_stub_); 56 DCHECK(cursor_stub_);
57 DCHECK(video_stub_); 57 DCHECK(video_stub_);
58 } 58 }
59 59
60 // Public methods -------------------------------------------------------------- 60 // Public methods --------------------------------------------------------------
61 61
62 void VideoScheduler::OnCaptureCompleted( 62 webrtc::SharedMemory* VideoScheduler::CreateSharedMemory(size_t size) {
63 scoped_refptr<media::ScreenCaptureData> capture_data) { 63 return NULL;
64 }
65
66 void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
64 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 67 DCHECK(capture_task_runner_->BelongsToCurrentThread());
65 68
66 // Do nothing if the scheduler is being stopped. 69 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
67 if (!capturer_)
68 return;
69 70
70 if (capture_data) { 71 if (frame) {
71 scheduler_.RecordCaptureTime( 72 scheduler_.RecordCaptureTime(
72 base::TimeDelta::FromMilliseconds(capture_data->capture_time_ms())); 73 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 } 74 }
81 75
82 encode_task_runner_->PostTask( 76 encode_task_runner_->PostTask(
83 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data)); 77 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this,
78 base::Passed(&owned_frame), sequence_number_));
84 } 79 }
85 80
86 void VideoScheduler::OnCursorShapeChanged( 81 void VideoScheduler::OnCursorShapeChanged(
87 scoped_ptr<media::MouseCursorShape> cursor_shape) { 82 scoped_ptr<media::MouseCursorShape> cursor_shape) {
88 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 83 DCHECK(capture_task_runner_->BelongsToCurrentThread());
89 84
90 // Do nothing if the scheduler is being stopped. 85 // Do nothing if the scheduler is being stopped.
91 if (!capturer_) 86 if (!capturer_)
92 return; 87 return;
93 88
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 VideoScheduler::~VideoScheduler() { 151 VideoScheduler::~VideoScheduler() {
157 } 152 }
158 153
159 // Capturer thread ------------------------------------------------------------- 154 // Capturer thread -------------------------------------------------------------
160 155
161 void VideoScheduler::StartOnCaptureThread() { 156 void VideoScheduler::StartOnCaptureThread() {
162 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 157 DCHECK(capture_task_runner_->BelongsToCurrentThread());
163 DCHECK(!capture_timer_); 158 DCHECK(!capture_timer_);
164 159
165 // Start the capturer and let it notify us if cursor shape changes. 160 // Start the capturer and let it notify us if cursor shape changes.
161 capturer_->SetMouseShapeObserver(this);
166 capturer_->Start(this); 162 capturer_->Start(this);
167 163
168 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); 164 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>());
169 165
170 // Capture first frame immedately. 166 // Capture first frame immedately.
171 CaptureNextFrame(); 167 CaptureNextFrame();
172 } 168 }
173 169
174 void VideoScheduler::StopOnCaptureThread() { 170 void VideoScheduler::StopOnCaptureThread() {
175 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 171 DCHECK(capture_task_runner_->BelongsToCurrentThread());
176 172
173 // This doesn't deleted already captured frames, so encoder can keep using the
174 // frames that were captured previously.
175 capturer_.reset();
176
177 // |capture_timer_| must be destroyed on the thread on which it is used. 177 // |capture_timer_| must be destroyed on the thread on which it is used.
178 capture_timer_.reset(); 178 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 } 179 }
189 180
190 void VideoScheduler::ScheduleNextCapture() { 181 void VideoScheduler::ScheduleNextCapture() {
191 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 182 DCHECK(capture_task_runner_->BelongsToCurrentThread());
192 183
193 capture_timer_->Start(FROM_HERE, 184 capture_timer_->Start(FROM_HERE,
194 scheduler_.NextCaptureDelay(), 185 scheduler_.NextCaptureDelay(),
195 this, 186 this,
196 &VideoScheduler::CaptureNextFrame); 187 &VideoScheduler::CaptureNextFrame);
197 } 188 }
(...skipping 16 matching lines...) Expand all
214 did_skip_frame_ = false; 205 did_skip_frame_ = false;
215 206
216 // At this point we are going to perform one capture so save the current time. 207 // At this point we are going to perform one capture so save the current time.
217 pending_captures_++; 208 pending_captures_++;
218 DCHECK_LE(pending_captures_, kMaxPendingCaptures); 209 DCHECK_LE(pending_captures_, kMaxPendingCaptures);
219 210
220 // Before doing a capture schedule for the next one. 211 // Before doing a capture schedule for the next one.
221 ScheduleNextCapture(); 212 ScheduleNextCapture();
222 213
223 // And finally perform one capture. 214 // And finally perform one capture.
224 capturer_->CaptureFrame(); 215 capturer_->Capture(webrtc::DesktopRegion());
225 } 216 }
226 217
227 void VideoScheduler::FrameCaptureCompleted() { 218 void VideoScheduler::FrameCaptureCompleted() {
228 DCHECK(capture_task_runner_->BelongsToCurrentThread()); 219 DCHECK(capture_task_runner_->BelongsToCurrentThread());
229 220
230 // Decrement the pending capture count. 221 // Decrement the pending capture count.
231 pending_captures_--; 222 pending_captures_--;
232 DCHECK_GE(pending_captures_, 0); 223 DCHECK_GE(pending_captures_, 0);
233 224
234 // If we've skipped a frame capture because too we had too many captures 225 // If we've skipped a frame capture because too we had too many captures
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 259
269 if (!cursor_stub_) 260 if (!cursor_stub_)
270 return; 261 return;
271 262
272 cursor_stub_->SetCursorShape(*cursor_shape); 263 cursor_stub_->SetCursorShape(*cursor_shape);
273 } 264 }
274 265
275 // Encoder thread -------------------------------------------------------------- 266 // Encoder thread --------------------------------------------------------------
276 267
277 void VideoScheduler::EncodeFrame( 268 void VideoScheduler::EncodeFrame(
278 scoped_refptr<media::ScreenCaptureData> capture_data) { 269 scoped_ptr<webrtc::DesktopFrame> frame,
270 int sequence_number) {
279 DCHECK(encode_task_runner_->BelongsToCurrentThread()); 271 DCHECK(encode_task_runner_->BelongsToCurrentThread());
280 272
281 // If there is nothing to encode then send an empty keep-alive packet. 273 // If there is nothing to encode then send an empty keep-alive packet.
282 if (!capture_data || capture_data->dirty_region().isEmpty()) { 274 if (!frame || frame->updated_region().is_empty()) {
283 scoped_ptr<VideoPacket> packet(new VideoPacket()); 275 scoped_ptr<VideoPacket> packet(new VideoPacket());
284 packet->set_flags(VideoPacket::LAST_PARTITION); 276 packet->set_flags(VideoPacket::LAST_PARTITION);
277 packet->set_sequence_number(sequence_number);
285 network_task_runner_->PostTask( 278 network_task_runner_->PostTask(
286 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, 279 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this,
287 base::Passed(&packet))); 280 base::Passed(&packet)));
281 capture_task_runner_->DeleteSoon(FROM_HERE, frame.release());
288 return; 282 return;
289 } 283 }
290 284
291 encoder_->Encode( 285 encoder_->Encode(
292 capture_data, false, 286 frame.get(), base::Bind(&VideoScheduler::EncodedDataAvailableCallback,
293 base::Bind(&VideoScheduler::EncodedDataAvailableCallback, this)); 287 this, sequence_number));
288 capture_task_runner_->DeleteSoon(FROM_HERE, frame.release());
294 } 289 }
295 290
296 void VideoScheduler::EncodedDataAvailableCallback( 291 void VideoScheduler::EncodedDataAvailableCallback(
292 int sequence_number,
297 scoped_ptr<VideoPacket> packet) { 293 scoped_ptr<VideoPacket> packet) {
298 DCHECK(encode_task_runner_->BelongsToCurrentThread()); 294 DCHECK(encode_task_runner_->BelongsToCurrentThread());
299 295
296 packet->set_sequence_number(sequence_number);
297
300 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0; 298 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
301 if (last) { 299 if (last) {
302 scheduler_.RecordEncodeTime( 300 scheduler_.RecordEncodeTime(
303 base::TimeDelta::FromMilliseconds(packet->encode_time_ms())); 301 base::TimeDelta::FromMilliseconds(packet->encode_time_ms()));
304 } 302 }
305 303
306 network_task_runner_->PostTask( 304 network_task_runner_->PostTask(
307 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, 305 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this,
308 base::Passed(&packet))); 306 base::Passed(&packet)));
309 } 307 }
310 308
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 309 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698