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

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: Remove unnecessary code 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
« no previous file with comments | « remoting/protocol/webrtc_frame_scheduler.h ('k') | remoting/protocol/webrtc_transport.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Target quantizer at which stop the encoding top-off.
20 const int kTargetQuantizerForTopOff = 30;
21
22 // Max Quantizer value.
23 const int kMaxQuantizer = 63;
24
25 // Default target bitrate in kbps
26 const int kDefaultTargetBitrateKbps = 1000;
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 : target_bitrate_kbps_(kDefaultTargetBitrateKbps),
40 last_quantizer_(kMaxQuantizer),
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(int target_bitrate_kbps) {
103 VLOG(1) << "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 void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) { 115 void WebRtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
88 DCHECK(thread_checker_.CalledOnValidThread()); 116 DCHECK(thread_checker_.CalledOnValidThread());
89 117
90 VLOG(1) << "Capture overhead " 118 base::TimeTicks captured_ticks = base::TimeTicks::Now();
91 << (base::TimeTicks::Now() - last_capture_ticks_).InMilliseconds(); 119 int64_t capture_timestamp_ms =
120 (captured_ticks - base::TimeTicks()).InMilliseconds();
92 capture_pending_ = false; 121 capture_pending_ = false;
93 122
94 std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame); 123 std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame);
95 124
96 if (encode_pending_) { 125 if (encode_pending_) {
97 // TODO(isheriff): consider queuing here 126 // TODO(isheriff): consider queuing here
98 VLOG(1) << "Dropping captured frame since encoder is still busy"; 127 VLOG(1) << "Dropping captured frame since encoder is still busy";
99 return; 128 return;
100 } 129 }
101 if (!frame || frame->updated_region().is_empty()) 130
131 // If unchanged and does not need top-off, return.
132 if (!frame || (frame->updated_region().is_empty() &&
133 last_quantizer_ <= kTargetQuantizerForTopOff))
102 return; 134 return;
103 135
136 last_capture_completed_ticks_ = captured_ticks;
137
104 webrtc::DesktopVector dpi = 138 webrtc::DesktopVector dpi =
105 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi) 139 frame->dpi().is_zero() ? webrtc::DesktopVector(kDefaultDpi, kDefaultDpi)
106 : frame->dpi(); 140 : frame->dpi();
107 141
108 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) { 142 if (!frame_size_.equals(frame->size()) || !frame_dpi_.equals(dpi)) {
109 frame_size_ = frame->size(); 143 frame_size_ = frame->size();
110 frame_dpi_ = dpi; 144 frame_dpi_ = dpi;
111 if (!size_callback_.is_null()) 145 if (!size_callback_.is_null())
112 size_callback_.Run(frame_size_, frame_dpi_); 146 size_callback_.Run(frame_size_, frame_dpi_);
113 } 147 }
114 encode_pending_ = true; 148 encode_pending_ = true;
115 task_tracker_.PostTaskAndReplyWithResult( 149 task_tracker_.PostTaskAndReplyWithResult(
116 encode_task_runner_.get(), FROM_HERE, 150 encode_task_runner_.get(), FROM_HERE,
117 base::Bind(&WebRtcFrameScheduler::EncodeFrame, encoder_.get(), 151 base::Bind(&WebRtcFrameScheduler::EncodeFrame, encoder_.get(),
118 base::Passed(std::move(owned_frame)), 152 base::Passed(std::move(owned_frame)), target_bitrate_kbps_,
119 ClearAndGetKeyFrameRequest()), 153 ClearAndGetKeyFrameRequest(), capture_timestamp_ms),
120 base::Bind(&WebRtcFrameScheduler::OnFrameEncoded, 154 base::Bind(&WebRtcFrameScheduler::OnFrameEncoded,
121 weak_factory_.GetWeakPtr())); 155 weak_factory_.GetWeakPtr()));
122 } 156 }
123 157
124 void WebRtcFrameScheduler::CaptureNextFrame() { 158 void WebRtcFrameScheduler::CaptureNextFrame() {
125 DCHECK(thread_checker_.CalledOnValidThread()); 159 DCHECK(thread_checker_.CalledOnValidThread());
126 160
127 if (capture_pending_ || encode_pending_) { 161 if (capture_pending_ || encode_pending_) {
128 VLOG(1) << "Capture/encode still pending.."; 162 VLOG(1) << "Capture/encode still pending..";
129 return; 163 return;
130 } 164 }
131 capture_pending_ = true; 165 capture_pending_ = true;
132 VLOG(1) << "Capture next frame after " 166 VLOG(1) << "Capture next frame after "
133 << (base::TimeTicks::Now() - last_capture_ticks_).InMilliseconds(); 167 << (base::TimeTicks::Now() - last_capture_started_ticks_)
134 last_capture_ticks_ = base::TimeTicks::Now(); 168 .InMilliseconds();
169 last_capture_started_ticks_ = base::TimeTicks::Now();
135 capturer_->Capture(webrtc::DesktopRegion()); 170 capturer_->Capture(webrtc::DesktopRegion());
136 } 171 }
137 172
138 // static 173 // static
139 std::unique_ptr<VideoPacket> WebRtcFrameScheduler::EncodeFrame( 174 std::unique_ptr<VideoPacket> WebRtcFrameScheduler::EncodeFrame(
140 VideoEncoder* encoder, 175 VideoEncoder* encoder,
141 std::unique_ptr<webrtc::DesktopFrame> frame, 176 std::unique_ptr<webrtc::DesktopFrame> frame,
142 bool key_frame_request) { 177 uint32_t target_bitrate_kbps,
178 bool key_frame_request,
179 int64_t capture_time_ms) {
143 uint32_t flags = 0; 180 uint32_t flags = 0;
144 if (key_frame_request) 181 if (key_frame_request)
145 flags |= VideoEncoder::REQUEST_KEY_FRAME; 182 flags |= VideoEncoder::REQUEST_KEY_FRAME;
146 183
147 base::TimeTicks current = base::TimeTicks::Now(); 184 base::TimeTicks current = base::TimeTicks::Now();
185 encoder->UpdateTargetBitrate(target_bitrate_kbps);
148 std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags); 186 std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags);
149 if (!packet) 187 if (!packet)
150 return nullptr; 188 return nullptr;
189 // TODO(isheriff): Note that while VideoPacket capture time is supposed
190 // to be capture duration, we (ab)use it for capture timestamp here. This
191 // will go away when we move away from VideoPacket.
192 packet->set_capture_time_ms(capture_time_ms);
151 193
152 VLOG(1) << "Encode duration " 194 VLOG(1) << "Encode duration "
153 << (base::TimeTicks::Now() - current).InMilliseconds() 195 << (base::TimeTicks::Now() - current).InMilliseconds()
154 << " payload size " << packet->data().size(); 196 << " payload size " << packet->data().size() << " quantizer "
197 << packet->quantizer();
155 return packet; 198 return packet;
156 } 199 }
157 200
158 void WebRtcFrameScheduler::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) { 201 void WebRtcFrameScheduler::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) {
159 DCHECK(thread_checker_.CalledOnValidThread()); 202 DCHECK(thread_checker_.CalledOnValidThread());
160 encode_pending_ = false; 203 encode_pending_ = false;
161 if (!packet) 204 if (!packet)
162 return; 205 return;
163 int64_t capture_timestamp_ms = 206 last_quantizer_ = packet->quantizer();
164 (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
165 base::TimeTicks current = base::TimeTicks::Now(); 207 base::TimeTicks current = base::TimeTicks::Now();
208 uint32_t encoded_bits = packet->data().size() * 8.0;
209
210 // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS.
211 uint32_t next_sched_ms = std::max(
212 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200));
166 // TODO(isheriff): Investigate why first frame fails to send at times. 213 // TODO(isheriff): Investigate why first frame fails to send at times.
167 // This gets resolved through a PLI request. 214 // This gets resolved through a PLI request.
168 webrtc_transport_->video_encoder_factory()->SendEncodedFrame( 215 if (webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
169 capture_timestamp_ms, std::move(packet)); 216 std::move(packet)) >= 0) {
170 217 VLOG(1) << " Send duration "
171 VLOG(1) << "Send duration " 218 << (base::TimeTicks::Now() - current).InMilliseconds()
172 << (base::TimeTicks::Now() - current).InMilliseconds(); 219 << "next sched " << next_sched_ms;
220 } else {
221 LOG(ERROR) << "SendEncodedFrame() failed";
222 }
223 capture_timer_->Start(FROM_HERE,
224 base::TimeDelta::FromMilliseconds(next_sched_ms), this,
225 &WebRtcFrameScheduler::CaptureNextFrame);
173 } 226 }
174 227
175 } // namespace protocol 228 } // namespace protocol
176 } // namespace remoting 229 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/protocol/webrtc_frame_scheduler.h ('k') | remoting/protocol/webrtc_transport.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698