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

Side by Side 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 unified diff | Download patch
OLDNEW
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.h" 5 #include "remoting/protocol/webrtc_frame_scheduler.h"
6 6
7 #include <algorithm>
7 #include <memory> 8 #include <memory>
8 9
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "remoting/base/constants.h" 11 #include "remoting/base/constants.h"
11 #include "remoting/proto/video.pb.h" 12 #include "remoting/proto/video.pb.h"
12 13
13 namespace remoting { 14 namespace remoting {
14 namespace protocol { 15 namespace protocol {
15 16
17 namespace {
18
19 // Amount of time in microseconds after which the accumulated average is halved.
20 const int kAccFrameDurationHalfLifeUs = 200000;
21
22 // Starting value on the expected duration of a frame.
23 const int kStartingFrameDurationUs = 100000;
24
25 // Target quantizer at which stop the encoding top-off.
26 const int kTargetQuantizerForTopOff = 30;
27
28 } // namespace
29
16 // The frame scheduler currently uses a simple polling technique 30 // The frame scheduler currently uses a simple polling technique
17 // at 30 FPS to capture, encode and send frames over webrtc transport. 31 // at 30 FPS to capture, encode and send frames over webrtc transport.
18 // An improved solution will use target bitrate feedback to pace out 32 // An improved solution will use target bitrate feedback to pace out
19 // the capture rate. 33 // the capture rate.
20 WebRtcFrameScheduler::WebRtcFrameScheduler( 34 WebRtcFrameScheduler::WebRtcFrameScheduler(
21 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, 35 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
22 std::unique_ptr<webrtc::DesktopCapturer> capturer, 36 std::unique_ptr<webrtc::DesktopCapturer> capturer,
23 WebrtcTransport* webrtc_transport, 37 WebrtcTransport* webrtc_transport,
24 std::unique_ptr<VideoEncoder> encoder) 38 std::unique_ptr<VideoEncoder> encoder)
25 : encode_task_runner_(encode_task_runner), 39 : acc_frame_duration_(
40 base::TimeDelta::FromMicroseconds(kAccFrameDurationHalfLifeUs)),
41 encode_task_runner_(encode_task_runner),
26 capturer_(std::move(capturer)), 42 capturer_(std::move(capturer)),
27 webrtc_transport_(webrtc_transport), 43 webrtc_transport_(webrtc_transport),
28 encoder_(std::move(encoder)), 44 encoder_(std::move(encoder)),
29 weak_factory_(this) { 45 weak_factory_(this) {
30 DCHECK(encode_task_runner_); 46 DCHECK(encode_task_runner_);
31 DCHECK(capturer_); 47 DCHECK(capturer_);
32 DCHECK(webrtc_transport_); 48 DCHECK(webrtc_transport_);
33 DCHECK(encoder_); 49 DCHECK(encoder_);
34 // Does not really start anything. Registers callback on this class. 50 // Does not really start anything. Registers callback on this class.
35 capturer_->Start(this); 51 capturer_->Start(this);
36 capture_timer_.reset(new base::RepeatingTimer()); 52 capture_timer_.reset(new base::RepeatingTimer());
37 } 53 }
38 54
39 WebRtcFrameScheduler::~WebRtcFrameScheduler() { 55 WebRtcFrameScheduler::~WebRtcFrameScheduler() {
40 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); 56 encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release());
41 } 57 }
42 58
43 void WebRtcFrameScheduler::Start() { 59 void WebRtcFrameScheduler::Start() {
44 // Register for PLI requests. 60 // Register for PLI requests.
45 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( 61 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback(
46 base::Bind(&WebRtcFrameScheduler::SetKeyFrameRequest, 62 base::Bind(&WebRtcFrameScheduler::SetKeyFrameRequest,
47 base::Unretained(this))); 63 base::Unretained(this)));
64 // Register for target bitrate notifications.
65 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback(
66 base::Bind(&WebRtcFrameScheduler::SetTargetBitrate,
67 base::Unretained(this)));
48 capture_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, 68 capture_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this,
49 &WebRtcFrameScheduler::CaptureNextFrame); 69 &WebRtcFrameScheduler::CaptureNextFrame);
50 } 70 }
51 71
52 void WebRtcFrameScheduler::Stop() { 72 void WebRtcFrameScheduler::Stop() {
53 // Clear PLI request callback. 73 // Clear PLI request callback.
54 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( 74 webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback(
55 base::Closure()); 75 base::Closure());
76 webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback(
77 TargetBitrateCallback());
56 // Cancel any pending encode. 78 // Cancel any pending encode.
57 task_tracker_.TryCancelAll(); 79 task_tracker_.TryCancelAll();
58 capture_timer_->Stop(); 80 capture_timer_->Stop();
59 } 81 }
60 82
61 void WebRtcFrameScheduler::Pause(bool pause) { 83 void WebRtcFrameScheduler::Pause(bool pause) {
62 if (pause) { 84 if (pause) {
63 Stop(); 85 Stop();
64 } else { 86 } else {
65 Start(); 87 Start();
66 } 88 }
67 } 89 }
68 90
69 void WebRtcFrameScheduler::SetSizeCallback( 91 void WebRtcFrameScheduler::SetSizeCallback(
70 const VideoStream::SizeCallback& callback) { 92 const VideoStream::SizeCallback& callback) {
71 size_callback_ = callback; 93 size_callback_ = callback;
72 } 94 }
73 95
74 void WebRtcFrameScheduler::SetKeyFrameRequest() { 96 void WebRtcFrameScheduler::SetKeyFrameRequest() {
75 VLOG(1) << "Request key frame"; 97 VLOG(1) << "Request key frame";
76 base::AutoLock lock(lock_); 98 base::AutoLock lock(lock_);
77 key_frame_request_ = true; 99 key_frame_request_ = true;
78 } 100 }
79 101
102 void WebRtcFrameScheduler::SetTargetBitrate(uint32_t target_bitrate_kbps) {
103 LOG(ERROR) << "Set Target bitrate " << target_bitrate_kbps;
104 base::AutoLock lock(lock_);
105 target_bitrate_kbps_ = target_bitrate_kbps;
106 }
107
80 bool WebRtcFrameScheduler::ClearAndGetKeyFrameRequest() { 108 bool WebRtcFrameScheduler::ClearAndGetKeyFrameRequest() {
81 base::AutoLock lock(lock_); 109 base::AutoLock lock(lock_);
82 bool key_frame_request = key_frame_request_; 110 bool key_frame_request = key_frame_request_;
83 key_frame_request_ = false; 111 key_frame_request_ = false;
84 return key_frame_request; 112 return key_frame_request;
85 } 113 }
86 114
87 webrtc::SharedMemory* WebRtcFrameScheduler::CreateSharedMemory(size_t size) { 115 webrtc::SharedMemory* WebRtcFrameScheduler::CreateSharedMemory(size_t size) {
88 DCHECK(thread_checker_.CalledOnValidThread()); 116 DCHECK(thread_checker_.CalledOnValidThread());
89 return nullptr; 117 return nullptr;
90 } 118 }
91 119
92 void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) { 120 void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
93 DCHECK(thread_checker_.CalledOnValidThread()); 121 DCHECK(thread_checker_.CalledOnValidThread());
94 122
95 VLOG(1) << "Capture overhead " 123 base::TimeTicks captured_ticks = base::TimeTicks::Now();
96 << (base::TimeTicks::Now() - last_capture_ticks_).InMilliseconds(); 124 int64_t capture_timestamp_ms =
125 (captured_ticks - base::TimeTicks()).InMilliseconds();
97 capture_pending_ = false; 126 capture_pending_ = false;
98 127
99 std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame); 128 std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame);
100 129
101 if (encode_pending_) { 130 if (encode_pending_) {
102 // TODO(isheriff): consider queuing here 131 // TODO(isheriff): consider queuing here
103 VLOG(1) << "Dropping captured frame since encoder is still busy"; 132 VLOG(1) << "Dropping captured frame since encoder is still busy";
104 return; 133 return;
105 } 134 }
106 if (!frame || frame->updated_region().is_empty()) 135
136 // If unchanged and does not need top-off, return.
137 if (!frame || (frame->updated_region().is_empty() &&
138 last_quantizer_ <= kTargetQuantizerForTopOff))
107 return; 139 return;
108 140
141 if ((last_capture_completed_ticks_ - base::TimeTicks()).is_zero()) {
142 acc_frame_duration_.Reset(kStartingFrameDurationUs, captured_ticks);
143 } else {
144 base::TimeDelta duration = captured_ticks - last_capture_completed_ticks_;
145 acc_frame_duration_.Update(duration.InMicroseconds(), captured_ticks);
146 }
147 last_capture_completed_ticks_ = captured_ticks;
148
109 webrtc::DesktopVector dpi = 149 webrtc::DesktopVector dpi =
110 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) 150 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi)
111 : frame->dpi(); 151 : frame->dpi();
112 152
113 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { 153 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) {
114 frame_size_ = frame->size(); 154 frame_size_ = frame->size();
115 frame_dpi_ = dpi; 155 frame_dpi_ = dpi;
116 if (!size_callback_.is_null()) 156 if (!size_callback_.is_null())
117 size_callback_.Run(frame_size_, frame_dpi_); 157 size_callback_.Run(frame_size_, frame_dpi_);
118 } 158 }
119 encode_pending_ = true; 159 encode_pending_ = true;
120 task_tracker_.PostTaskAndReplyWithResult( 160 task_tracker_.PostTaskAndReplyWithResult(
121 encode_task_runner_.get(), FROM_HERE, 161 encode_task_runner_.get(), FROM_HERE,
122 base::Bind(&WebRtcFrameScheduler::EncodeFrame, encoder_.get(), 162 base::Bind(&WebRtcFrameScheduler::EncodeFrame, encoder_.get(),
123 base::Passed(std::move(owned_frame)), 163 base::Passed(std::move(owned_frame)), target_bitrate_kbps_,
124 ClearAndGetKeyFrameRequest()), 164 static_cast<int64_t>(acc_frame_duration_.current()),
165 ClearAndGetKeyFrameRequest(), capture_timestamp_ms),
125 base::Bind(&WebRtcFrameScheduler::OnFrameEncoded, 166 base::Bind(&WebRtcFrameScheduler::OnFrameEncoded,
126 weak_factory_.GetWeakPtr())); 167 weak_factory_.GetWeakPtr()));
127 } 168 }
128 169
129 void WebRtcFrameScheduler::CaptureNextFrame() { 170 void WebRtcFrameScheduler::CaptureNextFrame() {
130 DCHECK(thread_checker_.CalledOnValidThread()); 171 DCHECK(thread_checker_.CalledOnValidThread());
131 172
132 if (capture_pending_ || encode_pending_) { 173 if (capture_pending_ || encode_pending_) {
133 VLOG(1) << "Capture/encode still pending.."; 174 VLOG(1) << "Capture/encode still pending..";
134 return; 175 return;
135 } 176 }
136 capture_pending_ = true; 177 capture_pending_ = true;
137 VLOG(1) << "Capture next frame after " 178 VLOG(1) << "Capture next frame after "
138 << (base::TimeTicks::Now() - last_capture_ticks_).InMilliseconds(); 179 << (base::TimeTicks::Now() - last_capture_started_ticks_)
139 last_capture_ticks_ = base::TimeTicks::Now(); 180 .InMilliseconds();
181 last_capture_started_ticks_ = base::TimeTicks::Now();
140 capturer_->Capture(webrtc::DesktopRegion()); 182 capturer_->Capture(webrtc::DesktopRegion());
141 } 183 }
142 184
143 // static 185 // static
144 std::unique_ptr<VideoPacket> WebRtcFrameScheduler::EncodeFrame( 186 std::unique_ptr<VideoPacket> WebRtcFrameScheduler::EncodeFrame(
145 VideoEncoder* encoder, 187 VideoEncoder* encoder,
146 std::unique_ptr<webrtc::DesktopFrame> frame, 188 std::unique_ptr<webrtc::DesktopFrame> frame,
147 bool key_frame_request) { 189 uint32_t target_bitrate_kbps,
190 int64_t frame_duration_us,
191 bool key_frame_request,
192 int64_t capture_time_ms) {
148 uint32_t flags = 0; 193 uint32_t flags = 0;
149 if (key_frame_request) 194 if (key_frame_request)
150 flags |= VideoEncoder::REQUEST_KEY_FRAME; 195 flags |= VideoEncoder::REQUEST_KEY_FRAME;
151 196
152 base::TimeTicks current = base::TimeTicks::Now(); 197 base::TimeTicks current = base::TimeTicks::Now();
198 encoder->UpdateTargetBitrate(target_bitrate_kbps);
153 std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags); 199 std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags);
154 if (!packet) 200 if (!packet)
155 return nullptr; 201 return nullptr;
202 packet->set_capture_time_ms(capture_time_ms);
156 203
157 VLOG(1) << "Encode duration " 204 VLOG(1) << "Encode duration "
158 << (base::TimeTicks::Now() - current).InMilliseconds() 205 << (base::TimeTicks::Now() - current).InMilliseconds()
159 << " payload size " << packet->data().size(); 206 << " payload size " << packet->data().size() << " quantizer "
207 << packet->quantizer();
160 return packet; 208 return packet;
161 } 209 }
162 210
163 void WebRtcFrameScheduler::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) { 211 void WebRtcFrameScheduler::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) {
164 DCHECK(thread_checker_.CalledOnValidThread()); 212 DCHECK(thread_checker_.CalledOnValidThread());
165 encode_pending_ = false; 213 encode_pending_ = false;
166 if (!packet) 214 if (!packet)
167 return; 215 return;
168 int64_t capture_timestamp_ms = 216 last_quantizer_ = packet->quantizer();
169 (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
170 base::TimeTicks current = base::TimeTicks::Now(); 217 base::TimeTicks current = base::TimeTicks::Now();
218 uint32_t encoded_bits = packet->data().size() * 8.0;
219 VLOG(1) << "frame duration " << acc_frame_duration_.current()
220 << " encoded bitrate (kbps) "
221 << (encoded_bits * 1000 / acc_frame_duration_.current());
222
223 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS.
224 uint32_t next_sched_ms = std::max(
225 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200));
171 // TODO(isheriff): Investigate why first frame fails to send at times. 226 // TODO(isheriff): Investigate why first frame fails to send at times.
172 // This gets resolved through a PLI request. 227 // This gets resolved through a PLI request.
173 webrtc_transport_->video_encoder_factory()->SendEncodedFrame( 228 if (webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
174 capture_timestamp_ms, std::move(packet)); 229 std::move(packet)) >= 0) {
175 230 VLOG(1) << " Send duration "
176 VLOG(1) << "Send duration " 231 << (base::TimeTicks::Now() - current).InMilliseconds()
177 << (base::TimeTicks::Now() - current).InMilliseconds(); 232 << "next sched " << next_sched_ms;
233 } else {
234 LOG(ERROR) << "SendEncodedFrame() failed";
235 }
236 capture_timer_->Start(FROM_HERE,
237 base::TimeDelta::FromMilliseconds(next_sched_ms), this,
238 &WebRtcFrameScheduler::CaptureNextFrame);
178 } 239 }
179 240
180 } // namespace protocol 241 } // namespace protocol
181 } // namespace remoting 242 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698