Index: remoting/protocol/webrtc_frame_scheduler_simple.cc |
diff --git a/remoting/protocol/webrtc_frame_scheduler_simple.cc b/remoting/protocol/webrtc_frame_scheduler_simple.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..daedb6f3aa3d2afdc6fe737756347b3d29708790 |
--- /dev/null |
+++ b/remoting/protocol/webrtc_frame_scheduler_simple.cc |
@@ -0,0 +1,127 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "remoting/protocol/webrtc_frame_scheduler_simple.h" |
+ |
+#include <algorithm> |
+ |
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
+ |
+namespace remoting { |
+namespace protocol { |
+ |
+namespace { |
+ |
+const int kTargetFrameRate = 30; |
+constexpr base::TimeDelta kTargetFrameInterval = |
+ base::TimeDelta::FromMilliseconds(1000 / kTargetFrameRate); |
+ |
+// Target quantizer at which stop the encoding top-off. |
+const int kTargetQuantizerForVp8TopOff = 30; |
+ |
+} // namespace |
+ |
+WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() {} |
+WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
+ |
+void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { |
+ capture_callback_ = capture_callback; |
+ ScheduleNextFrame(); |
+} |
+ |
+void WebrtcFrameSchedulerSimple::Pause(bool pause) { |
+ paused_ = pause; |
+ if (paused_) { |
+ capture_timer_.Stop(); |
+ } else if (!capture_callback_.is_null()) { |
+ ScheduleNextFrame(); |
+ } |
+} |
+ |
+void WebrtcFrameSchedulerSimple::SetKeyFrameRequest() { |
+ key_frame_request_ = true; |
+} |
+ |
+void WebrtcFrameSchedulerSimple::SetTargetBitrate(int bitrate_kbps) { |
+ target_bitrate_kbps_ = bitrate_kbps; |
+} |
+ |
+bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( |
+ const webrtc::DesktopFrame& frame, |
+ WebrtcVideoEncoder::FrameParams* params_out) { |
+ if (frame.updated_region().is_empty() && !top_off_is_active_ && |
+ !key_frame_request_) { |
+ ScheduleNextFrame(); |
+ return false; |
+ } |
+ |
+ params_out->bitrate_kbps = target_bitrate_kbps_; |
+ |
+ // TODO(sergeyu): Currently duration is always set to 1/15 of a second. |
+ // Experiment with different values, and try changing it dynamically. |
+ params_out->duration = base::TimeDelta::FromSeconds(1) / 15; |
+ |
+ params_out->key_frame = key_frame_request_; |
+ key_frame_request_ = false; |
+ |
+ params_out->vpx_min_quantizer = 10; |
+ params_out->vpx_max_quantizer = 63; |
+ |
+ params_out->clear_active_map = !top_off_is_active_; |
+ |
+ return true; |
+} |
+ |
+void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
+ const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
+ const webrtc::EncodedImageCallback::Result& send_result) { |
+ if (encoded_frame.data.empty()) { |
+ top_off_is_active_ = false; |
+ ScheduleNextFrame(); |
+ return; |
+ } |
+ |
+ // Top-off until the target quantizer value is reached. |
+ top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; |
+ |
+ // Capture next frame after we finish sending the current one. |
+ const double kKiloBitsPerByte = 8.0 / 1000.0; |
+ base::TimeDelta expected_send_delay = base::TimeDelta::FromSecondsD( |
+ encoded_frame.data.size() * kKiloBitsPerByte / target_bitrate_kbps_); |
+ last_frame_send_finish_time_ = base::TimeTicks::Now() + expected_send_delay; |
+ |
+ ScheduleNextFrame(); |
+} |
+ |
+void WebrtcFrameSchedulerSimple::ScheduleNextFrame() { |
+ if (paused_) |
+ return; |
+ |
+ base::TimeTicks now = base::TimeTicks::Now(); |
+ base::TimeDelta delay; |
+ |
+ // If this is not the first frame then capture next frame after the previous |
+ // one has finished sending. |
+ if (!last_frame_send_finish_time_.is_null()) { |
+ delay = std::max(base::TimeDelta(), last_frame_send_finish_time_ - now); |
+ } |
+ |
+ // Cap interval between frames to kTargetFrameInterval. |
+ if (!last_capture_started_time_.is_null()) { |
+ delay = std::max(delay, |
+ last_capture_started_time_ + kTargetFrameInterval - now); |
+ } |
+ |
+ capture_timer_.Start(FROM_HERE, delay, |
+ base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, |
+ base::Unretained(this))); |
+} |
+ |
+void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
+ last_capture_started_time_ = base::TimeTicks::Now(); |
+ capture_callback_.Run(); |
+} |
+ |
+} // namespace protocol |
+} // namespace remoting |