| Index: remoting/host/capture_scheduler.cc
|
| diff --git a/remoting/host/capture_scheduler.cc b/remoting/host/capture_scheduler.cc
|
| index c6b3be0a1d23fd87759d1cf4cddf39d7b303cb82..ccd141ddcdc85f8c5cb8c1916fe41f12a17a4d06 100644
|
| --- a/remoting/host/capture_scheduler.cc
|
| +++ b/remoting/host/capture_scheduler.cc
|
| @@ -8,6 +8,7 @@
|
|
|
| #include "base/logging.h"
|
| #include "base/sys_info.h"
|
| +#include "base/time/default_tick_clock.h"
|
| #include "base/time/time.h"
|
|
|
| namespace {
|
| @@ -24,46 +25,125 @@ const int64 kDefaultMinimumIntervalMs = 33;
|
| // available while 1 means using 100% of all CPUs available.
|
| const double kRecordingCpuConsumption = 0.5;
|
|
|
| +// Maximum number of frames that can be processed simultaneously.
|
| +static const int kMaxPendingFrames = 2;
|
| +
|
| } // namespace
|
|
|
| namespace remoting {
|
|
|
| // We assume that the number of available cores is constant.
|
| -CaptureScheduler::CaptureScheduler()
|
| - : minimum_interval_(
|
| +CaptureScheduler::CaptureScheduler(const base::Closure& capture_closure)
|
| + : capture_closure_(capture_closure),
|
| + tick_clock_(new base::DefaultTickClock()),
|
| + capture_timer_(new base::Timer(false, false)),
|
| + minimum_interval_(
|
| base::TimeDelta::FromMilliseconds(kDefaultMinimumIntervalMs)),
|
| num_of_processors_(base::SysInfo::NumberOfProcessors()),
|
| capture_time_(kStatisticsWindow),
|
| - encode_time_(kStatisticsWindow) {
|
| + encode_time_(kStatisticsWindow),
|
| + pending_frames_(0),
|
| + capture_pending_(false),
|
| + is_paused_(false) {
|
| DCHECK(num_of_processors_);
|
| }
|
|
|
| CaptureScheduler::~CaptureScheduler() {
|
| }
|
|
|
| -base::TimeDelta CaptureScheduler::NextCaptureDelay() {
|
| - // Delay by an amount chosen such that if capture and encode times
|
| - // continue to follow the averages, then we'll consume the target
|
| - // fraction of CPU across all cores.
|
| - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(
|
| - (capture_time_.Average() + encode_time_.Average()) /
|
| - (kRecordingCpuConsumption * num_of_processors_));
|
| +void CaptureScheduler::Start() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + ScheduleNextCapture();
|
| +}
|
| +
|
| +void CaptureScheduler::Pause(bool pause) {
|
| + DCHECK(CalledOnValidThread());
|
|
|
| - if (delay < minimum_interval_)
|
| - return minimum_interval_;
|
| - return delay;
|
| + if (is_paused_ != pause) {
|
| + is_paused_ = pause;
|
| +
|
| + if (is_paused_) {
|
| + capture_timer_->Stop();
|
| + } else {
|
| + ScheduleNextCapture();
|
| + }
|
| + }
|
| }
|
|
|
| -void CaptureScheduler::RecordCaptureTime(base::TimeDelta capture_time) {
|
| - capture_time_.Record(capture_time.InMilliseconds());
|
| +void CaptureScheduler::OnCaptureCompleted() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + capture_pending_ = false;
|
| + capture_time_.Record(
|
| + (tick_clock_->NowTicks() - last_capture_started_time_).InMilliseconds());
|
| +
|
| + ScheduleNextCapture();
|
| +}
|
| +
|
| +void CaptureScheduler::OnFrameSent() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + // Decrement the pending capture count.
|
| + pending_frames_--;
|
| + DCHECK_GE(pending_frames_, 0);
|
| +
|
| + ScheduleNextCapture();
|
| }
|
|
|
| -void CaptureScheduler::RecordEncodeTime(base::TimeDelta encode_time) {
|
| +void CaptureScheduler::OnFrameEncoded(base::TimeDelta encode_time) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| encode_time_.Record(encode_time.InMilliseconds());
|
| + ScheduleNextCapture();
|
| }
|
|
|
| +void CaptureScheduler::SetTickClockForTest(
|
| + scoped_ptr<base::TickClock> tick_clock) {
|
| + tick_clock_ = tick_clock.Pass();
|
| +}
|
| +void CaptureScheduler::SetTimerForTest(scoped_ptr<base::Timer> timer) {
|
| + capture_timer_ = timer.Pass();
|
| +}
|
| void CaptureScheduler::SetNumOfProcessorsForTest(int num_of_processors) {
|
| num_of_processors_ = num_of_processors;
|
| }
|
|
|
| +void CaptureScheduler::ScheduleNextCapture() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + if (is_paused_ || pending_frames_ >= kMaxPendingFrames || capture_pending_)
|
| + return;
|
| +
|
| + // Delay by an amount chosen such that if capture and encode times
|
| + // continue to follow the averages, then we'll consume the target
|
| + // fraction of CPU across all cores.
|
| + base::TimeDelta delay =
|
| + std::max(minimum_interval_,
|
| + base::TimeDelta::FromMilliseconds(
|
| + (capture_time_.Average() + encode_time_.Average()) /
|
| + (kRecordingCpuConsumption * num_of_processors_)));
|
| +
|
| + // Account for the time that has passed since the last capture.
|
| + delay = std::max(base::TimeDelta(), delay - (tick_clock_->NowTicks() -
|
| + last_capture_started_time_));
|
| +
|
| + capture_timer_->Start(
|
| + FROM_HERE, delay,
|
| + base::Bind(&CaptureScheduler::CaptureNextFrame, base::Unretained(this)));
|
| +}
|
| +
|
| +void CaptureScheduler::CaptureNextFrame() {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(!is_paused_);
|
| + DCHECK(!capture_pending_);
|
| +
|
| + pending_frames_++;
|
| + DCHECK_LE(pending_frames_, kMaxPendingFrames);
|
| +
|
| + capture_pending_ = true;
|
| + last_capture_started_time_ = tick_clock_->NowTicks();
|
| + capture_closure_.Run();
|
| +}
|
| +
|
| } // namespace remoting
|
|
|