Chromium Code Reviews| 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_(-1, 1000), frame_processing_delay_us_(kStatsWindow) {} |
|
Irfan
2016/09/29 22:22:41
-1 should perhaps be a constant to indicate UNLIMI
Sergey Ulanov
2016/09/29 23:25:21
Done.
| |
| 35 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 35 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
| 36 | 36 |
| 37 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { | 37 void WebrtcFrameSchedulerSimple::Start(const base::Closure& capture_callback) { |
| 38 capture_callback_ = capture_callback; | 38 capture_callback_ = capture_callback; |
| 39 ScheduleNextFrame(); | 39 ScheduleNextFrame(base::TimeTicks::Now()); |
| 40 } | 40 } |
| 41 | 41 |
| 42 void WebrtcFrameSchedulerSimple::Pause(bool pause) { | 42 void WebrtcFrameSchedulerSimple::Pause(bool pause) { |
| 43 paused_ = pause; | 43 paused_ = pause; |
| 44 if (paused_) { | 44 if (paused_) { |
| 45 capture_timer_.Stop(); | 45 capture_timer_.Stop(); |
| 46 } else if (!capture_callback_.is_null()) { | 46 } else if (!capture_callback_.is_null()) { |
| 47 ScheduleNextFrame(); | 47 ScheduleNextFrame(base::TimeTicks::Now()); |
| 48 } | 48 } |
| 49 } | 49 } |
| 50 | 50 |
| 51 void WebrtcFrameSchedulerSimple::SetKeyFrameRequest() { | 51 void WebrtcFrameSchedulerSimple::SetKeyFrameRequest() { |
| 52 key_frame_request_ = true; | 52 key_frame_request_ = true; |
| 53 } | 53 } |
| 54 | 54 |
| 55 void WebrtcFrameSchedulerSimple::SetTargetBitrate(int bitrate_kbps) { | 55 void WebrtcFrameSchedulerSimple::SetTargetBitrate(int bitrate_kbps) { |
| 56 target_bitrate_kbps_ = bitrate_kbps; | 56 base::TimeTicks now = base::TimeTicks::Now(); |
| 57 pacing_bucket_.UpdateRate(bitrate_kbps * (1000 / 8), now); | |
| 58 ScheduleNextFrame(now); | |
| 57 } | 59 } |
| 58 | 60 |
| 59 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( | 61 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( |
| 60 const webrtc::DesktopFrame& frame, | 62 const webrtc::DesktopFrame& frame, |
| 61 WebrtcVideoEncoder::FrameParams* params_out) { | 63 WebrtcVideoEncoder::FrameParams* params_out) { |
| 64 base::TimeTicks now = base::TimeTicks::Now(); | |
| 65 | |
| 62 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 66 if (frame.updated_region().is_empty() && !top_off_is_active_ && |
| 63 !key_frame_request_) { | 67 !key_frame_request_) { |
| 64 ScheduleNextFrame(); | 68 ScheduleNextFrame(now); |
| 65 return false; | 69 return false; |
| 66 } | 70 } |
| 67 | 71 |
| 68 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. | 72 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for VP9. |
| 69 int minimum_bitrate = | 73 int minimum_bitrate = |
| 70 static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * | 74 static_cast<uint64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * |
| 71 frame.size().width() * frame.size().height() / 1000000LL; | 75 frame.size().width() * frame.size().height() / 1000000LL; |
| 72 params_out->bitrate_kbps = std::max(minimum_bitrate, target_bitrate_kbps_); | 76 params_out->bitrate_kbps = |
| 77 std::max(minimum_bitrate, pacing_bucket_.rate() * 8 / 1000); | |
| 73 | 78 |
| 74 // TODO(sergeyu): Currently duration is always set to 1/15 of a second. | 79 // TODO(sergeyu): Currently duration is always set to 1/15 of a second. |
| 75 // Experiment with different values, and try changing it dynamically. | 80 // Experiment with different values, and try changing it dynamically. |
| 76 params_out->duration = base::TimeDelta::FromSeconds(1) / 15; | 81 params_out->duration = base::TimeDelta::FromSeconds(1) / 15; |
| 77 | 82 |
| 78 params_out->key_frame = key_frame_request_; | 83 params_out->key_frame = key_frame_request_; |
| 79 key_frame_request_ = false; | 84 key_frame_request_ = false; |
| 80 | 85 |
| 81 params_out->vpx_min_quantizer = 10; | 86 params_out->vpx_min_quantizer = 10; |
| 82 params_out->vpx_max_quantizer = 63; | 87 params_out->vpx_max_quantizer = 63; |
| 83 | 88 |
| 84 params_out->clear_active_map = !top_off_is_active_; | 89 params_out->clear_active_map = !top_off_is_active_; |
| 85 | 90 |
| 86 return true; | 91 return true; |
| 87 } | 92 } |
| 88 | 93 |
| 89 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 94 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
| 90 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 95 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, |
| 91 const webrtc::EncodedImageCallback::Result& send_result) { | 96 const webrtc::EncodedImageCallback::Result& send_result) { |
| 97 base::TimeTicks now = base::TimeTicks::Now(); | |
| 98 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); | |
| 99 | |
| 92 if (encoded_frame.data.empty()) { | 100 if (encoded_frame.data.empty()) { |
| 93 top_off_is_active_ = false; | 101 top_off_is_active_ = false; |
| 94 ScheduleNextFrame(); | 102 } else { |
| 95 return; | 103 frame_processing_delay_us_.Record( |
| 104 (now - last_capture_started_time_).InMicroseconds()); | |
| 105 | |
| 106 // Top-off until the target quantizer value is reached. | |
| 107 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; | |
| 96 } | 108 } |
| 97 | 109 |
| 98 frame_processing_delay_us_.Record( | 110 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 } | 111 } |
| 112 | 112 |
| 113 void WebrtcFrameSchedulerSimple::ScheduleNextFrame() { | 113 void WebrtcFrameSchedulerSimple::ScheduleNextFrame(base::TimeTicks now) { |
| 114 if (paused_) | 114 if (paused_) |
| 115 return; | 115 return; |
| 116 | 116 |
| 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 | 117 // If this is not the first frame then capture next frame after the previous |
| 121 // one has finished sending. | 118 // one has finished sending. |
| 122 if (!last_frame_send_finish_time_.is_null()) { | 119 base::TimeDelta expected_processing_time = |
| 123 base::TimeDelta expected_processing_time = | 120 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); |
| 124 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); | 121 base::TimeTicks target_capture_time = |
| 125 delay = std::max(base::TimeDelta(), last_frame_send_finish_time_ - | 122 pacing_bucket_.GetEmptyTime() - expected_processing_time; |
| 126 expected_processing_time - now); | |
| 127 } | |
| 128 | 123 |
| 129 // Cap interval between frames to kTargetFrameInterval. | 124 // Cap interval between frames to kTargetFrameInterval. |
| 130 if (!last_capture_started_time_.is_null()) { | 125 if (!last_capture_started_time_.is_null()) { |
| 131 delay = std::max(delay, | 126 target_capture_time = std::max( |
| 132 last_capture_started_time_ + kTargetFrameInterval - now); | 127 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); |
| 133 } | 128 } |
| 134 | 129 |
| 135 capture_timer_.Start(FROM_HERE, delay, | 130 if (target_capture_time < now) |
| 131 target_capture_time = now; | |
| 132 | |
| 133 capture_timer_.Start(FROM_HERE, target_capture_time - now, | |
| 136 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, | 134 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, |
| 137 base::Unretained(this))); | 135 base::Unretained(this))); |
| 138 } | 136 } |
| 139 | 137 |
| 140 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 138 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
| 141 last_capture_started_time_ = base::TimeTicks::Now(); | 139 last_capture_started_time_ = base::TimeTicks::Now(); |
| 142 capture_callback_.Run(); | 140 capture_callback_.Run(); |
| 143 } | 141 } |
| 144 | 142 |
| 145 } // namespace protocol | 143 } // namespace protocol |
| 146 } // namespace remoting | 144 } // namespace remoting |
| OLD | NEW |