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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 | 54 |
55 return scheduler; | 55 return scheduler; |
56 } | 56 } |
57 | 57 |
58 // Public methods -------------------------------------------------------------- | 58 // Public methods -------------------------------------------------------------- |
59 | 59 |
60 void VideoScheduler::OnCaptureCompleted( | 60 void VideoScheduler::OnCaptureCompleted( |
61 scoped_refptr<media::ScreenCaptureData> capture_data) { | 61 scoped_refptr<media::ScreenCaptureData> capture_data) { |
62 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 62 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
63 | 63 |
| 64 // Do nothing if the scheduler is being stopped. |
| 65 if (!capturer_) |
| 66 return; |
| 67 |
64 if (capture_data) { | 68 if (capture_data) { |
65 scheduler_.RecordCaptureTime( | 69 scheduler_.RecordCaptureTime( |
66 base::TimeDelta::FromMilliseconds(capture_data->capture_time_ms())); | 70 base::TimeDelta::FromMilliseconds(capture_data->capture_time_ms())); |
67 | 71 |
68 // The best way to get this value is by binding the sequence number to | 72 // The best way to get this value is by binding the sequence number to |
69 // the callback when calling CaptureInvalidRects(). However the callback | 73 // the callback when calling CaptureInvalidRects(). However the callback |
70 // system doesn't allow this. Reading from the member variable is | 74 // system doesn't allow this. Reading from the member variable is |
71 // accurate as long as capture is synchronous as the following statement | 75 // accurate as long as capture is synchronous as the following statement |
72 // will obtain the most recent sequence number received. | 76 // will obtain the most recent sequence number received. |
73 capture_data->set_client_sequence_number(sequence_number_); | 77 capture_data->set_client_sequence_number(sequence_number_); |
74 } | 78 } |
75 | 79 |
76 encode_task_runner_->PostTask( | 80 encode_task_runner_->PostTask( |
77 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data)); | 81 FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data)); |
78 } | 82 } |
79 | 83 |
80 void VideoScheduler::OnCursorShapeChanged( | 84 void VideoScheduler::OnCursorShapeChanged( |
81 scoped_ptr<media::MouseCursorShape> cursor_shape) { | 85 scoped_ptr<media::MouseCursorShape> cursor_shape) { |
82 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 86 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
83 | 87 |
| 88 // Do nothing if the scheduler is being stopped. |
| 89 if (!capturer_) |
| 90 return; |
| 91 |
84 scoped_ptr<protocol::CursorShapeInfo> cursor_proto( | 92 scoped_ptr<protocol::CursorShapeInfo> cursor_proto( |
85 new protocol::CursorShapeInfo()); | 93 new protocol::CursorShapeInfo()); |
86 cursor_proto->set_width(cursor_shape->size.width()); | 94 cursor_proto->set_width(cursor_shape->size.width()); |
87 cursor_proto->set_height(cursor_shape->size.height()); | 95 cursor_proto->set_height(cursor_shape->size.height()); |
88 cursor_proto->set_hotspot_x(cursor_shape->hotspot.x()); | 96 cursor_proto->set_hotspot_x(cursor_shape->hotspot.x()); |
89 cursor_proto->set_hotspot_y(cursor_shape->hotspot.y()); | 97 cursor_proto->set_hotspot_y(cursor_shape->hotspot.y()); |
90 cursor_proto->set_data(cursor_shape->data); | 98 cursor_proto->set_data(cursor_shape->data); |
91 | 99 |
92 network_task_runner_->PostTask( | 100 network_task_runner_->PostTask( |
93 FROM_HERE, base::Bind(&VideoScheduler::SendCursorShape, this, | 101 FROM_HERE, base::Bind(&VideoScheduler::SendCursorShape, this, |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 | 178 |
171 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); | 179 capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); |
172 | 180 |
173 // Capture first frame immedately. | 181 // Capture first frame immedately. |
174 CaptureNextFrame(); | 182 CaptureNextFrame(); |
175 } | 183 } |
176 | 184 |
177 void VideoScheduler::StopOnCaptureThread() { | 185 void VideoScheduler::StopOnCaptureThread() { |
178 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | 186 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
179 | 187 |
180 // Stop |capturer_| and clear it to prevent pending tasks from using it. | |
181 capturer_->Stop(); | |
182 | |
183 // |capture_timer_| must be destroyed on the thread on which it is used. | 188 // |capture_timer_| must be destroyed on the thread on which it is used. |
184 capture_timer_.reset(); | 189 capture_timer_.reset(); |
185 | 190 |
186 // Schedule deletion of |capturer_| once the encode thread is no longer | 191 // Schedule deletion of |capturer_| once the encode thread is no longer |
187 // processing capture data. See http://crbug.com/163641. This also clears | 192 // processing capture data. See http://crbug.com/163641. This also clears |
188 // |capturer_| pointer to prevent pending tasks from using it. | 193 // |capturer_| pointer to prevent pending tasks from using it. |
189 // TODO(wez): Make it safe to tear down capturer while buffers remain, and | 194 // TODO(wez): Make it safe to tear down capturer while buffers remain, and |
190 // remove this work-around. | 195 // remove this work-around. |
191 encode_task_runner_->PostTask( | 196 encode_task_runner_->PostTask( |
192 FROM_HERE, base::Bind(&VideoScheduler::StopOnEncodeThread, this, | 197 FROM_HERE, base::Bind(&VideoScheduler::StopOnEncodeThread, this, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 void VideoScheduler::SendCursorShape( | 276 void VideoScheduler::SendCursorShape( |
272 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { | 277 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { |
273 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 278 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
274 | 279 |
275 if (!cursor_stub_) | 280 if (!cursor_stub_) |
276 return; | 281 return; |
277 | 282 |
278 cursor_stub_->SetCursorShape(*cursor_shape); | 283 cursor_stub_->SetCursorShape(*cursor_shape); |
279 } | 284 } |
280 | 285 |
281 void VideoScheduler::StopOnNetworkThread( | |
282 scoped_ptr<media::ScreenCapturer> capturer) { | |
283 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
284 | |
285 // This is posted by StopOnEncodeThread meaning that both capture and encode | |
286 // threads are stopped now and it is safe to delete |capturer|. | |
287 } | |
288 | |
289 // Encoder thread -------------------------------------------------------------- | 286 // Encoder thread -------------------------------------------------------------- |
290 | 287 |
291 void VideoScheduler::EncodeFrame( | 288 void VideoScheduler::EncodeFrame( |
292 scoped_refptr<media::ScreenCaptureData> capture_data) { | 289 scoped_refptr<media::ScreenCaptureData> capture_data) { |
293 DCHECK(encode_task_runner_->BelongsToCurrentThread()); | 290 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
294 | 291 |
295 // If there is nothing to encode then send an empty keep-alive packet. | 292 // If there is nothing to encode then send an empty keep-alive packet. |
296 if (!capture_data || capture_data->dirty_region().isEmpty()) { | 293 if (!capture_data || capture_data->dirty_region().isEmpty()) { |
297 scoped_ptr<VideoPacket> packet(new VideoPacket()); | 294 scoped_ptr<VideoPacket> packet(new VideoPacket()); |
298 packet->set_flags(VideoPacket::LAST_PARTITION); | 295 packet->set_flags(VideoPacket::LAST_PARTITION); |
(...skipping 21 matching lines...) Expand all Loading... |
320 network_task_runner_->PostTask( | 317 network_task_runner_->PostTask( |
321 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, | 318 FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, |
322 base::Passed(&packet))); | 319 base::Passed(&packet))); |
323 } | 320 } |
324 | 321 |
325 void VideoScheduler::StopOnEncodeThread( | 322 void VideoScheduler::StopOnEncodeThread( |
326 scoped_ptr<media::ScreenCapturer> capturer) { | 323 scoped_ptr<media::ScreenCapturer> capturer) { |
327 DCHECK(encode_task_runner_->BelongsToCurrentThread()); | 324 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
328 | 325 |
329 // This is posted by StopOnCaptureThread, so we know that by the time we | 326 // This is posted by StopOnCaptureThread, so we know that by the time we |
330 // process it there are no more encode tasks queued. Pass |capturer_| for | 327 // process it there are no more encode tasks queued. Pass |capturer| for |
331 // deletion on the thread that created it. | 328 // deletion on the capture thread. |
332 network_task_runner_->PostTask( | 329 capture_task_runner_->DeleteSoon(FROM_HERE, capturer.release()); |
333 FROM_HERE, base::Bind(&VideoScheduler::StopOnNetworkThread, this, | |
334 base::Passed(&capturer))); | |
335 } | 330 } |
336 | 331 |
337 } // namespace remoting | 332 } // namespace remoting |
OLD | NEW |