OLD | NEW |
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 |
OLD | NEW |