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

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

Issue 8342040: Gather history of capture and encode time determine next recoring delay (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: done Created 9 years, 1 month 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop_proxy.h" 12 #include "base/message_loop_proxy.h"
13 #include "base/stl_util.h" 13 #include "base/stl_util.h"
14 #include "base/sys_info.h"
14 #include "base/task.h" 15 #include "base/task.h"
15 #include "base/time.h" 16 #include "base/time.h"
16 #include "remoting/base/capture_data.h" 17 #include "remoting/base/capture_data.h"
17 #include "remoting/proto/control.pb.h" 18 #include "remoting/proto/control.pb.h"
18 #include "remoting/proto/video.pb.h" 19 #include "remoting/proto/video.pb.h"
19 #include "remoting/protocol/client_stub.h" 20 #include "remoting/protocol/client_stub.h"
20 #include "remoting/protocol/connection_to_client.h" 21 #include "remoting/protocol/connection_to_client.h"
21 #include "remoting/protocol/message_decoder.h" 22 #include "remoting/protocol/message_decoder.h"
22 #include "remoting/protocol/util.h" 23 #include "remoting/protocol/util.h"
23 24
24 using remoting::protocol::ConnectionToClient; 25 using remoting::protocol::ConnectionToClient;
25 26
26 namespace remoting { 27 namespace remoting {
27 28
28 // By default we capture 20 times a second. This number is obtained by
29 // experiment to provide good latency.
30 static const double kDefaultCaptureRate = 20.0;
31
32 // Maximum number of frames that can be processed similtaneously. 29 // Maximum number of frames that can be processed similtaneously.
33 // TODO(sergeyu): Should this be set to 1? Or should we change
34 // dynamically depending on how fast network and CPU are? Experement
35 // with it.
36 static const int kMaxRecordings = 2; 30 static const int kMaxRecordings = 2;
37 31
38 ScreenRecorder::ScreenRecorder( 32 ScreenRecorder::ScreenRecorder(
39 MessageLoop* capture_loop, 33 MessageLoop* capture_loop,
40 MessageLoop* encode_loop, 34 MessageLoop* encode_loop,
41 base::MessageLoopProxy* network_loop, 35 base::MessageLoopProxy* network_loop,
42 Capturer* capturer, 36 Capturer* capturer,
43 Encoder* encoder) 37 Encoder* encoder)
44 : capture_loop_(capture_loop), 38 : capture_loop_(capture_loop),
45 encode_loop_(encode_loop), 39 encode_loop_(encode_loop),
46 network_loop_(network_loop), 40 network_loop_(network_loop),
47 capturer_(capturer), 41 capturer_(capturer),
48 encoder_(encoder), 42 encoder_(encoder),
49 is_recording_(false), 43 is_recording_(false),
50 network_stopped_(false), 44 network_stopped_(false),
51 encoder_stopped_(false), 45 encoder_stopped_(false),
46 max_recordings_(kMaxRecordings),
52 recordings_(0), 47 recordings_(0),
53 frame_skipped_(false), 48 frame_skipped_(false),
54 max_rate_(kDefaultCaptureRate),
55 sequence_number_(0) { 49 sequence_number_(0) {
56 DCHECK(capture_loop_); 50 DCHECK(capture_loop_);
57 DCHECK(encode_loop_); 51 DCHECK(encode_loop_);
58 DCHECK(network_loop_); 52 DCHECK(network_loop_);
59 } 53 }
60 54
61 ScreenRecorder::~ScreenRecorder() { 55 ScreenRecorder::~ScreenRecorder() {
62 } 56 }
63 57
64 // Public methods -------------------------------------------------------------- 58 // Public methods --------------------------------------------------------------
(...skipping 12 matching lines...) Expand all
77 71
78 DCHECK(!done_task.is_null()); 72 DCHECK(!done_task.is_null());
79 73
80 capture_timer_.Stop(); 74 capture_timer_.Stop();
81 is_recording_ = false; 75 is_recording_ = false;
82 76
83 network_loop_->PostTask(FROM_HERE, base::Bind( 77 network_loop_->PostTask(FROM_HERE, base::Bind(
84 &ScreenRecorder::DoStopOnNetworkThread, this, done_task)); 78 &ScreenRecorder::DoStopOnNetworkThread, this, done_task));
85 } 79 }
86 80
87 void ScreenRecorder::SetMaxRate(double rate) {
88 capture_loop_->PostTask(
89 FROM_HERE, NewRunnableMethod(this, &ScreenRecorder::DoSetMaxRate, rate));
90 }
91
92 void ScreenRecorder::AddConnection( 81 void ScreenRecorder::AddConnection(
93 scoped_refptr<ConnectionToClient> connection) { 82 scoped_refptr<ConnectionToClient> connection) {
94 capture_loop_->PostTask( 83 capture_loop_->PostTask(
95 FROM_HERE, 84 FROM_HERE,
96 NewRunnableMethod(this, &ScreenRecorder::DoInvalidateFullScreen)); 85 NewRunnableMethod(this, &ScreenRecorder::DoInvalidateFullScreen));
97 86
98 // Add the client to the list so it can receive update stream. 87 // Add the client to the list so it can receive update stream.
99 network_loop_->PostTask( 88 network_loop_->PostTask(
100 FROM_HERE, 89 FROM_HERE,
101 NewRunnableMethod(this, &ScreenRecorder::DoAddConnection, connection)); 90 NewRunnableMethod(this, &ScreenRecorder::DoAddConnection, connection));
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 134
146 void ScreenRecorder::DoStart() { 135 void ScreenRecorder::DoStart() {
147 DCHECK_EQ(capture_loop_, MessageLoop::current()); 136 DCHECK_EQ(capture_loop_, MessageLoop::current());
148 137
149 if (is_recording_) { 138 if (is_recording_) {
150 NOTREACHED() << "Record session already started."; 139 NOTREACHED() << "Record session already started.";
151 return; 140 return;
152 } 141 }
153 142
154 is_recording_ = true; 143 is_recording_ = true;
155 StartCaptureTimer();
156 144
157 // Capture first frame immedately. 145 // Capture first frame immedately.
158 DoCapture(); 146 DoCapture();
159 } 147 }
160 148
161 void ScreenRecorder::DoSetMaxRate(double max_rate) {
162 DCHECK_EQ(capture_loop_, MessageLoop::current());
163
164 // TODO(hclam): Should also check for small epsilon.
165 DCHECK_GT(max_rate, 0.0) << "Rate is too small.";
166
167 max_rate_ = max_rate;
168
169 // Restart the timer with the new rate.
170 if (is_recording_) {
171 capture_timer_.Stop();
172 StartCaptureTimer();
173 }
174 }
175
176 void ScreenRecorder::StartCaptureTimer() { 149 void ScreenRecorder::StartCaptureTimer() {
177 DCHECK_EQ(capture_loop_, MessageLoop::current()); 150 DCHECK_EQ(capture_loop_, MessageLoop::current());
178 151
179 base::TimeDelta interval = base::TimeDelta::FromMilliseconds( 152 capture_timer_.Start(FROM_HERE,
180 static_cast<int>(base::Time::kMillisecondsPerSecond / max_rate_)); 153 scheduler_.NextCaptureDelay(),
181 capture_timer_.Start(FROM_HERE, interval, this, &ScreenRecorder::DoCapture); 154 this,
155 &ScreenRecorder::DoCapture);
182 } 156 }
183 157
184 void ScreenRecorder::DoCapture() { 158 void ScreenRecorder::DoCapture() {
185 DCHECK_EQ(capture_loop_, MessageLoop::current()); 159 DCHECK_EQ(capture_loop_, MessageLoop::current());
186 // Make sure we have at most two oustanding recordings. We can simply return 160 // Make sure we have at most two oustanding recordings. We can simply return
187 // if we can't make a capture now, the next capture will be started by the 161 // if we can't make a capture now, the next capture will be started by the
188 // end of an encode operation. 162 // end of an encode operation.
189 if (recordings_ >= kMaxRecordings || !is_recording_) { 163 if (recordings_ >= max_recordings_ || !is_recording_) {
190 frame_skipped_ = true; 164 frame_skipped_ = true;
191 return; 165 return;
192 } 166 }
193 167
194 if (frame_skipped_) { 168 if (frame_skipped_)
195 frame_skipped_ = false; 169 frame_skipped_ = false;
196 capture_timer_.Reset();
197 }
198 170
199 // At this point we are going to perform one capture so save the current time. 171 // At this point we are going to perform one capture so save the current time.
200 ++recordings_; 172 ++recordings_;
201 DCHECK_LE(recordings_, kMaxRecordings); 173 DCHECK_LE(recordings_, max_recordings_);
174
175 // Before doing a capture schedule for the next one.
176 capture_timer_.Stop();
177 capture_timer_.Start(FROM_HERE,
178 scheduler_.NextCaptureDelay(),
179 this,
180 &ScreenRecorder::DoCapture);
202 181
203 // And finally perform one capture. 182 // And finally perform one capture.
204 capture_start_time_ = base::Time::Now(); 183 capture_start_time_ = base::Time::Now();
205 capturer()->CaptureInvalidRegion( 184 capturer()->CaptureInvalidRegion(
206 NewCallback(this, &ScreenRecorder::CaptureDoneCallback)); 185 NewCallback(this, &ScreenRecorder::CaptureDoneCallback));
207 } 186 }
208 187
209 void ScreenRecorder::CaptureDoneCallback( 188 void ScreenRecorder::CaptureDoneCallback(
210 scoped_refptr<CaptureData> capture_data) { 189 scoped_refptr<CaptureData> capture_data) {
211 DCHECK_EQ(capture_loop_, MessageLoop::current()); 190 DCHECK_EQ(capture_loop_, MessageLoop::current());
212 191
213 if (!is_recording_) 192 if (!is_recording_)
214 return; 193 return;
215 194
216 if (capture_data) { 195 if (capture_data) {
217 int capture_time = static_cast<int>( 196 base::TimeDelta capture_time = base::Time::Now() - capture_start_time_;
218 (base::Time::Now() - capture_start_time_).InMilliseconds()); 197 int capture_time_ms =
219 capture_data->set_capture_time_ms(capture_time); 198 static_cast<int>(capture_time.InMilliseconds());
199 capture_data->set_capture_time_ms(capture_time_ms);
200 scheduler_.RecordCaptureTime(capture_time);
220 201
221 // The best way to get this value is by binding the sequence number to 202 // The best way to get this value is by binding the sequence number to
222 // the callback when calling CaptureInvalidRects(). However the callback 203 // the callback when calling CaptureInvalidRects(). However the callback
223 // system doesn't allow this. Reading from the member variable is 204 // system doesn't allow this. Reading from the member variable is
224 // accurate as long as capture is synchronous as the following statement 205 // accurate as long as capture is synchronous as the following statement
225 // will obtain the most recent sequence number received. 206 // will obtain the most recent sequence number received.
226 capture_data->set_client_sequence_number(sequence_number_); 207 capture_data->set_client_sequence_number(sequence_number_);
227 } 208 }
228 209
229 encode_loop_->PostTask( 210 encode_loop_->PostTask(
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 } 355 }
375 356
376 void ScreenRecorder::EncodedDataAvailableCallback(VideoPacket* packet) { 357 void ScreenRecorder::EncodedDataAvailableCallback(VideoPacket* packet) {
377 DCHECK_EQ(encode_loop_, MessageLoop::current()); 358 DCHECK_EQ(encode_loop_, MessageLoop::current());
378 359
379 if (encoder_stopped_) 360 if (encoder_stopped_)
380 return; 361 return;
381 362
382 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0; 363 bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
383 if (last) { 364 if (last) {
384 int encode_time = static_cast<int>( 365 base::TimeDelta encode_time = base::Time::Now() - encode_start_time_;
385 (base::Time::Now() - encode_start_time_).InMilliseconds()); 366 int encode_time_ms =
386 packet->set_encode_time_ms(encode_time); 367 static_cast<int>(encode_time.InMilliseconds());
368 packet->set_encode_time_ms(encode_time_ms);
369 scheduler_.RecordEncodeTime(encode_time);
387 } 370 }
388 371
389 network_loop_->PostTask( 372 network_loop_->PostTask(
390 FROM_HERE, 373 FROM_HERE,
391 NewRunnableMethod(this, &ScreenRecorder::DoSendVideoPacket, packet)); 374 NewRunnableMethod(this, &ScreenRecorder::DoSendVideoPacket, packet));
392 } 375 }
393 376
394 } // namespace remoting 377 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698