| 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 |