| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/protocol/webrtc_frame_scheduler_simple.h" | 5 #include "remoting/protocol/webrtc_frame_scheduler_simple.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 9 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 10 | 10 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 const int kTargetQuantizerForVp8TopOff = 30; | 24 const int kTargetQuantizerForVp8TopOff = 30; |
| 25 | 25 |
| 26 // Minimum target bitrate per megapixel. The value is chosen experimentally such | 26 // Minimum target bitrate per megapixel. The value is chosen experimentally such |
| 27 // that when screen is not changing the codec converges to the target quantizer | 27 // that when screen is not changing the codec converges to the target quantizer |
| 28 // above in less than 10 frames. | 28 // above in less than 10 frames. |
| 29 const int kVp8MinimumTargetBitrateKbpsPerMegapixel = 2500; | 29 const int kVp8MinimumTargetBitrateKbpsPerMegapixel = 2500; |
| 30 | 30 |
| 31 } // namespace | 31 } // namespace |
| 32 | 32 |
| 33 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() | 33 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() |
| 34 : frame_processing_delay_us_(kStatsWindow) {} | 34 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), |
| 35 frame_processing_delay_us_(kStatsWindow) {} |
| 35 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 36 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
| 36 | 37 |
| 37 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { | 38 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { |
| 38 capture_callback_ = capture_callback; | 39 capture_callback_ = capture_callback; |
| 39 ScheduleNextFrame(); | 40 ScheduleNextFrame(base::TimeTicks::Now()); |
| 40 } | 41 } |
| 41 | 42 |
| 42 void WebrtcFrameSchedulerSimple::Pause(bool pause) { | 43 void WebrtcFrameSchedulerSimple::Pause(bool pause) { |
| 43 paused_ = pause; | 44 paused_ = pause; |
| 44 if (paused_) { | 45 if (paused_) { |
| 45 capture_timer_.Stop(); | 46 capture_timer_.Stop(); |
| 46 } else if (!capture_callback_.is_null()) { | 47 } else if (!capture_callback_.is_null()) { |
| 47 ScheduleNextFrame(); | 48 ScheduleNextFrame(base::TimeTicks::Now()); |
| 48 } | 49 } |
| 49 } | 50 } |
| 50 | 51 |
| 51 void WebrtcFrameSchedulerSimple::SetKeyFrameRequest() { | 52 void WebrtcFrameSchedulerSimple::SetKeyFrameRequest() { |
| 52 key_frame_request_ = true; | 53 key_frame_request_ = true; |
| 53 } | 54 } |
| 54 | 55 |
| 55 void WebrtcFrameSchedulerSimple::SetTargetBitrate(int bitrate_kbps) { | 56 void WebrtcFrameSchedulerSimple::SetTargetBitrate(int bitrate_kbps) { |
| 56 target_bitrate_kbps_ = bitrate_kbps; | 57 base::TimeTicks now = base::TimeTicks::Now(); |
| 58 pacing_bucket_.UpdateRate(bitrate_kbps * 1000 / 8, now); |
| 59 ScheduleNextFrame(now); |
| 57 } | 60 } |
| 58 | 61 |
| 59 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( | 62 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( |
| 60 const webrtc::DesktopFrame& frame, | 63 const webrtc::DesktopFrame& frame, |
| 61 WebrtcVideoEncoder::FrameParams* params_out) { | 64 WebrtcVideoEncoder::FrameParams* params_out) { |
| 65 base::TimeTicks now = base::TimeTicks::Now(); |
| 66 |
| 62 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 67 if (frame.updated_region().is_empty() && !top_off_is_active_ && |
| 63 !key_frame_request_) { | 68 !key_frame_request_) { |
| 64 ScheduleNextFrame(); | 69 ScheduleNextFrame(now); |
| 65 return false; | 70 return false; |
| 66 } | 71 } |
| 67 | 72 |
| 68 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. | 73 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. |
| 69 int minimum_bitrate = | 74 int minimum_bitrate = |
| 70 static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * | 75 static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * |
| 71 frame.size().width() * frame.size().height() / 1000000LL; | 76 frame.size().width() * frame.size().height() / 1000000LL; |
| 72 params_out->bitrate_kbps = std::max(minimum_bitrate, target_bitrate_kbps_); | 77 params_out->bitrate_kbps = |
| 78 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); |
| 73 | 79 |
| 74 // TODO(sergeyu): Currently duration is always set to 1/15 of a second. | 80 // TODO(sergeyu): Currently duration is always set to 1/15 of a second. |
| 75 // Experiment with different values, and try changing it dynamically. | 81 // Experiment with different values, and try changing it dynamically. |
| 76 params_out->duration = base::TimeDelta::FromSeconds(1) / 15; | 82 params_out->duration = base::TimeDelta::FromSeconds(1) / 15; |
| 77 | 83 |
| 78 params_out->key_frame = key_frame_request_; | 84 params_out->key_frame = key_frame_request_; |
| 79 key_frame_request_ = false; | 85 key_frame_request_ = false; |
| 80 | 86 |
| 81 params_out->vpx_min_quantizer = 10; | 87 params_out->vpx_min_quantizer = 10; |
| 82 params_out->vpx_max_quantizer = 63; | 88 params_out->vpx_max_quantizer = 63; |
| 83 | 89 |
| 84 params_out->clear_active_map = !top_off_is_active_; | 90 params_out->clear_active_map = !top_off_is_active_; |
| 85 | 91 |
| 86 return true; | 92 return true; |
| 87 } | 93 } |
| 88 | 94 |
| 89 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 95 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
| 90 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 96 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
| 91 const webrtc::EncodedImageCallback::Result& send_result) { | 97 const webrtc::EncodedImageCallback::Result& send_result) { |
| 98 base::TimeTicks now = base::TimeTicks::Now(); |
| 99 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); |
| 100 |
| 92 if (encoded_frame.data.empty()) { | 101 if (encoded_frame.data.empty()) { |
| 93 top_off_is_active_ = false; | 102 top_off_is_active_ = false; |
| 94 ScheduleNextFrame(); | 103 } else { |
| 95 return; | 104 frame_processing_delay_us_.Record( |
| 105 (now - last_capture_started_time_).InMicroseconds()); |
| 106 |
| 107 // Top-off until the target quantizer value is reached. |
| 108 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; |
| 96 } | 109 } |
| 97 | 110 |
| 98 frame_processing_delay_us_.Record( | 111 ScheduleNextFrame(now); |
| 99 (base::TimeTicks::Now() - last_capture_started_time_).InMicroseconds()); | |
| 100 | |
| 101 // Top-off until the target quantizer value is reached. | |
| 102 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; | |
| 103 | |
| 104 // Capture next frame after we finish sending the current one. | |
| 105 const double kKiloBitsPerByte = 8.0 / 1000.0; | |
| 106 base::TimeDelta expected_send_delay = base::TimeDelta::FromSecondsD( | |
| 107 encoded_frame.data.size() * kKiloBitsPerByte / target_bitrate_kbps_); | |
| 108 last_frame_send_finish_time_ = base::TimeTicks::Now() + expected_send_delay; | |
| 109 | |
| 110 ScheduleNextFrame(); | |
| 111 } | 112 } |
| 112 | 113 |
| 113 void WebrtcFrameSchedulerSimple::ScheduleNextFrame() { | 114 void WebrtcFrameSchedulerSimple::ScheduleNextFrame(base::TimeTicks now) { |
| 114 if (paused_) | 115 // Don't capture frames when paused or target bitrate is 0. |
| 116 if (paused_ || pacing_bucket_.rate() == 0) |
| 115 return; | 117 return; |
| 116 | 118 |
| 117 base::TimeTicks now = base::TimeTicks::Now(); | |
| 118 base::TimeDelta delay; | |
| 119 | |
| 120 // If this is not the first frame then capture next frame after the previous | 119 // If this is not the first frame then capture next frame after the previous |
| 121 // one has finished sending. | 120 // one has finished sending. |
| 122 if (!last_frame_send_finish_time_.is_null()) { | 121 base::TimeDelta expected_processing_time = |
| 123 base::TimeDelta expected_processing_time = | 122 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); |
| 124 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); | 123 base::TimeTicks target_capture_time = |
| 125 delay = std::max(base::TimeDelta(), last_frame_send_finish_time_ - | 124 pacing_bucket_.GetEmptyTime() - expected_processing_time; |
| 126 expected_processing_time - now); | |
| 127 } | |
| 128 | 125 |
| 129 // Cap interval between frames to kTargetFrameInterval. | 126 // Cap interval between frames to kTargetFrameInterval. |
| 130 if (!last_capture_started_time_.is_null()) { | 127 if (!last_capture_started_time_.is_null()) { |
| 131 delay = std::max(delay, | 128 target_capture_time = std::max( |
| 132 last_capture_started_time_ + kTargetFrameInterval - now); | 129 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); |
| 133 } | 130 } |
| 134 | 131 |
| 135 capture_timer_.Start(FROM_HERE, delay, | 132 if (target_capture_time < now) |
| 133 target_capture_time = now; |
| 134 |
| 135 capture_timer_.Start(FROM_HERE, target_capture_time - now, |
| 136 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, | 136 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, |
| 137 base::Unretained(this))); | 137 base::Unretained(this))); |
| 138 } | 138 } |
| 139 | 139 |
| 140 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 140 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
| 141 last_capture_started_time_ = base::TimeTicks::Now(); | 141 last_capture_started_time_ = base::TimeTicks::Now(); |
| 142 capture_callback_.Run(); | 142 capture_callback_.Run(); |
| 143 } | 143 } |
| 144 | 144 |
| 145 } // namespace protocol | 145 } // namespace protocol |
| 146 } // namespace remoting | 146 } // namespace remoting |
| OLD | NEW |