| 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/screen_recorder.h" | 5 #include "remoting/host/screen_recorder.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 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 using remoting::protocol::ConnectionToClient; | 26 using remoting::protocol::ConnectionToClient; |
| 27 | 27 |
| 28 namespace remoting { | 28 namespace remoting { |
| 29 | 29 |
| 30 // Maximum number of frames that can be processed similtaneously. | 30 // Maximum number of frames that can be processed similtaneously. |
| 31 // TODO(hclam): Move this value to CaptureScheduler. | 31 // TODO(hclam): Move this value to CaptureScheduler. |
| 32 static const int kMaxRecordings = 2; | 32 static const int kMaxRecordings = 2; |
| 33 | 33 |
| 34 ScreenRecorder::ScreenRecorder( | 34 ScreenRecorder::ScreenRecorder( |
| 35 MessageLoop* capture_loop, | 35 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, |
| 36 MessageLoop* encode_loop, | 36 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, |
| 37 base::MessageLoopProxy* network_loop, | 37 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, |
| 38 Capturer* capturer, | 38 Capturer* capturer, |
| 39 Encoder* encoder) | 39 Encoder* encoder) |
| 40 : capture_loop_(capture_loop), | 40 : capture_task_runner_(capture_task_runner), |
| 41 encode_loop_(encode_loop), | 41 encode_task_runner_(encode_task_runner), |
| 42 network_loop_(network_loop), | 42 network_task_runner_(network_task_runner), |
| 43 capturer_(capturer), | 43 capturer_(capturer), |
| 44 encoder_(encoder), | 44 encoder_(encoder), |
| 45 network_stopped_(false), | 45 network_stopped_(false), |
| 46 encoder_stopped_(false), | 46 encoder_stopped_(false), |
| 47 max_recordings_(kMaxRecordings), | 47 max_recordings_(kMaxRecordings), |
| 48 recordings_(0), | 48 recordings_(0), |
| 49 frame_skipped_(false), | 49 frame_skipped_(false), |
| 50 sequence_number_(0) { | 50 sequence_number_(0) { |
| 51 DCHECK(capture_loop_); | 51 DCHECK(capture_task_runner_); |
| 52 DCHECK(encode_loop_); | 52 DCHECK(encode_task_runner_); |
| 53 DCHECK(network_loop_); | 53 DCHECK(network_task_runner_); |
| 54 } | 54 } |
| 55 | 55 |
| 56 // Public methods -------------------------------------------------------------- | 56 // Public methods -------------------------------------------------------------- |
| 57 | 57 |
| 58 void ScreenRecorder::Start() { | 58 void ScreenRecorder::Start() { |
| 59 capture_loop_->PostTask( | 59 capture_task_runner_->PostTask( |
| 60 FROM_HERE, base::Bind(&ScreenRecorder::DoStart, this)); | 60 FROM_HERE, base::Bind(&ScreenRecorder::DoStart, this)); |
| 61 } | 61 } |
| 62 | 62 |
| 63 void ScreenRecorder::Stop(const base::Closure& done_task) { | 63 void ScreenRecorder::Stop(const base::Closure& done_task) { |
| 64 if (MessageLoop::current() != capture_loop_) { | 64 if (!capture_task_runner_->BelongsToCurrentThread()) { |
| 65 capture_loop_->PostTask(FROM_HERE, base::Bind( | 65 capture_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 66 &ScreenRecorder::Stop, this, done_task)); | 66 &ScreenRecorder::Stop, this, done_task)); |
| 67 return; | 67 return; |
| 68 } | 68 } |
| 69 | 69 |
| 70 DCHECK(!done_task.is_null()); | 70 DCHECK(!done_task.is_null()); |
| 71 | 71 |
| 72 capturer()->Stop(); | 72 capturer()->Stop(); |
| 73 capture_timer_.reset(); | 73 capture_timer_.reset(); |
| 74 | 74 |
| 75 network_loop_->PostTask(FROM_HERE, base::Bind( | 75 network_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 76 &ScreenRecorder::DoStopOnNetworkThread, this, done_task)); | 76 &ScreenRecorder::DoStopOnNetworkThread, this, done_task)); |
| 77 } | 77 } |
| 78 | 78 |
| 79 void ScreenRecorder::AddConnection(ConnectionToClient* connection) { | 79 void ScreenRecorder::AddConnection(ConnectionToClient* connection) { |
| 80 DCHECK(network_loop_->BelongsToCurrentThread()); | 80 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 81 connections_.push_back(connection); | 81 connections_.push_back(connection); |
| 82 | 82 |
| 83 capture_loop_->PostTask( | 83 capture_task_runner_->PostTask( |
| 84 FROM_HERE, base::Bind(&ScreenRecorder::DoInvalidateFullScreen, this)); | 84 FROM_HERE, base::Bind(&ScreenRecorder::DoInvalidateFullScreen, this)); |
| 85 } | 85 } |
| 86 | 86 |
| 87 void ScreenRecorder::RemoveConnection(ConnectionToClient* connection) { | 87 void ScreenRecorder::RemoveConnection(ConnectionToClient* connection) { |
| 88 DCHECK(network_loop_->BelongsToCurrentThread()); | 88 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 89 | 89 |
| 90 ConnectionToClientList::iterator it = | 90 ConnectionToClientList::iterator it = |
| 91 std::find(connections_.begin(), connections_.end(), connection); | 91 std::find(connections_.begin(), connections_.end(), connection); |
| 92 if (it != connections_.end()) { | 92 if (it != connections_.end()) { |
| 93 connections_.erase(it); | 93 connections_.erase(it); |
| 94 } | 94 } |
| 95 } | 95 } |
| 96 | 96 |
| 97 void ScreenRecorder::RemoveAllConnections() { | 97 void ScreenRecorder::RemoveAllConnections() { |
| 98 DCHECK(network_loop_->BelongsToCurrentThread()); | 98 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 99 connections_.clear(); | 99 connections_.clear(); |
| 100 } | 100 } |
| 101 | 101 |
| 102 void ScreenRecorder::UpdateSequenceNumber(int64 sequence_number) { | 102 void ScreenRecorder::UpdateSequenceNumber(int64 sequence_number) { |
| 103 // Sequence number is used and written only on the capture thread. | 103 // Sequence number is used and written only on the capture thread. |
| 104 if (MessageLoop::current() != capture_loop_) { | 104 if (!capture_task_runner_->BelongsToCurrentThread()) { |
| 105 capture_loop_->PostTask( | 105 capture_task_runner_->PostTask( |
| 106 FROM_HERE, base::Bind(&ScreenRecorder::UpdateSequenceNumber, | 106 FROM_HERE, base::Bind(&ScreenRecorder::UpdateSequenceNumber, |
| 107 this, sequence_number)); | 107 this, sequence_number)); |
| 108 return; | 108 return; |
| 109 } | 109 } |
| 110 | 110 |
| 111 sequence_number_ = sequence_number; | 111 sequence_number_ = sequence_number; |
| 112 } | 112 } |
| 113 | 113 |
| 114 // Private methods ----------------------------------------------------------- | 114 // Private methods ----------------------------------------------------------- |
| 115 | 115 |
| 116 ScreenRecorder::~ScreenRecorder() { | 116 ScreenRecorder::~ScreenRecorder() { |
| 117 } | 117 } |
| 118 | 118 |
| 119 Capturer* ScreenRecorder::capturer() { | 119 Capturer* ScreenRecorder::capturer() { |
| 120 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 120 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 121 DCHECK(capturer_); | 121 DCHECK(capturer_); |
| 122 return capturer_; | 122 return capturer_; |
| 123 } | 123 } |
| 124 | 124 |
| 125 Encoder* ScreenRecorder::encoder() { | 125 Encoder* ScreenRecorder::encoder() { |
| 126 DCHECK_EQ(encode_loop_, MessageLoop::current()); | 126 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
| 127 DCHECK(encoder_.get()); | 127 DCHECK(encoder_.get()); |
| 128 return encoder_.get(); | 128 return encoder_.get(); |
| 129 } | 129 } |
| 130 | 130 |
| 131 bool ScreenRecorder::is_recording() { | 131 bool ScreenRecorder::is_recording() { |
| 132 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 132 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 133 return capture_timer_.get() != NULL; | 133 return capture_timer_.get() != NULL; |
| 134 } | 134 } |
| 135 | 135 |
| 136 // Capturer thread ------------------------------------------------------------- | 136 // Capturer thread ------------------------------------------------------------- |
| 137 | 137 |
| 138 void ScreenRecorder::DoStart() { | 138 void ScreenRecorder::DoStart() { |
| 139 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 139 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 140 | 140 |
| 141 if (is_recording()) { | 141 if (is_recording()) { |
| 142 NOTREACHED() << "Record session already started."; | 142 NOTREACHED() << "Record session already started."; |
| 143 return; | 143 return; |
| 144 } | 144 } |
| 145 | 145 |
| 146 capturer()->Start( | 146 capturer()->Start( |
| 147 base::Bind(&ScreenRecorder::CursorShapeChangedCallback, this)); | 147 base::Bind(&ScreenRecorder::CursorShapeChangedCallback, this)); |
| 148 | 148 |
| 149 capture_timer_.reset(new base::OneShotTimer<ScreenRecorder>()); | 149 capture_timer_.reset(new base::OneShotTimer<ScreenRecorder>()); |
| 150 | 150 |
| 151 // Capture first frame immedately. | 151 // Capture first frame immedately. |
| 152 DoCapture(); | 152 DoCapture(); |
| 153 } | 153 } |
| 154 | 154 |
| 155 void ScreenRecorder::StartCaptureTimer() { | 155 void ScreenRecorder::StartCaptureTimer() { |
| 156 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 156 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 157 | 157 |
| 158 capture_timer_->Start(FROM_HERE, | 158 capture_timer_->Start(FROM_HERE, |
| 159 scheduler_.NextCaptureDelay(), | 159 scheduler_.NextCaptureDelay(), |
| 160 this, | 160 this, |
| 161 &ScreenRecorder::DoCapture); | 161 &ScreenRecorder::DoCapture); |
| 162 } | 162 } |
| 163 | 163 |
| 164 void ScreenRecorder::DoCapture() { | 164 void ScreenRecorder::DoCapture() { |
| 165 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 165 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 166 // Make sure we have at most two oustanding recordings. We can simply return | 166 // Make sure we have at most two oustanding recordings. We can simply return |
| 167 // if we can't make a capture now, the next capture will be started by the | 167 // if we can't make a capture now, the next capture will be started by the |
| 168 // end of an encode operation. | 168 // end of an encode operation. |
| 169 if (recordings_ >= max_recordings_ || !is_recording()) { | 169 if (recordings_ >= max_recordings_ || !is_recording()) { |
| 170 frame_skipped_ = true; | 170 frame_skipped_ = true; |
| 171 return; | 171 return; |
| 172 } | 172 } |
| 173 | 173 |
| 174 if (frame_skipped_) | 174 if (frame_skipped_) |
| 175 frame_skipped_ = false; | 175 frame_skipped_ = false; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 186 &ScreenRecorder::DoCapture); | 186 &ScreenRecorder::DoCapture); |
| 187 | 187 |
| 188 // And finally perform one capture. | 188 // And finally perform one capture. |
| 189 capture_start_time_ = base::Time::Now(); | 189 capture_start_time_ = base::Time::Now(); |
| 190 capturer()->CaptureInvalidRegion( | 190 capturer()->CaptureInvalidRegion( |
| 191 base::Bind(&ScreenRecorder::CaptureDoneCallback, this)); | 191 base::Bind(&ScreenRecorder::CaptureDoneCallback, this)); |
| 192 } | 192 } |
| 193 | 193 |
| 194 void ScreenRecorder::CaptureDoneCallback( | 194 void ScreenRecorder::CaptureDoneCallback( |
| 195 scoped_refptr<CaptureData> capture_data) { | 195 scoped_refptr<CaptureData> capture_data) { |
| 196 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 196 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 197 | 197 |
| 198 if (!is_recording()) | 198 if (!is_recording()) |
| 199 return; | 199 return; |
| 200 | 200 |
| 201 if (capture_data) { | 201 if (capture_data) { |
| 202 base::TimeDelta capture_time = base::Time::Now() - capture_start_time_; | 202 base::TimeDelta capture_time = base::Time::Now() - capture_start_time_; |
| 203 int capture_time_ms = | 203 int capture_time_ms = |
| 204 static_cast<int>(capture_time.InMilliseconds()); | 204 static_cast<int>(capture_time.InMilliseconds()); |
| 205 capture_data->set_capture_time_ms(capture_time_ms); | 205 capture_data->set_capture_time_ms(capture_time_ms); |
| 206 scheduler_.RecordCaptureTime(capture_time); | 206 scheduler_.RecordCaptureTime(capture_time); |
| 207 | 207 |
| 208 // The best way to get this value is by binding the sequence number to | 208 // The best way to get this value is by binding the sequence number to |
| 209 // the callback when calling CaptureInvalidRects(). However the callback | 209 // the callback when calling CaptureInvalidRects(). However the callback |
| 210 // system doesn't allow this. Reading from the member variable is | 210 // system doesn't allow this. Reading from the member variable is |
| 211 // accurate as long as capture is synchronous as the following statement | 211 // accurate as long as capture is synchronous as the following statement |
| 212 // will obtain the most recent sequence number received. | 212 // will obtain the most recent sequence number received. |
| 213 capture_data->set_client_sequence_number(sequence_number_); | 213 capture_data->set_client_sequence_number(sequence_number_); |
| 214 } | 214 } |
| 215 | 215 |
| 216 encode_loop_->PostTask( | 216 encode_task_runner_->PostTask( |
| 217 FROM_HERE, base::Bind(&ScreenRecorder::DoEncode, this, capture_data)); | 217 FROM_HERE, base::Bind(&ScreenRecorder::DoEncode, this, capture_data)); |
| 218 } | 218 } |
| 219 | 219 |
| 220 void ScreenRecorder::CursorShapeChangedCallback( | 220 void ScreenRecorder::CursorShapeChangedCallback( |
| 221 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { | 221 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { |
| 222 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 222 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 223 | 223 |
| 224 if (!is_recording()) | 224 if (!is_recording()) |
| 225 return; | 225 return; |
| 226 | 226 |
| 227 network_loop_->PostTask( | 227 network_task_runner_->PostTask( |
| 228 FROM_HERE, base::Bind(&ScreenRecorder::DoSendCursorShape, this, | 228 FROM_HERE, base::Bind(&ScreenRecorder::DoSendCursorShape, this, |
| 229 base::Passed(cursor_shape.Pass()))); | 229 base::Passed(cursor_shape.Pass()))); |
| 230 } | 230 } |
| 231 | 231 |
| 232 void ScreenRecorder::DoFinishOneRecording() { | 232 void ScreenRecorder::DoFinishOneRecording() { |
| 233 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 233 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 234 | 234 |
| 235 if (!is_recording()) | 235 if (!is_recording()) |
| 236 return; | 236 return; |
| 237 | 237 |
| 238 // Decrement the number of recording in process since we have completed | 238 // Decrement the number of recording in process since we have completed |
| 239 // one cycle. | 239 // one cycle. |
| 240 --recordings_; | 240 --recordings_; |
| 241 DCHECK_GE(recordings_, 0); | 241 DCHECK_GE(recordings_, 0); |
| 242 | 242 |
| 243 // Try to do a capture again only if |frame_skipped_| is set to true by | 243 // Try to do a capture again only if |frame_skipped_| is set to true by |
| 244 // capture timer. | 244 // capture timer. |
| 245 if (frame_skipped_) | 245 if (frame_skipped_) |
| 246 DoCapture(); | 246 DoCapture(); |
| 247 } | 247 } |
| 248 | 248 |
| 249 void ScreenRecorder::DoInvalidateFullScreen() { | 249 void ScreenRecorder::DoInvalidateFullScreen() { |
| 250 DCHECK_EQ(capture_loop_, MessageLoop::current()); | 250 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 251 | 251 |
| 252 capturer_->InvalidateFullScreen(); | 252 capturer_->InvalidateFullScreen(); |
| 253 } | 253 } |
| 254 | 254 |
| 255 // Network thread -------------------------------------------------------------- | 255 // Network thread -------------------------------------------------------------- |
| 256 | 256 |
| 257 void ScreenRecorder::DoSendVideoPacket(scoped_ptr<VideoPacket> packet) { | 257 void ScreenRecorder::DoSendVideoPacket(scoped_ptr<VideoPacket> packet) { |
| 258 DCHECK(network_loop_->BelongsToCurrentThread()); | 258 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 259 | 259 |
| 260 if (network_stopped_ || connections_.empty()) | 260 if (network_stopped_ || connections_.empty()) |
| 261 return; | 261 return; |
| 262 | 262 |
| 263 base::Closure callback; | 263 base::Closure callback; |
| 264 if ((packet->flags() & VideoPacket::LAST_PARTITION) != 0) | 264 if ((packet->flags() & VideoPacket::LAST_PARTITION) != 0) |
| 265 callback = base::Bind(&ScreenRecorder::VideoFrameSentCallback, this); | 265 callback = base::Bind(&ScreenRecorder::VideoFrameSentCallback, this); |
| 266 | 266 |
| 267 // TODO(sergeyu): Currently we send the data only to the first | 267 // TODO(sergeyu): Currently we send the data only to the first |
| 268 // connection. Send it to all connections if necessary. | 268 // connection. Send it to all connections if necessary. |
| 269 connections_.front()->video_stub()->ProcessVideoPacket( | 269 connections_.front()->video_stub()->ProcessVideoPacket( |
| 270 packet.Pass(), callback); | 270 packet.Pass(), callback); |
| 271 } | 271 } |
| 272 | 272 |
| 273 void ScreenRecorder::VideoFrameSentCallback() { | 273 void ScreenRecorder::VideoFrameSentCallback() { |
| 274 DCHECK(network_loop_->BelongsToCurrentThread()); | 274 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 275 | 275 |
| 276 if (network_stopped_) | 276 if (network_stopped_) |
| 277 return; | 277 return; |
| 278 | 278 |
| 279 capture_loop_->PostTask( | 279 capture_task_runner_->PostTask( |
| 280 FROM_HERE, base::Bind(&ScreenRecorder::DoFinishOneRecording, this)); | 280 FROM_HERE, base::Bind(&ScreenRecorder::DoFinishOneRecording, this)); |
| 281 } | 281 } |
| 282 | 282 |
| 283 void ScreenRecorder::DoStopOnNetworkThread(const base::Closure& done_task) { | 283 void ScreenRecorder::DoStopOnNetworkThread(const base::Closure& done_task) { |
| 284 DCHECK(network_loop_->BelongsToCurrentThread()); | 284 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 285 | 285 |
| 286 // There could be tasks on the network thread when this method is being | 286 // There could be tasks on the network thread when this method is being |
| 287 // executed. By setting the flag we'll not post anymore tasks from network | 287 // executed. By setting the flag we'll not post anymore tasks from network |
| 288 // thread. | 288 // thread. |
| 289 // | 289 // |
| 290 // After that a task is posted on encode thread to continue the stop | 290 // After that a task is posted on encode thread to continue the stop |
| 291 // sequence. | 291 // sequence. |
| 292 network_stopped_ = true; | 292 network_stopped_ = true; |
| 293 | 293 |
| 294 encode_loop_->PostTask( | 294 encode_task_runner_->PostTask( |
| 295 FROM_HERE, base::Bind(&ScreenRecorder::DoStopOnEncodeThread, | 295 FROM_HERE, base::Bind(&ScreenRecorder::DoStopOnEncodeThread, |
| 296 this, done_task)); | 296 this, done_task)); |
| 297 } | 297 } |
| 298 | 298 |
| 299 void ScreenRecorder::DoSendCursorShape( | 299 void ScreenRecorder::DoSendCursorShape( |
| 300 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { | 300 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { |
| 301 DCHECK(network_loop_->BelongsToCurrentThread()); | 301 DCHECK(network_task_runner_->BelongsToCurrentThread()); |
| 302 | 302 |
| 303 if (network_stopped_ || connections_.empty()) | 303 if (network_stopped_ || connections_.empty()) |
| 304 return; | 304 return; |
| 305 | 305 |
| 306 // TODO(sergeyu): Currently we send the data only to the first | 306 // TODO(sergeyu): Currently we send the data only to the first |
| 307 // connection. Send it to all connections if necessary. | 307 // connection. Send it to all connections if necessary. |
| 308 connections_.front()->client_stub()->SetCursorShape(*cursor_shape); | 308 connections_.front()->client_stub()->SetCursorShape(*cursor_shape); |
| 309 } | 309 } |
| 310 | 310 |
| 311 // Encoder thread -------------------------------------------------------------- | 311 // Encoder thread -------------------------------------------------------------- |
| 312 | 312 |
| 313 void ScreenRecorder::DoEncode( | 313 void ScreenRecorder::DoEncode( |
| 314 scoped_refptr<CaptureData> capture_data) { | 314 scoped_refptr<CaptureData> capture_data) { |
| 315 DCHECK_EQ(encode_loop_, MessageLoop::current()); | 315 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
| 316 | 316 |
| 317 if (encoder_stopped_) | 317 if (encoder_stopped_) |
| 318 return; | 318 return; |
| 319 | 319 |
| 320 // Early out if there's nothing to encode. | 320 // Early out if there's nothing to encode. |
| 321 if (!capture_data || capture_data->dirty_region().isEmpty()) { | 321 if (!capture_data || capture_data->dirty_region().isEmpty()) { |
| 322 // Send an empty video packet to keep network active. | 322 // Send an empty video packet to keep network active. |
| 323 scoped_ptr<VideoPacket> packet(new VideoPacket()); | 323 scoped_ptr<VideoPacket> packet(new VideoPacket()); |
| 324 packet->set_flags(VideoPacket::LAST_PARTITION); | 324 packet->set_flags(VideoPacket::LAST_PARTITION); |
| 325 network_loop_->PostTask( | 325 network_task_runner_->PostTask( |
| 326 FROM_HERE, base::Bind(&ScreenRecorder::DoSendVideoPacket, | 326 FROM_HERE, base::Bind(&ScreenRecorder::DoSendVideoPacket, |
| 327 this, base::Passed(packet.Pass()))); | 327 this, base::Passed(packet.Pass()))); |
| 328 return; | 328 return; |
| 329 } | 329 } |
| 330 | 330 |
| 331 encode_start_time_ = base::Time::Now(); | 331 encode_start_time_ = base::Time::Now(); |
| 332 encoder()->Encode( | 332 encoder()->Encode( |
| 333 capture_data, false, | 333 capture_data, false, |
| 334 base::Bind(&ScreenRecorder::EncodedDataAvailableCallback, this)); | 334 base::Bind(&ScreenRecorder::EncodedDataAvailableCallback, this)); |
| 335 } | 335 } |
| 336 | 336 |
| 337 void ScreenRecorder::DoStopOnEncodeThread(const base::Closure& done_task) { | 337 void ScreenRecorder::DoStopOnEncodeThread(const base::Closure& done_task) { |
| 338 DCHECK_EQ(encode_loop_, MessageLoop::current()); | 338 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
| 339 | 339 |
| 340 encoder_stopped_ = true; | 340 encoder_stopped_ = true; |
| 341 | 341 |
| 342 // When this method is being executed there are no more tasks on encode thread | 342 // When this method is being executed there are no more tasks on encode thread |
| 343 // for this object. We can then post a task to capture thread to finish the | 343 // for this object. We can then post a task to capture thread to finish the |
| 344 // stop sequence. | 344 // stop sequence. |
| 345 capture_loop_->PostTask(FROM_HERE, done_task); | 345 capture_task_runner_->PostTask(FROM_HERE, done_task); |
| 346 } | 346 } |
| 347 | 347 |
| 348 void ScreenRecorder::EncodedDataAvailableCallback( | 348 void ScreenRecorder::EncodedDataAvailableCallback( |
| 349 scoped_ptr<VideoPacket> packet) { | 349 scoped_ptr<VideoPacket> packet) { |
| 350 DCHECK_EQ(encode_loop_, MessageLoop::current()); | 350 DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
| 351 | 351 |
| 352 if (encoder_stopped_) | 352 if (encoder_stopped_) |
| 353 return; | 353 return; |
| 354 | 354 |
| 355 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0; | 355 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0; |
| 356 if (last) { | 356 if (last) { |
| 357 base::TimeDelta encode_time = base::Time::Now() - encode_start_time_; | 357 base::TimeDelta encode_time = base::Time::Now() - encode_start_time_; |
| 358 int encode_time_ms = | 358 int encode_time_ms = |
| 359 static_cast<int>(encode_time.InMilliseconds()); | 359 static_cast<int>(encode_time.InMilliseconds()); |
| 360 packet->set_encode_time_ms(encode_time_ms); | 360 packet->set_encode_time_ms(encode_time_ms); |
| 361 scheduler_.RecordEncodeTime(encode_time); | 361 scheduler_.RecordEncodeTime(encode_time); |
| 362 } | 362 } |
| 363 | 363 |
| 364 network_loop_->PostTask( | 364 network_task_runner_->PostTask( |
| 365 FROM_HERE, base::Bind(&ScreenRecorder::DoSendVideoPacket, this, | 365 FROM_HERE, base::Bind(&ScreenRecorder::DoSendVideoPacket, this, |
| 366 base::Passed(packet.Pass()))); | 366 base::Passed(packet.Pass()))); |
| 367 } | 367 } |
| 368 | 368 |
| 369 } // namespace remoting | 369 } // namespace remoting |
| OLD | NEW |