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

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

Issue 6282006: Add a done task to ScreenRecorder::Stop() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed comments Created 9 years, 11 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/screen_recorder.h ('k') | remoting/host/screen_recorder_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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/logging.h" 9 #include "base/logging.h"
10 #include "base/scoped_ptr.h" 10 #include "base/scoped_ptr.h"
(...skipping 27 matching lines...) Expand all
38 MessageLoop* capture_loop, 38 MessageLoop* capture_loop,
39 MessageLoop* encode_loop, 39 MessageLoop* encode_loop,
40 MessageLoop* network_loop, 40 MessageLoop* network_loop,
41 Capturer* capturer, 41 Capturer* capturer,
42 Encoder* encoder) 42 Encoder* encoder)
43 : capture_loop_(capture_loop), 43 : capture_loop_(capture_loop),
44 encode_loop_(encode_loop), 44 encode_loop_(encode_loop),
45 network_loop_(network_loop), 45 network_loop_(network_loop),
46 capturer_(capturer), 46 capturer_(capturer),
47 encoder_(encoder), 47 encoder_(encoder),
48 started_(false), 48 is_recording_(false),
49 network_stopped_(false),
49 recordings_(0), 50 recordings_(0),
50 frame_skipped_(false), 51 frame_skipped_(false),
51 max_rate_(kDefaultCaptureRate) { 52 max_rate_(kDefaultCaptureRate) {
52 DCHECK(capture_loop_); 53 DCHECK(capture_loop_);
53 DCHECK(encode_loop_); 54 DCHECK(encode_loop_);
54 DCHECK(network_loop_); 55 DCHECK(network_loop_);
55 } 56 }
56 57
57 ScreenRecorder::~ScreenRecorder() { 58 ScreenRecorder::~ScreenRecorder() {
58 connections_.clear();
59 } 59 }
60 60
61 // Public methods -------------------------------------------------------------- 61 // Public methods --------------------------------------------------------------
62 62
63 void ScreenRecorder::Start() { 63 void ScreenRecorder::Start() {
64 capture_loop_->PostTask( 64 capture_loop_->PostTask(
65 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoStart)); 65 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoStart));
66 } 66 }
67 67
68 void ScreenRecorder::Pause() { 68 void ScreenRecorder::Stop(Task* done_task) {
69 capture_loop_->PostTask( 69 capture_loop_->PostTask(
70 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoPause)); 70 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoStop, done_task));
71 } 71 }
72 72
73 void ScreenRecorder::SetMaxRate(double rate) { 73 void ScreenRecorder::SetMaxRate(double rate) {
74 capture_loop_->PostTask( 74 capture_loop_->PostTask(
75 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoSetMaxRate, rate)); 75 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoSetMaxRate, rate));
76 } 76 }
77 77
78 void ScreenRecorder::AddConnection( 78 void ScreenRecorder::AddConnection(
79 scoped_refptr<ConnectionToClient> connection) { 79 scoped_refptr<ConnectionToClient> connection) {
80 ScopedTracer tracer("AddConnection"); 80 ScopedTracer tracer("AddConnection");
(...skipping 28 matching lines...) Expand all
109 Encoder* ScreenRecorder::encoder() { 109 Encoder* ScreenRecorder::encoder() {
110 DCHECK_EQ(encode_loop_, MessageLoop::current()); 110 DCHECK_EQ(encode_loop_, MessageLoop::current());
111 DCHECK(encoder_.get()); 111 DCHECK(encoder_.get());
112 return encoder_.get(); 112 return encoder_.get();
113 } 113 }
114 114
115 // Capturer thread ------------------------------------------------------------- 115 // Capturer thread -------------------------------------------------------------
116 116
117 void ScreenRecorder::DoStart() { 117 void ScreenRecorder::DoStart() {
118 DCHECK_EQ(capture_loop_, MessageLoop::current()); 118 DCHECK_EQ(capture_loop_, MessageLoop::current());
119 DCHECK(!started_);
120 119
121 if (started_) { 120 if (is_recording_) {
122 NOTREACHED() << "Record session already started."; 121 NOTREACHED() << "Record session already started.";
123 return; 122 return;
124 } 123 }
125 124
126 started_ = true; 125 is_recording_ = true;
127 StartCaptureTimer(); 126 StartCaptureTimer();
128 127
129 // Capture first frame immedately. 128 // Capture first frame immedately.
130 DoCapture(); 129 DoCapture();
131 } 130 }
132 131
133 void ScreenRecorder::DoPause() { 132 void ScreenRecorder::DoStop(Task* done_task) {
134 DCHECK_EQ(capture_loop_, MessageLoop::current()); 133 DCHECK_EQ(capture_loop_, MessageLoop::current());
135 134
136 if (!started_) { 135 if (!is_recording_) {
137 NOTREACHED() << "Record session not started."; 136 NOTREACHED() << "Record session not started.";
138 return; 137 return;
139 } 138 }
140 139
141 capture_timer_.Stop(); 140 capture_timer_.Stop();
142 started_ = false; 141 is_recording_ = false;
142
143 DCHECK_GE(recordings_, 0);
144 if (recordings_) {
145 network_loop_->PostTask(
146 FROM_HERE,
147 NewTracedMethod(this,
148 &ScreenRecorder::DoStopOnNetworkThread, done_task));
149 return;
150 }
151
152 DoCompleteStop(done_task);
153 }
154
155 void ScreenRecorder::DoCompleteStop(Task* done_task) {
156 DCHECK_EQ(capture_loop_, MessageLoop::current());
157
158 if (done_task) {
159 done_task->Run();
160 delete done_task;
161 }
143 } 162 }
144 163
145 void ScreenRecorder::DoSetMaxRate(double max_rate) { 164 void ScreenRecorder::DoSetMaxRate(double max_rate) {
146 DCHECK_EQ(capture_loop_, MessageLoop::current()); 165 DCHECK_EQ(capture_loop_, MessageLoop::current());
147 166
148 // TODO(hclam): Should also check for small epsilon. 167 // TODO(hclam): Should also check for small epsilon.
149 DCHECK_GT(max_rate, 0.0) << "Rate is too small."; 168 DCHECK_GT(max_rate, 0.0) << "Rate is too small.";
150 169
151 max_rate_ = max_rate; 170 max_rate_ = max_rate;
152 171
153 // Restart the timer with the new rate. 172 // Restart the timer with the new rate.
154 if (started_) { 173 if (is_recording_) {
155 capture_timer_.Stop(); 174 capture_timer_.Stop();
156 StartCaptureTimer(); 175 StartCaptureTimer();
157 } 176 }
158 } 177 }
159 178
160 void ScreenRecorder::StartCaptureTimer() { 179 void ScreenRecorder::StartCaptureTimer() {
161 DCHECK_EQ(capture_loop_, MessageLoop::current()); 180 DCHECK_EQ(capture_loop_, MessageLoop::current());
162 181
163 base::TimeDelta interval = base::TimeDelta::FromMilliseconds( 182 base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
164 static_cast<int>(base::Time::kMillisecondsPerSecond / max_rate_)); 183 static_cast<int>(base::Time::kMillisecondsPerSecond / max_rate_));
165 capture_timer_.Start(interval, this, &ScreenRecorder::DoCapture); 184 capture_timer_.Start(interval, this, &ScreenRecorder::DoCapture);
166 } 185 }
167 186
168 void ScreenRecorder::DoCapture() { 187 void ScreenRecorder::DoCapture() {
169 DCHECK_EQ(capture_loop_, MessageLoop::current()); 188 DCHECK_EQ(capture_loop_, MessageLoop::current());
170 // Make sure we have at most two oustanding recordings. We can simply return 189 // Make sure we have at most two oustanding recordings. We can simply return
171 // if we can't make a capture now, the next capture will be started by the 190 // if we can't make a capture now, the next capture will be started by the
172 // end of an encode operation. 191 // end of an encode operation.
173 if (recordings_ >= kMaxRecordings || !started_) { 192 if (recordings_ >= kMaxRecordings || !is_recording_) {
174 frame_skipped_ = true; 193 frame_skipped_ = true;
175 return; 194 return;
176 } 195 }
177 196
178 if (frame_skipped_) { 197 if (frame_skipped_) {
179 frame_skipped_ = false; 198 frame_skipped_ = false;
180 capture_timer_.Reset(); 199 capture_timer_.Reset();
181 } 200 }
182 201
183 TraceContext::tracer()->PrintString("Capture Started"); 202 TraceContext::tracer()->PrintString("Capture Started");
184 203
185 // At this point we are going to perform one capture so save the current time. 204 // At this point we are going to perform one capture so save the current time.
186 ++recordings_; 205 ++recordings_;
206 DCHECK_LE(recordings_, kMaxRecordings);
187 207
188 // And finally perform one capture. 208 // And finally perform one capture.
189 capturer()->CaptureInvalidRects( 209 capturer()->CaptureInvalidRects(
190 NewCallback(this, &ScreenRecorder::CaptureDoneCallback)); 210 NewCallback(this, &ScreenRecorder::CaptureDoneCallback));
191 } 211 }
192 212
193 void ScreenRecorder::CaptureDoneCallback( 213 void ScreenRecorder::CaptureDoneCallback(
194 scoped_refptr<CaptureData> capture_data) { 214 scoped_refptr<CaptureData> capture_data) {
195 // TODO(hclam): There is a bug if the capturer doesn't produce any dirty
196 // rects.
197 DCHECK_EQ(capture_loop_, MessageLoop::current()); 215 DCHECK_EQ(capture_loop_, MessageLoop::current());
216
217 if (!is_recording_)
218 return;
219
198 TraceContext::tracer()->PrintString("Capture Done"); 220 TraceContext::tracer()->PrintString("Capture Done");
199 encode_loop_->PostTask( 221 encode_loop_->PostTask(
200 FROM_HERE, 222 FROM_HERE,
201 NewTracedMethod(this, &ScreenRecorder::DoEncode, capture_data)); 223 NewTracedMethod(this, &ScreenRecorder::DoEncode, capture_data));
202 } 224 }
203 225
204 void ScreenRecorder::DoFinishSend() { 226 void ScreenRecorder::DoFinishOneRecording() {
205 DCHECK_EQ(capture_loop_, MessageLoop::current()); 227 DCHECK_EQ(capture_loop_, MessageLoop::current());
206 228
229 if (!is_recording_)
230 return;
231
207 // Decrement the number of recording in process since we have completed 232 // Decrement the number of recording in process since we have completed
208 // one cycle. 233 // one cycle.
209 --recordings_; 234 --recordings_;
235 DCHECK_GE(recordings_, 0);
210 236
211 // Try to do a capture again. Note that the following method may do nothing 237 // Try to do a capture again. Note that the following method may do nothing
212 // if it is too early to perform a capture. 238 // if it is too early to perform a capture.
213 DoCapture(); 239 DoCapture();
214 } 240 }
215 241
216 // Network thread -------------------------------------------------------------- 242 // Network thread --------------------------------------------------------------
217 243
218 void ScreenRecorder::DoSendVideoPacket(VideoPacket* packet) { 244 void ScreenRecorder::DoSendVideoPacket(VideoPacket* packet) {
219 DCHECK_EQ(network_loop_, MessageLoop::current()); 245 DCHECK_EQ(network_loop_, MessageLoop::current());
220 246
221 TraceContext::tracer()->PrintString("DoSendVideoPacket"); 247 TraceContext::tracer()->PrintString("DoSendVideoPacket");
222 248
223 bool last = (packet->flags() & VideoPacket::LAST_PARTITION) != 0; 249 bool last = (packet->flags() & VideoPacket::LAST_PARTITION) != 0;
224 250
251 if (network_stopped_) {
252 delete packet;
253 return;
254 }
255
225 for (ConnectionToClientList::const_iterator i = connections_.begin(); 256 for (ConnectionToClientList::const_iterator i = connections_.begin();
226 i < connections_.end(); ++i) { 257 i < connections_.end(); ++i) {
227 Task* done_task = NULL; 258 Task* done_task = NULL;
228 259
229 // Call OnFrameSent() only for the last packet in the first connection. 260 // Call FrameSentCallback() only for the last packet in the first
261 // connection.
230 if (last && i == connections_.begin()) { 262 if (last && i == connections_.begin()) {
231 done_task = NewTracedMethod(this, &ScreenRecorder::OnFrameSent, packet); 263 done_task = NewTracedMethod(this, &ScreenRecorder::FrameSentCallback,
264 packet);
232 } else { 265 } else {
266 // TODO(hclam): Fix this code since it causes multiple deletion if there's
267 // more than one connection.
233 done_task = new DeleteTask<VideoPacket>(packet); 268 done_task = new DeleteTask<VideoPacket>(packet);
234 } 269 }
235 270
236 (*i)->video_stub()->ProcessVideoPacket(packet, done_task); 271 (*i)->video_stub()->ProcessVideoPacket(packet, done_task);
237 } 272 }
238 273
239 TraceContext::tracer()->PrintString("DoSendVideoPacket done"); 274 TraceContext::tracer()->PrintString("DoSendVideoPacket done");
240 } 275 }
241 276
242 void ScreenRecorder::OnFrameSent(VideoPacket* packet) { 277 void ScreenRecorder::FrameSentCallback(VideoPacket* packet) {
243 delete packet; 278 delete packet;
279
280 if (network_stopped_)
281 return;
282
244 capture_loop_->PostTask( 283 capture_loop_->PostTask(
245 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoFinishSend)); 284 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoFinishOneRecording));
246 } 285 }
247 286
248 void ScreenRecorder::DoAddConnection( 287 void ScreenRecorder::DoAddConnection(
249 scoped_refptr<ConnectionToClient> connection) { 288 scoped_refptr<ConnectionToClient> connection) {
250 DCHECK_EQ(network_loop_, MessageLoop::current()); 289 DCHECK_EQ(network_loop_, MessageLoop::current());
251 290
252 // TODO(hclam): Force a full frame for next encode. 291 // TODO(hclam): Force a full frame for next encode.
253 connections_.push_back(connection); 292 connections_.push_back(connection);
254 } 293 }
255 294
256 void ScreenRecorder::DoRemoveClient( 295 void ScreenRecorder::DoRemoveClient(
257 scoped_refptr<ConnectionToClient> connection) { 296 scoped_refptr<ConnectionToClient> connection) {
258 DCHECK_EQ(network_loop_, MessageLoop::current()); 297 DCHECK_EQ(network_loop_, MessageLoop::current());
259 298
260 // TODO(hclam): Is it correct to do to a scoped_refptr? 299 // TODO(hclam): Is it correct to do to a scoped_refptr?
261 ConnectionToClientList::iterator it = 300 ConnectionToClientList::iterator it =
262 std::find(connections_.begin(), connections_.end(), connection); 301 std::find(connections_.begin(), connections_.end(), connection);
263 if (it != connections_.end()) { 302 if (it != connections_.end()) {
264 connections_.erase(it); 303 connections_.erase(it);
265 } 304 }
266 } 305 }
267 306
268 void ScreenRecorder::DoRemoveAllClients() { 307 void ScreenRecorder::DoRemoveAllClients() {
269 DCHECK_EQ(network_loop_, MessageLoop::current()); 308 DCHECK_EQ(network_loop_, MessageLoop::current());
270 309
271 // Clear the list of connections. 310 // Clear the list of connections.
272 connections_.clear(); 311 connections_.clear();
273 } 312 }
274 313
314 void ScreenRecorder::DoStopOnNetworkThread(Task* done_task) {
315 DCHECK_EQ(network_loop_, MessageLoop::current());
316
317 // There could be tasks on the network thread when this method is being
318 // executed. By setting the flag we'll not post anymore tasks from network
319 // thread.
320 //
321 // After that a task is posted on encode thread to continue the stop
322 // sequence.
323 network_stopped_ = true;
324
325 encode_loop_->PostTask(
326 FROM_HERE,
327 NewTracedMethod(this, &ScreenRecorder::DoStopOnEncodeThread, done_task));
328 }
329
275 // Encoder thread -------------------------------------------------------------- 330 // Encoder thread --------------------------------------------------------------
276 331
277 void ScreenRecorder::DoEncode( 332 void ScreenRecorder::DoEncode(
278 scoped_refptr<CaptureData> capture_data) { 333 scoped_refptr<CaptureData> capture_data) {
279 DCHECK_EQ(encode_loop_, MessageLoop::current()); 334 DCHECK_EQ(encode_loop_, MessageLoop::current());
280 TraceContext::tracer()->PrintString("DoEncode called"); 335 TraceContext::tracer()->PrintString("DoEncode called");
281 336
282 // Early out if there's nothing to encode. 337 // Early out if there's nothing to encode.
283 if (!capture_data->dirty_rects().size()) { 338 if (!capture_data->dirty_rects().size()) {
284 capture_loop_->PostTask( 339 capture_loop_->PostTask(
285 FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoFinishSend)); 340 FROM_HERE,
341 NewTracedMethod(this, &ScreenRecorder::DoFinishOneRecording));
286 return; 342 return;
287 } 343 }
288 344
289 // TODO(hclam): Enable |force_refresh| if a new connection was 345 // TODO(hclam): Invalidate the full screen if there is a new connection added.
290 // added.
291 TraceContext::tracer()->PrintString("Encode start"); 346 TraceContext::tracer()->PrintString("Encode start");
292 encoder()->Encode(capture_data, false, 347 encoder()->Encode(
293 NewCallback(this, &ScreenRecorder::EncodeDataAvailableTask)); 348 capture_data, false,
349 NewCallback(this, &ScreenRecorder::EncodedDataAvailableCallback));
294 TraceContext::tracer()->PrintString("Encode Done"); 350 TraceContext::tracer()->PrintString("Encode Done");
295 } 351 }
296 352
297 void ScreenRecorder::EncodeDataAvailableTask(VideoPacket* packet) { 353 void ScreenRecorder::DoStopOnEncodeThread(Task* done_task) {
354 DCHECK_EQ(encode_loop_, MessageLoop::current());
355
356 // When this method is being executed there are no more tasks on encode thread
357 // for this object. We can then post a task to capture thread to finish the
358 // stop sequence.
359 capture_loop_->PostTask(
360 FROM_HERE,
361 NewTracedMethod(this, &ScreenRecorder::DoCompleteStop, done_task));
362 }
363
364 void ScreenRecorder::EncodedDataAvailableCallback(VideoPacket* packet) {
298 DCHECK_EQ(encode_loop_, MessageLoop::current()); 365 DCHECK_EQ(encode_loop_, MessageLoop::current());
299 366
300 network_loop_->PostTask( 367 network_loop_->PostTask(
301 FROM_HERE, 368 FROM_HERE,
302 NewTracedMethod(this, &ScreenRecorder::DoSendVideoPacket, packet)); 369 NewTracedMethod(this, &ScreenRecorder::DoSendVideoPacket, packet));
303 } 370 }
304 371
305 } // namespace remoting 372 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/screen_recorder.h ('k') | remoting/host/screen_recorder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698