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

Side by Side Diff: webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc

Issue 1193513006: In screenshare mode, suppress VP8 bitrate overshoot and increase quality (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rebase Created 5 years, 6 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 (c) 2013 The WebRTC project authors. All Rights Reserved. 1 /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
2 * 2 *
3 * Use of this source code is governed by a BSD-style license 3 * Use of this source code is governed by a BSD-style license
4 * that can be found in the LICENSE file in the root of the source 4 * that can be found in the LICENSE file in the root of the source
5 * tree. An additional intellectual property rights grant can be found 5 * tree. An additional intellectual property rights grant can be found
6 * in the file PATENTS. All contributing project authors may 6 * in the file PATENTS. All contributing project authors may
7 * be found in the AUTHORS file in the root of the source tree. 7 * be found in the AUTHORS file in the root of the source tree.
8 */ 8 */
9 9
10 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" 10 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
11 11
12 #include <stdlib.h> 12 #include <stdlib.h>
13 13
14 #include "webrtc/base/checks.h"
14 #include "vpx/vpx_encoder.h" 15 #include "vpx/vpx_encoder.h"
15 #include "vpx/vp8cx.h" 16 #include "vpx/vp8cx.h"
16 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" 17 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
17 18
18 namespace webrtc { 19 namespace webrtc {
19 20
20 enum { kOneSecond90Khz = 90000 }; 21 static const int kOneSecond90Khz = 90000;
22 static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 5;
23 static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 10;
24 static const int kQpDeltaThresholdForSync = 8;
21 25
22 const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5; 26 const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
23 const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0; 27 const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
24 28
29 // Since this is TL0 we only allow updating and predicting from the LAST
30 // reference frame.
31 const int ScreenshareLayers::kTl0Flags =
32 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF |
33 VP8_EFLAG_NO_REF_ARF;
34
35 // Allow predicting from both TL0 and TL1.
36 const int ScreenshareLayers::kTl1Flags =
37 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
38
39 // Allow predicting from only TL0 to allow participants to switch to the high
40 // bitrate stream. This means predicting only from the LAST reference frame, but
41 // only updating GF to not corrupt TL0.
42 const int ScreenshareLayers::kTl1SyncFlags =
43 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF |
44 VP8_EFLAG_NO_UPD_LAST;
45
25 ScreenshareLayers::ScreenshareLayers(int num_temporal_layers, 46 ScreenshareLayers::ScreenshareLayers(int num_temporal_layers,
26 uint8_t initial_tl0_pic_idx, 47 uint8_t initial_tl0_pic_idx)
27 FrameDropper* tl0_frame_dropper, 48 : number_of_temporal_layers_(num_temporal_layers),
28 FrameDropper* tl1_frame_dropper)
29 : tl0_frame_dropper_(tl0_frame_dropper),
30 tl1_frame_dropper_(tl1_frame_dropper),
31 number_of_temporal_layers_(num_temporal_layers),
32 last_base_layer_sync_(false), 49 last_base_layer_sync_(false),
33 tl0_pic_idx_(initial_tl0_pic_idx), 50 tl0_pic_idx_(initial_tl0_pic_idx),
34 active_layer_(0), 51 active_layer_(-1),
35 framerate_(5), 52 last_timestamp_(-1),
36 last_sync_timestamp_(-1) { 53 last_sync_timestamp_(-1),
54 min_qp_(-1),
55 max_qp_(-1),
56 max_debt_bytes_(0),
57 frame_rate_(-1) {
37 assert(num_temporal_layers > 0); 58 assert(num_temporal_layers > 0);
38 assert(num_temporal_layers <= 2); 59 assert(num_temporal_layers <= 2);
39 assert(tl0_frame_dropper && tl1_frame_dropper);
40 } 60 }
41 61
42 int ScreenshareLayers::CurrentLayerId() const { 62 int ScreenshareLayers::CurrentLayerId() const {
43 // Codec does not use temporal layers for screenshare. 63 // Codec does not use temporal layers for screenshare.
44 return 0; 64 return 0;
45 } 65 }
46 66
47 int ScreenshareLayers::EncodeFlags(uint32_t timestamp) { 67 int ScreenshareLayers::EncodeFlags(uint32_t timestamp) {
48 if (number_of_temporal_layers_ <= 1) { 68 if (number_of_temporal_layers_ <= 1) {
49 // No flags needed for 1 layer screenshare. 69 // No flags needed for 1 layer screenshare.
50 return 0; 70 return 0;
51 } 71 }
52 CalculateFramerate(timestamp); 72
73 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
53 int flags = 0; 74 int flags = 0;
54 // Note that ARF on purpose isn't used in this scheme since it is allocated 75
55 // for the last key frame to make key frame caching possible. 76 if (active_layer_ == -1 ||
56 if (tl0_frame_dropper_->DropFrame()) { 77 layers_[active_layer_].state != TemporalLayer::State::kDropped) {
57 // Must drop TL0, encode TL1 instead. 78 if (layers_[0].debt_bytes_ > max_debt_bytes_) {
58 if (tl1_frame_dropper_->DropFrame()) { 79 // Must drop TL0, encode TL1 instead.
59 // Must drop both TL0 and TL1. 80 if (layers_[1].debt_bytes_ > max_debt_bytes_) {
81 // Must drop both TL0 and TL1.
82 active_layer_ = -1;
83 } else {
84 active_layer_ = 1;
85 }
86 } else {
87 active_layer_ = 0;
88 }
89 }
90
91 switch (active_layer_) {
92 case 0:
93 flags = kTl0Flags;
94 break;
95 case 1:
96 if (TimeToSync(unwrapped_timestamp)) {
97 last_sync_timestamp_ = unwrapped_timestamp;
98 flags = kTl1SyncFlags;
99 } else {
100 flags = kTl1Flags;
101 }
102 break;
103 case -1:
60 flags = -1; 104 flags = -1;
61 } else { 105 break;
62 active_layer_ = 1; 106 default:
63 if (TimeToSync(timestamp)) { 107 flags = -1;
64 last_sync_timestamp_ = timestamp; 108 RTC_NOTREACHED();
65 // Allow predicting from only TL0 to allow participants to switch to the 109 }
66 // high bitrate stream. This means predicting only from the LAST 110
67 // reference frame, but only updating GF to not corrupt TL0. 111 // Make sure both frame droppers leak out bits.
68 flags = VP8_EFLAG_NO_REF_ARF; 112 int64_t ts_diff;
69 flags |= VP8_EFLAG_NO_REF_GF; 113 if (last_timestamp_ == -1) {
70 flags |= VP8_EFLAG_NO_UPD_ARF; 114 ts_diff = kOneSecond90Khz / (frame_rate_ <= 0 ? 5 : frame_rate_);
71 flags |= VP8_EFLAG_NO_UPD_LAST;
72 } else {
73 // Allow predicting from both TL0 and TL1.
74 flags = VP8_EFLAG_NO_REF_ARF;
75 flags |= VP8_EFLAG_NO_UPD_ARF;
76 flags |= VP8_EFLAG_NO_UPD_LAST;
77 }
78 }
79 } else { 115 } else {
80 active_layer_ = 0; 116 ts_diff = unwrapped_timestamp - last_timestamp_;
81 // Since this is TL0 we only allow updating and predicting from the LAST
82 // reference frame.
83 flags = VP8_EFLAG_NO_UPD_GF;
84 flags |= VP8_EFLAG_NO_UPD_ARF;
85 flags |= VP8_EFLAG_NO_REF_GF;
86 flags |= VP8_EFLAG_NO_REF_ARF;
87 } 117 }
88 // Make sure both frame droppers leak out bits. 118
89 tl0_frame_dropper_->Leak(framerate_); 119 layers_[0].UpdateDebt(ts_diff / 90);
90 tl1_frame_dropper_->Leak(framerate_); 120 layers_[1].UpdateDebt(ts_diff / 90);
121 last_timestamp_ = timestamp;
91 return flags; 122 return flags;
92 } 123 }
93 124
94 bool ScreenshareLayers::ConfigureBitrates(int bitrate_kbit, 125 bool ScreenshareLayers::ConfigureBitrates(int bitrate_kbps,
95 int max_bitrate_kbit, 126 int max_bitrate_kbps,
96 int framerate, 127 int framerate,
97 vpx_codec_enc_cfg_t* cfg) { 128 vpx_codec_enc_cfg_t* cfg) {
98 if (framerate > 0) 129 layers_[0].target_rate_kbps_ = bitrate_kbps;
99 framerate_ = framerate; 130 layers_[1].target_rate_kbps_ = max_bitrate_kbps;
100 131
101 tl0_frame_dropper_->SetRates(bitrate_kbit, framerate_); 132 int target_bitrate_kbps = bitrate_kbps;
102 tl1_frame_dropper_->SetRates(max_bitrate_kbit, framerate_);
103 133
104 if (cfg != nullptr) { 134 if (cfg != nullptr) {
105 // Calculate a codec target bitrate. This may be higher than TL0, gaining 135 // Calculate a codec target bitrate. This may be higher than TL0, gaining
106 // quality at the expense of frame rate at TL0. Constraints: 136 // quality at the expense of frame rate at TL0. Constraints:
107 // - TL0 frame rate should not be less than framerate / kMaxTL0FpsReduction. 137 // - TL0 frame rate should not be less than framerate / kMaxTL0FpsReduction.
108 // - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate. 138 // - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate.
109 double target_bitrate = 139 target_bitrate_kbps =
110 std::min(bitrate_kbit * kMaxTL0FpsReduction, 140 std::min(bitrate_kbps * kMaxTL0FpsReduction,
111 max_bitrate_kbit / kAcceptableTargetOvershoot); 141 max_bitrate_kbps / kAcceptableTargetOvershoot);
112 cfg->rc_target_bitrate = 142
113 std::max(static_cast<unsigned int>(bitrate_kbit), 143 // Don't reconfigure qp limits during quality boost frames.
114 static_cast<unsigned int>(target_bitrate + 0.5)); 144 if (layers_[active_layer_].state != TemporalLayer::State::kQualityBoost) {
145 min_qp_ = cfg->rc_min_quantizer;
146 max_qp_ = cfg->rc_max_quantizer;
147 // After a dropped frame, a frame with max qp will be encoded and the
148 // quality will then ramp up from there. To boost the speed of recovery,
149 // encode the next frame with lower max qp. TL0 is the most important to
150 // improve since the errors in this layer will propagate to TL1.
151 // Currently, reduce max qp by 20% for TL0 and 15% for TL1.
152 layers_[0].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
153 layers_[1].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
154 }
155
156 cfg->rc_target_bitrate = std::max(bitrate_kbps, target_bitrate_kbps);
115 } 157 }
116 158
159 int avg_frame_size = (target_bitrate_kbps * 1000) / (8 * framerate);
160 max_debt_bytes_ = 4 * avg_frame_size;
161
117 return true; 162 return true;
118 } 163 }
119 164
120 void ScreenshareLayers::FrameEncoded(unsigned int size, uint32_t timestamp) { 165 void ScreenshareLayers::FrameEncoded(unsigned int size,
166 uint32_t timestamp,
167 int qp) {
168 if (size == 0) {
169 layers_[active_layer_].state = TemporalLayer::State::kDropped;
170 return;
171 }
172 if (layers_[active_layer_].state == TemporalLayer::State::kDropped) {
173 layers_[active_layer_].state = TemporalLayer::State::kQualityBoost;
174 }
175
176 if (qp != -1)
177 layers_[active_layer_].last_qp = qp;
178
121 if (active_layer_ == 0) { 179 if (active_layer_ == 0) {
122 tl0_frame_dropper_->Fill(size, true); 180 layers_[0].debt_bytes_ += size;
181 layers_[1].debt_bytes_ += size;
182 } else if (active_layer_ == 1) {
183 layers_[1].debt_bytes_ += size;
123 } 184 }
124 tl1_frame_dropper_->Fill(size, true);
125 } 185 }
126 186
127 void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync, 187 void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync,
128 CodecSpecificInfoVP8 *vp8_info, 188 CodecSpecificInfoVP8 *vp8_info,
129 uint32_t timestamp) { 189 uint32_t timestamp) {
190 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
130 if (number_of_temporal_layers_ == 1) { 191 if (number_of_temporal_layers_ == 1) {
131 vp8_info->temporalIdx = kNoTemporalIdx; 192 vp8_info->temporalIdx = kNoTemporalIdx;
132 vp8_info->layerSync = false; 193 vp8_info->layerSync = false;
133 vp8_info->tl0PicIdx = kNoTl0PicIdx; 194 vp8_info->tl0PicIdx = kNoTl0PicIdx;
134 } else { 195 } else {
135 vp8_info->temporalIdx = active_layer_; 196 vp8_info->temporalIdx = active_layer_;
136 if (base_layer_sync) { 197 if (base_layer_sync) {
137 vp8_info->temporalIdx = 0; 198 vp8_info->temporalIdx = 0;
138 last_sync_timestamp_ = timestamp; 199 last_sync_timestamp_ = unwrapped_timestamp;
139 } else if (last_base_layer_sync_ && vp8_info->temporalIdx != 0) { 200 } else if (last_base_layer_sync_ && vp8_info->temporalIdx != 0) {
140 // Regardless of pattern the frame after a base layer sync will always 201 // Regardless of pattern the frame after a base layer sync will always
141 // be a layer sync. 202 // be a layer sync.
142 last_sync_timestamp_ = timestamp; 203 last_sync_timestamp_ = unwrapped_timestamp;
143 } 204 }
144 vp8_info->layerSync = (last_sync_timestamp_ == timestamp); 205 vp8_info->layerSync = last_sync_timestamp_ != -1 &&
206 last_sync_timestamp_ == unwrapped_timestamp;
145 if (vp8_info->temporalIdx == 0) { 207 if (vp8_info->temporalIdx == 0) {
146 tl0_pic_idx_++; 208 tl0_pic_idx_++;
147 } 209 }
148 last_base_layer_sync_ = base_layer_sync; 210 last_base_layer_sync_ = base_layer_sync;
149 vp8_info->tl0PicIdx = tl0_pic_idx_; 211 vp8_info->tl0PicIdx = tl0_pic_idx_;
150 } 212 }
151 } 213 }
152 214
153 bool ScreenshareLayers::TimeToSync(uint32_t timestamp) const { 215 bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
154 const uint32_t timestamp_diff = timestamp - last_sync_timestamp_; 216 if (active_layer_ != 1) {
155 return last_sync_timestamp_ < 0 || timestamp_diff > kOneSecond90Khz; 217 RTC_NOTREACHED();
218 return false;
219 }
220 DCHECK_NE(-1, layers_[0].last_qp);
221 if (layers_[1].last_qp == -1) {
222 // First frame in TL1 should only depend on TL0 since there are no
223 // previous frames in TL1.
224 return true;
225 }
226
227 DCHECK_NE(-1, last_sync_timestamp_);
228 int64_t timestamp_diff = timestamp - last_sync_timestamp_;
229 if (timestamp_diff > kMaxTimeBetweenSyncs) {
230 // After a certain time, force a sync frame.
231 return true;
232 } else if (timestamp_diff < kMinTimeBetweenSyncs) {
233 // If too soon from previous sync frame, don't issue a new one.
234 return false;
235 }
236 // Issue a sync frame if difference in quality between TL0 and TL1 isn't too
237 // large.
238 if (layers_[0].last_qp - layers_[1].last_qp < kQpDeltaThresholdForSync)
239 return true;
240 return false;
156 } 241 }
157 242
158 void ScreenshareLayers::CalculateFramerate(uint32_t timestamp) { 243 bool ScreenshareLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) {
159 timestamp_list_.push_front(timestamp); 244 if (max_qp_ == -1)
160 // Remove timestamps older than 1 second from the list. 245 return false;
161 uint32_t timestamp_diff = timestamp - timestamp_list_.back(); 246
162 while (timestamp_diff > kOneSecond90Khz) { 247 // If layer is in the quality boost state (following a dropped frame), update
163 timestamp_list_.pop_back(); 248 // the configuration with the adjusted (lower) qp and set the state back to
164 timestamp_diff = timestamp - timestamp_list_.back(); 249 // normal.
250 unsigned int adjusted_max_qp;
251 if (layers_[active_layer_].state == TemporalLayer::State::kQualityBoost &&
252 layers_[active_layer_].enhanced_max_qp != -1) {
253 adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
254 layers_[active_layer_].state = TemporalLayer::State::kNormal;
255 } else {
256 if (max_qp_ == -1)
257 return false;
258 adjusted_max_qp = max_qp_; // Set the normal max qp.
165 } 259 }
166 // If we have encoded frames within the last second, that number of frames 260
167 // is a reasonable first estimate of the framerate. 261 if (adjusted_max_qp == cfg->rc_max_quantizer)
168 framerate_ = timestamp_list_.size(); 262 return false;
169 if (timestamp_diff > 0) { 263
170 // Estimate the framerate by dividing the number of timestamp diffs with 264 cfg->rc_max_quantizer = adjusted_max_qp;
171 // the sum of the timestamp diffs (with rounding). 265 return true;
172 framerate_ = (kOneSecond90Khz * (timestamp_list_.size() - 1) + 266 }
173 timestamp_diff / 2) / timestamp_diff; 267
268 void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) {
269 uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8;
270 if (debt_reduction_bytes >= debt_bytes_) {
271 debt_bytes_ = 0;
272 } else {
273 debt_bytes_ -= debt_reduction_bytes;
174 } 274 }
175 } 275 }
176 276
177 } // namespace webrtc 277 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698