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

Unified Diff: remoting/protocol/webrtc_frame_scheduler.cc

Issue 1908203002: Adapt encoder behavior to target bitrate (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moved webrtc encoder to its own file Created 4 years, 7 months 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 side-by-side diff with in-line comments
Download patch
Index: remoting/protocol/webrtc_frame_scheduler.cc
diff --git a/remoting/protocol/webrtc_frame_scheduler.cc b/remoting/protocol/webrtc_frame_scheduler.cc
index a9f25cb1dc1c4cdc6ba888d386f0078149cb3d73..1d3a43e02f8d72e1d943b12495354ac4cc3ec67b 100644
--- a/remoting/protocol/webrtc_frame_scheduler.cc
+++ b/remoting/protocol/webrtc_frame_scheduler.cc
@@ -4,6 +4,7 @@
#include "remoting/protocol/webrtc_frame_scheduler.h"
+#include <algorithm>
#include <memory>
#include "base/logging.h"
@@ -13,6 +14,19 @@
namespace remoting {
namespace protocol {
+namespace {
+
+// Amount of time in microseconds after which the accumulated average is halved.
+const int kAccFrameDurationHalfLifeUs = 200000;
+
+// Starting value on the expected duration of a frame.
+const int kStartingFrameDurationUs = 100000;
+
+// Target quantizer at which stop the encoding top-off.
+const int kTargetQuantizerForTopOff = 30;
+
+} // namespace
+
// The frame scheduler currently uses a simple polling technique
// at 30 FPS to capture, encode and send frames over webrtc transport.
// An improved solution will use target bitrate feedback to pace out
@@ -22,7 +36,9 @@ WebRtcFrameScheduler::WebRtcFrameScheduler(
std::unique_ptr<webrtc::DesktopCapturer> capturer,
WebrtcTransport* webrtc_transport,
std::unique_ptr<VideoEncoder> encoder)
- : encode_task_runner_(encode_task_runner),
+ : acc_frame_duration_(
+ base::TimeDelta::FromMicroseconds(kAccFrameDurationHalfLifeUs)),
+ encode_task_runner_(encode_task_runner),
capturer_(std::move(capturer)),
webrtc_transport_(webrtc_transport),
encoder_(std::move(encoder)),
@@ -45,6 +61,10 @@ void WebRtcFrameScheduler::Start() {
webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback(
base::Bind(&WebRtcFrameScheduler::SetKeyFrameRequest,
base::Unretained(this)));
+ // Register for target bitrate notifications.
+ webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback(
+ base::Bind(&WebRtcFrameScheduler::SetTargetBitrate,
+ base::Unretained(this)));
capture_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this,
&WebRtcFrameScheduler::CaptureNextFrame);
}
@@ -53,6 +73,8 @@ void WebRtcFrameScheduler::Stop() {
// Clear PLI request callback.
webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback(
base::Closure());
+ webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback(
+ TargetBitrateCallback());
// Cancel any pending encode.
task_tracker_.TryCancelAll();
capture_timer_->Stop();
@@ -77,6 +99,12 @@ void WebRtcFrameScheduler::SetKeyFrameRequest() {
key_frame_request_ = true;
}
+void WebRtcFrameScheduler::SetTargetBitrate(uint32_t target_bitrate_kbps) {
+ LOG(ERROR) << "Set Target bitrate " << target_bitrate_kbps;
+ base::AutoLock lock(lock_);
+ target_bitrate_kbps_ = target_bitrate_kbps;
+}
+
bool WebRtcFrameScheduler::ClearAndGetKeyFrameRequest() {
base::AutoLock lock(lock_);
bool key_frame_request = key_frame_request_;
@@ -92,8 +120,9 @@ webrtc::SharedMemory* WebRtcFrameScheduler::CreateSharedMemory(size_t size) {
void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
DCHECK(thread_checker_.CalledOnValidThread());
- VLOG(1) << "Capture overhead "
- << (base::TimeTicks::Now() - last_capture_ticks_).InMilliseconds();
+ base::TimeTicks captured_ticks = base::TimeTicks::Now();
+ int64_t capture_timestamp_ms =
+ (captured_ticks - base::TimeTicks()).InMilliseconds();
capture_pending_ = false;
std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame);
@@ -103,9 +132,20 @@ void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
VLOG(1) << "Dropping captured frame since encoder is still busy";
return;
}
- if (!frame || frame->updated_region().is_empty())
+
+ // If unchanged and does not need top-off, return.
+ if (!frame || (frame->updated_region().is_empty() &&
+ last_quantizer_ <= kTargetQuantizerForTopOff))
return;
+ if ((last_capture_completed_ticks_ - base::TimeTicks()).is_zero()) {
+ acc_frame_duration_.Reset(kStartingFrameDurationUs, captured_ticks);
+ } else {
+ base::TimeDelta duration = captured_ticks - last_capture_completed_ticks_;
+ acc_frame_duration_.Update(duration.InMicroseconds(), captured_ticks);
+ }
+ last_capture_completed_ticks_ = captured_ticks;
+
webrtc::DesktopVector dpi =
frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi)
: frame->dpi();
@@ -120,8 +160,9 @@ void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
task_tracker_.PostTaskAndReplyWithResult(
encode_task_runner_.get(), FROM_HERE,
base::Bind(&WebRtcFrameScheduler::EncodeFrame, encoder_.get(),
- base::Passed(std::move(owned_frame)),
- ClearAndGetKeyFrameRequest()),
+ base::Passed(std::move(owned_frame)), target_bitrate_kbps_,
+ static_cast<int64_t>(acc_frame_duration_.current()),
+ ClearAndGetKeyFrameRequest(), capture_timestamp_ms),
base::Bind(&WebRtcFrameScheduler::OnFrameEncoded,
weak_factory_.GetWeakPtr()));
}
@@ -135,8 +176,9 @@ void WebRtcFrameScheduler::CaptureNextFrame() {
}
capture_pending_ = true;
VLOG(1) << "Capture next frame after "
- << (base::TimeTicks::Now() - last_capture_ticks_).InMilliseconds();
- last_capture_ticks_ = base::TimeTicks::Now();
+ << (base::TimeTicks::Now() - last_capture_started_ticks_)
+ .InMilliseconds();
+ last_capture_started_ticks_ = base::TimeTicks::Now();
capturer_->Capture(webrtc::DesktopRegion());
}
@@ -144,19 +186,25 @@ void WebRtcFrameScheduler::CaptureNextFrame() {
std::unique_ptr<VideoPacket> WebRtcFrameScheduler::EncodeFrame(
VideoEncoder* encoder,
std::unique_ptr<webrtc::DesktopFrame> frame,
- bool key_frame_request) {
+ uint32_t target_bitrate_kbps,
+ int64_t frame_duration_us,
+ bool key_frame_request,
+ int64_t capture_time_ms) {
uint32_t flags = 0;
if (key_frame_request)
flags |= VideoEncoder::REQUEST_KEY_FRAME;
base::TimeTicks current = base::TimeTicks::Now();
+ encoder->UpdateTargetBitrate(target_bitrate_kbps);
std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags);
if (!packet)
return nullptr;
+ packet->set_capture_time_ms(capture_time_ms);
VLOG(1) << "Encode duration "
<< (base::TimeTicks::Now() - current).InMilliseconds()
- << " payload size " << packet->data().size();
+ << " payload size " << packet->data().size() << " quantizer "
+ << packet->quantizer();
return packet;
}
@@ -165,16 +213,29 @@ void WebRtcFrameScheduler::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) {
encode_pending_ = false;
if (!packet)
return;
- int64_t capture_timestamp_ms =
- (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
+ last_quantizer_ = packet->quantizer();
base::TimeTicks current = base::TimeTicks::Now();
+ uint32_t encoded_bits = packet->data().size() * 8.0;
+ VLOG(1) << "frame duration " << acc_frame_duration_.current()
+ << " encoded bitrate (kbps) "
+ << (encoded_bits * 1000 / acc_frame_duration_.current());
+
+ // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS.
+ uint32_t next_sched_ms = std::max(
+ 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200));
// TODO(isheriff): Investigate why first frame fails to send at times.
// This gets resolved through a PLI request.
- webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
- capture_timestamp_ms, std::move(packet));
-
- VLOG(1) << "Send duration "
- << (base::TimeTicks::Now() - current).InMilliseconds();
+ if (webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
+ std::move(packet)) >= 0) {
+ VLOG(1) << " Send duration "
+ << (base::TimeTicks::Now() - current).InMilliseconds()
+ << "next sched " << next_sched_ms;
+ } else {
+ LOG(ERROR) << "SendEncodedFrame() failed";
+ }
+ capture_timer_->Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(next_sched_ms), this,
+ &WebRtcFrameScheduler::CaptureNextFrame);
}
} // namespace protocol

Powered by Google App Engine
This is Rietveld 408576698