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 |