Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include <webrtc/modules/video_coding/protection_bitrate_calculator.h> | |
| 12 | |
| 13 namespace webrtc { | |
| 14 | |
| 15 using rtc::CritScope; | |
| 16 | |
| 17 struct ProtectionBitrateCalculator::EncodedFrameSample { | |
| 18 EncodedFrameSample(size_t size_bytes, | |
| 19 uint32_t timestamp, | |
| 20 int64_t time_complete_ms) | |
| 21 : size_bytes(size_bytes), | |
| 22 timestamp(timestamp), | |
| 23 time_complete_ms(time_complete_ms) {} | |
| 24 size_t size_bytes; | |
| 25 uint32_t timestamp; | |
| 26 int64_t time_complete_ms; | |
| 27 }; | |
| 28 | |
| 29 ProtectionBitrateCalculator::ProtectionBitrateCalculator( | |
| 30 Clock* clock, | |
| 31 VCMProtectionCallback* protection_callback) | |
| 32 : clock_(clock), | |
| 33 protection_callback_(protection_callback), | |
| 34 loss_prot_logic_(new media_optimization::VCMLossProtectionLogic( | |
| 35 clock_->TimeInMilliseconds())), | |
| 36 max_payload_size_(1460), | |
| 37 encoded_frame_samples_(), | |
| 38 avg_sent_bit_rate_bps_(0), | |
| 39 avg_sent_framerate_(0) {} | |
| 40 | |
| 41 ProtectionBitrateCalculator::~ProtectionBitrateCalculator(void) { | |
| 42 loss_prot_logic_->Release(); | |
| 43 } | |
| 44 | |
| 45 void ProtectionBitrateCalculator::SetEncodingData(uint32_t target_bitrate, | |
| 46 uint16_t width, | |
| 47 uint16_t height, | |
| 48 uint32_t frame_rate, | |
| 49 size_t num_layers, | |
| 50 size_t mtu) { | |
|
stefan-webrtc
2016/05/19 12:52:39
Call this max_payload_size instead.
perkj_webrtc
2016/06/01 20:55:23
Done.
| |
| 51 CritScope lock(&crit_sect_); | |
| 52 // Everything codec specific should be reset here since this means the codec | |
| 53 // has changed. | |
| 54 float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f; | |
| 55 loss_prot_logic_->UpdateBitRate(target_bitrate_kbps); | |
| 56 loss_prot_logic_->UpdateFrameRate(static_cast<float>(frame_rate)); | |
| 57 loss_prot_logic_->UpdateFrameSize(width, height); | |
| 58 loss_prot_logic_->UpdateNumLayers(num_layers); | |
| 59 max_payload_size_ = mtu; | |
| 60 } | |
| 61 | |
| 62 uint32_t ProtectionBitrateCalculator::SetTargetRates( | |
| 63 uint32_t target_bitrate, | |
|
stefan-webrtc
2016/05/19 12:52:39
add unit
perkj_webrtc
2016/06/01 20:55:23
Done.
| |
| 64 uint8_t fraction_lost, | |
| 65 int64_t round_trip_time_ms) { | |
| 66 crit_sect_.Enter(); | |
|
stefan-webrtc
2016/05/19 12:52:39
Change to use a scoped crit
perkj_webrtc
2016/06/01 20:55:23
ok- but I then have to move a few things around th
| |
| 67 | |
| 68 float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f; | |
| 69 loss_prot_logic_->UpdateBitRate(target_bitrate_kbps); | |
| 70 loss_prot_logic_->UpdateRtt(round_trip_time_ms); | |
| 71 | |
| 72 // Get frame rate for encoder: this is the actual/sent frame rate. | |
| 73 float actual_frame_rate = SentFrameRateInternal(); | |
| 74 | |
| 75 // Sanity check. | |
| 76 if (actual_frame_rate < 1.0) { | |
| 77 actual_frame_rate = 1.0; | |
| 78 } | |
| 79 | |
| 80 // Update frame rate for the loss protection logic class: frame rate should | |
| 81 // be the actual/sent rate. | |
| 82 loss_prot_logic_->UpdateFrameRate(actual_frame_rate); | |
| 83 | |
| 84 // Returns the filtered packet loss, used for the protection setting. | |
| 85 // The filtered loss may be the received loss (no filter), or some | |
| 86 // filtered value (average or max window filter). | |
| 87 // Use max window filter for now. | |
| 88 media_optimization::FilterPacketLossMode filter_mode = | |
| 89 media_optimization::kMaxFilter; | |
| 90 uint8_t packet_loss_enc = loss_prot_logic_->FilteredLoss( | |
| 91 clock_->TimeInMilliseconds(), filter_mode, fraction_lost); | |
| 92 | |
| 93 // For now use the filtered loss for computing the robustness settings. | |
| 94 loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc); | |
| 95 | |
| 96 // Rate cost of the protection methods. | |
| 97 float protection_overhead_rate = 0.0f; | |
| 98 | |
| 99 if (loss_prot_logic_->SelectedType() == media_optimization::kNone) { | |
| 100 crit_sect_.Leave(); | |
| 101 return target_bitrate; | |
| 102 } | |
| 103 | |
| 104 // Update method will compute the robustness settings for the given | |
| 105 // protection method and the overhead cost | |
| 106 // the protection method is set by the user via SetVideoProtection. | |
| 107 loss_prot_logic_->UpdateMethod(); | |
| 108 | |
| 109 // Update protection callback with protection settings. | |
| 110 uint32_t sent_video_rate_bps = 0; | |
| 111 uint32_t sent_nack_rate_bps = 0; | |
| 112 uint32_t sent_fec_rate_bps = 0; | |
| 113 | |
| 114 // Get the bit cost of protection method, based on the amount of | |
| 115 // overhead data actually transmitted (including headers) the last | |
| 116 // second. | |
| 117 FecProtectionParams delta_fec_params; | |
| 118 FecProtectionParams key_fec_params; | |
| 119 // Get the FEC code rate for Key frames (set to 0 when NA). | |
| 120 key_fec_params.fec_rate = | |
| 121 loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorK(); | |
| 122 | |
| 123 // Get the FEC code rate for Delta frames (set to 0 when NA). | |
| 124 delta_fec_params.fec_rate = | |
| 125 loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorD(); | |
| 126 | |
| 127 // The RTP module currently requires the same |max_fec_frames| for both | |
| 128 // key and delta frames. | |
| 129 delta_fec_params.max_fec_frames = | |
| 130 loss_prot_logic_->SelectedMethod()->MaxFramesFec(); | |
| 131 key_fec_params.max_fec_frames = | |
| 132 loss_prot_logic_->SelectedMethod()->MaxFramesFec(); | |
| 133 | |
| 134 // Set the FEC packet mask type. |kFecMaskBursty| is more effective for | |
| 135 // consecutive losses and little/no packet re-ordering. As we currently | |
| 136 // do not have feedback data on the degree of correlated losses and packet | |
| 137 // re-ordering, we keep default setting to |kFecMaskRandom| for now. | |
| 138 delta_fec_params.fec_mask_type = kFecMaskRandom; | |
| 139 key_fec_params.fec_mask_type = kFecMaskRandom; | |
| 140 | |
| 141 crit_sect_.Leave(); | |
| 142 | |
| 143 // TODO(Marco): Pass FEC protection values per layer. | |
| 144 protection_callback_->ProtectionRequest( | |
| 145 &delta_fec_params, &key_fec_params, &sent_video_rate_bps, | |
| 146 &sent_nack_rate_bps, &sent_fec_rate_bps); | |
| 147 | |
| 148 uint32_t sent_total_rate_bps = | |
| 149 sent_video_rate_bps + sent_nack_rate_bps + sent_fec_rate_bps; | |
| 150 // Estimate the overhead costs of the next second as staying the same | |
| 151 // wrt the source bitrate. | |
| 152 if (sent_total_rate_bps > 0) { | |
| 153 protection_overhead_rate = | |
| 154 static_cast<float>(sent_nack_rate_bps + sent_fec_rate_bps) / | |
| 155 sent_total_rate_bps; | |
| 156 } | |
| 157 // Cap the overhead estimate to 50%. | |
| 158 if (protection_overhead_rate > 0.5) | |
| 159 protection_overhead_rate = 0.5; | |
| 160 | |
| 161 // Source coding rate: total rate - protection overhead. | |
| 162 return target_bitrate * (1.0 - protection_overhead_rate); | |
| 163 } | |
| 164 | |
| 165 void ProtectionBitrateCalculator::SetProtectionMethod(bool enable_fec, | |
| 166 bool enable_nack) { | |
| 167 media_optimization::VCMProtectionMethodEnum method(media_optimization::kNone); | |
| 168 if (enable_fec && enable_nack) { | |
| 169 method = media_optimization::kNackFec; | |
| 170 } else if (enable_nack) { | |
| 171 method = media_optimization::kNack; | |
| 172 } else if (enable_fec) { | |
| 173 method = media_optimization::kFec; | |
| 174 } | |
| 175 CritScope lock(&crit_sect_); | |
| 176 loss_prot_logic_->SetMethod(method); | |
| 177 } | |
| 178 | |
| 179 uint32_t ProtectionBitrateCalculator::SentFrameRate() { | |
| 180 CritScope lock(&crit_sect_); | |
| 181 return SentFrameRateInternal(); | |
| 182 } | |
| 183 | |
| 184 uint32_t ProtectionBitrateCalculator::SentFrameRateInternal() { | |
| 185 PurgeOldFrameSamples(clock_->TimeInMilliseconds()); | |
| 186 UpdateSentFramerate(); | |
| 187 return avg_sent_framerate_; | |
| 188 } | |
| 189 | |
| 190 uint32_t ProtectionBitrateCalculator::SentBitRate() { | |
| 191 CritScope lock(&crit_sect_); | |
| 192 const int64_t now_ms = clock_->TimeInMilliseconds(); | |
| 193 PurgeOldFrameSamples(now_ms); | |
| 194 UpdateSentBitrate(now_ms); | |
| 195 return avg_sent_bit_rate_bps_; | |
| 196 } | |
| 197 | |
| 198 void ProtectionBitrateCalculator::UpdateWithEncodedData( | |
| 199 const EncodedImage& encoded_image) { | |
| 200 size_t encoded_length = encoded_image._length; | |
| 201 uint32_t timestamp = encoded_image._timeStamp; | |
| 202 CritScope lock(&crit_sect_); | |
| 203 const int64_t now_ms = clock_->TimeInMilliseconds(); | |
| 204 PurgeOldFrameSamples(now_ms); | |
| 205 if (encoded_frame_samples_.size() > 0 && | |
| 206 encoded_frame_samples_.back().timestamp == timestamp) { | |
| 207 // Frames having the same timestamp are generated from the same input | |
| 208 // frame. We don't want to double count them, but only increment the | |
| 209 // size_bytes. | |
| 210 encoded_frame_samples_.back().size_bytes += encoded_length; | |
| 211 encoded_frame_samples_.back().time_complete_ms = now_ms; | |
| 212 } else { | |
| 213 encoded_frame_samples_.push_back( | |
| 214 EncodedFrameSample(encoded_length, timestamp, now_ms)); | |
| 215 } | |
| 216 UpdateSentBitrate(now_ms); | |
| 217 UpdateSentFramerate(); | |
| 218 if (encoded_length > 0) { | |
| 219 const bool delta_frame = encoded_image._frameType != kVideoFrameKey; | |
| 220 | |
| 221 if (max_payload_size_ > 0 && encoded_length > 0) { | |
| 222 const float min_packets_per_frame = | |
| 223 encoded_length / static_cast<float>(max_payload_size_); | |
| 224 if (delta_frame) { | |
| 225 loss_prot_logic_->UpdatePacketsPerFrame(min_packets_per_frame, | |
| 226 clock_->TimeInMilliseconds()); | |
| 227 } else { | |
| 228 loss_prot_logic_->UpdatePacketsPerFrameKey( | |
| 229 min_packets_per_frame, clock_->TimeInMilliseconds()); | |
| 230 } | |
| 231 } | |
| 232 if (!delta_frame && encoded_length > 0) { | |
| 233 loss_prot_logic_->UpdateKeyFrameSize(static_cast<float>(encoded_length)); | |
| 234 } | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 void ProtectionBitrateCalculator::PurgeOldFrameSamples(int64_t now_ms) { | |
| 239 while (!encoded_frame_samples_.empty()) { | |
| 240 if (now_ms - encoded_frame_samples_.front().time_complete_ms > | |
| 241 kBitrateAverageWinMs) { | |
| 242 encoded_frame_samples_.pop_front(); | |
| 243 } else { | |
| 244 break; | |
| 245 } | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 void ProtectionBitrateCalculator::UpdateSentBitrate(int64_t now_ms) { | |
| 250 if (encoded_frame_samples_.empty()) { | |
| 251 avg_sent_bit_rate_bps_ = 0; | |
| 252 return; | |
| 253 } | |
| 254 size_t framesize_sum = 0; | |
| 255 for (const auto& encoded_sample : encoded_frame_samples_) { | |
| 256 framesize_sum += encoded_sample.size_bytes; | |
| 257 } | |
| 258 float denom = static_cast<float>( | |
| 259 now_ms - encoded_frame_samples_.front().time_complete_ms); | |
| 260 if (denom >= 1.0f) { | |
| 261 avg_sent_bit_rate_bps_ = | |
| 262 static_cast<uint32_t>(framesize_sum * 8.0f * 1000.0f / denom + 0.5f); | |
| 263 } else { | |
| 264 avg_sent_bit_rate_bps_ = framesize_sum * 8; | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 void ProtectionBitrateCalculator::UpdateSentFramerate() { | |
| 269 if (encoded_frame_samples_.size() <= 1) { | |
| 270 avg_sent_framerate_ = encoded_frame_samples_.size(); | |
| 271 return; | |
| 272 } | |
| 273 int denom = encoded_frame_samples_.back().timestamp - | |
| 274 encoded_frame_samples_.front().timestamp; | |
| 275 if (denom > 0) { | |
| 276 avg_sent_framerate_ = | |
| 277 (90000 * (encoded_frame_samples_.size() - 1) + denom / 2) / denom; | |
| 278 } else { | |
| 279 avg_sent_framerate_ = encoded_frame_samples_.size(); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 } // namespace webrtc | |
| OLD | NEW |