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

Side by Side Diff: webrtc/modules/video_coding/protection_bitrate_calculator.cc

Issue 1972083002: Move logic for calculating needed bitrate overhead used by NACK and FEC to VideoSender. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Removed video_sender_unittest for now. 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
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698