OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/video_coding/media_optimization.h" | 11 #include "webrtc/modules/video_coding/media_optimization.h" |
12 | 12 |
13 #include "webrtc/base/logging.h" | 13 #include "webrtc/base/logging.h" |
14 #include "webrtc/modules/video_coding/utility/frame_dropper.h" | 14 #include "webrtc/modules/video_coding/utility/frame_dropper.h" |
15 #include "webrtc/system_wrappers/include/clock.h" | 15 #include "webrtc/system_wrappers/include/clock.h" |
16 | 16 |
17 namespace webrtc { | 17 namespace webrtc { |
18 namespace media_optimization { | 18 namespace media_optimization { |
19 namespace { | |
20 void UpdateProtectionCallback( | |
21 VCMProtectionMethod* selected_method, | |
22 uint32_t* video_rate_bps, | |
23 uint32_t* nack_overhead_rate_bps, | |
24 uint32_t* fec_overhead_rate_bps, | |
25 VCMProtectionCallback* video_protection_callback) { | |
26 FecProtectionParams delta_fec_params; | |
27 FecProtectionParams key_fec_params; | |
28 // Get the FEC code rate for Key frames (set to 0 when NA). | |
29 key_fec_params.fec_rate = selected_method->RequiredProtectionFactorK(); | |
30 | |
31 // Get the FEC code rate for Delta frames (set to 0 when NA). | |
32 delta_fec_params.fec_rate = selected_method->RequiredProtectionFactorD(); | |
33 | |
34 // The RTP module currently requires the same |max_fec_frames| for both | |
35 // key and delta frames. | |
36 delta_fec_params.max_fec_frames = selected_method->MaxFramesFec(); | |
37 key_fec_params.max_fec_frames = selected_method->MaxFramesFec(); | |
38 | |
39 // Set the FEC packet mask type. |kFecMaskBursty| is more effective for | |
40 // consecutive losses and little/no packet re-ordering. As we currently | |
41 // do not have feedback data on the degree of correlated losses and packet | |
42 // re-ordering, we keep default setting to |kFecMaskRandom| for now. | |
43 delta_fec_params.fec_mask_type = kFecMaskRandom; | |
44 key_fec_params.fec_mask_type = kFecMaskRandom; | |
45 | |
46 // TODO(Marco): Pass FEC protection values per layer. | |
47 video_protection_callback->ProtectionRequest( | |
48 &delta_fec_params, &key_fec_params, video_rate_bps, | |
49 nack_overhead_rate_bps, fec_overhead_rate_bps); | |
50 } | |
51 } // namespace | |
52 | 19 |
53 struct MediaOptimization::EncodedFrameSample { | 20 struct MediaOptimization::EncodedFrameSample { |
54 EncodedFrameSample(size_t size_bytes, | 21 EncodedFrameSample(size_t size_bytes, |
55 uint32_t timestamp, | 22 uint32_t timestamp, |
56 int64_t time_complete_ms) | 23 int64_t time_complete_ms) |
57 : size_bytes(size_bytes), | 24 : size_bytes(size_bytes), |
58 timestamp(timestamp), | 25 timestamp(timestamp), |
59 time_complete_ms(time_complete_ms) {} | 26 time_complete_ms(time_complete_ms) {} |
60 | 27 |
61 size_t size_bytes; | 28 size_t size_bytes; |
62 uint32_t timestamp; | 29 uint32_t timestamp; |
63 int64_t time_complete_ms; | 30 int64_t time_complete_ms; |
64 }; | 31 }; |
65 | 32 |
66 MediaOptimization::MediaOptimization(Clock* clock) | 33 MediaOptimization::MediaOptimization(Clock* clock) |
67 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 34 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), |
68 clock_(clock), | 35 clock_(clock), |
69 max_bit_rate_(0), | 36 max_bit_rate_(0), |
70 send_codec_type_(kVideoCodecUnknown), | |
71 codec_width_(0), | 37 codec_width_(0), |
72 codec_height_(0), | 38 codec_height_(0), |
73 user_frame_rate_(0), | 39 user_frame_rate_(0), |
74 frame_dropper_(new FrameDropper), | 40 frame_dropper_(new FrameDropper), |
75 loss_prot_logic_( | |
76 new VCMLossProtectionLogic(clock_->TimeInMilliseconds())), | |
77 fraction_lost_(0), | 41 fraction_lost_(0), |
78 send_statistics_zero_encode_(0), | 42 send_statistics_zero_encode_(0), |
79 max_payload_size_(1460), | 43 max_payload_size_(1460), |
80 video_target_bitrate_(0), | 44 video_target_bitrate_(0), |
81 incoming_frame_rate_(0), | 45 incoming_frame_rate_(0), |
82 encoded_frame_samples_(), | 46 encoded_frame_samples_(), |
83 avg_sent_bit_rate_bps_(0), | 47 avg_sent_bit_rate_bps_(0), |
84 avg_sent_framerate_(0), | 48 avg_sent_framerate_(0), |
85 key_frame_cnt_(0), | |
86 delta_frame_cnt_(0), | |
87 num_layers_(0), | 49 num_layers_(0), |
88 suspension_enabled_(false), | 50 suspension_enabled_(false), |
89 video_suspended_(false), | 51 video_suspended_(false), |
90 suspension_threshold_bps_(0), | 52 suspension_threshold_bps_(0), |
91 suspension_window_bps_(0) { | 53 suspension_window_bps_(0) { |
92 memset(send_statistics_, 0, sizeof(send_statistics_)); | 54 memset(send_statistics_, 0, sizeof(send_statistics_)); |
93 memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_)); | 55 memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_)); |
94 } | 56 } |
95 | 57 |
96 MediaOptimization::~MediaOptimization(void) { | 58 MediaOptimization::~MediaOptimization(void) { |
97 loss_prot_logic_->Release(); | |
98 } | 59 } |
99 | 60 |
100 void MediaOptimization::Reset() { | 61 void MediaOptimization::Reset() { |
101 CriticalSectionScoped lock(crit_sect_.get()); | 62 CriticalSectionScoped lock(crit_sect_.get()); |
102 SetEncodingDataInternal(kVideoCodecUnknown, 0, 0, 0, 0, 0, 0, | 63 SetEncodingDataInternal(0, 0, 0, 0, 0, 0, max_payload_size_); |
103 max_payload_size_); | |
104 memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_)); | 64 memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_)); |
105 incoming_frame_rate_ = 0.0; | 65 incoming_frame_rate_ = 0.0; |
106 frame_dropper_->Reset(); | 66 frame_dropper_->Reset(); |
107 loss_prot_logic_->Reset(clock_->TimeInMilliseconds()); | |
108 frame_dropper_->SetRates(0, 0); | 67 frame_dropper_->SetRates(0, 0); |
109 loss_prot_logic_->UpdateFrameRate(incoming_frame_rate_); | |
110 loss_prot_logic_->Reset(clock_->TimeInMilliseconds()); | |
111 send_statistics_zero_encode_ = 0; | 68 send_statistics_zero_encode_ = 0; |
112 video_target_bitrate_ = 0; | 69 video_target_bitrate_ = 0; |
113 codec_width_ = 0; | 70 codec_width_ = 0; |
114 codec_height_ = 0; | 71 codec_height_ = 0; |
115 user_frame_rate_ = 0; | 72 user_frame_rate_ = 0; |
116 key_frame_cnt_ = 0; | |
117 delta_frame_cnt_ = 0; | |
118 encoded_frame_samples_.clear(); | 73 encoded_frame_samples_.clear(); |
119 avg_sent_bit_rate_bps_ = 0; | 74 avg_sent_bit_rate_bps_ = 0; |
120 num_layers_ = 1; | 75 num_layers_ = 1; |
121 } | 76 } |
122 | 77 |
123 void MediaOptimization::SetEncodingData(VideoCodecType send_codec_type, | 78 void MediaOptimization::SetEncodingData(int32_t max_bit_rate, |
124 int32_t max_bit_rate, | |
125 uint32_t target_bitrate, | 79 uint32_t target_bitrate, |
126 uint16_t width, | 80 uint16_t width, |
127 uint16_t height, | 81 uint16_t height, |
128 uint32_t frame_rate, | 82 uint32_t frame_rate, |
129 int num_layers, | 83 int num_layers, |
130 int32_t mtu) { | 84 int32_t mtu) { |
131 CriticalSectionScoped lock(crit_sect_.get()); | 85 CriticalSectionScoped lock(crit_sect_.get()); |
132 SetEncodingDataInternal(send_codec_type, max_bit_rate, frame_rate, | 86 SetEncodingDataInternal(max_bit_rate, frame_rate, target_bitrate, width, |
133 target_bitrate, width, height, num_layers, mtu); | 87 height, num_layers, mtu); |
134 } | 88 } |
135 | 89 |
136 void MediaOptimization::SetEncodingDataInternal(VideoCodecType send_codec_type, | 90 void MediaOptimization::SetEncodingDataInternal(int32_t max_bit_rate, |
137 int32_t max_bit_rate, | |
138 uint32_t frame_rate, | 91 uint32_t frame_rate, |
139 uint32_t target_bitrate, | 92 uint32_t target_bitrate, |
140 uint16_t width, | 93 uint16_t width, |
141 uint16_t height, | 94 uint16_t height, |
142 int num_layers, | 95 int num_layers, |
143 int32_t mtu) { | 96 int32_t mtu) { |
144 // Everything codec specific should be reset here since this means the codec | 97 // Everything codec specific should be reset here since this means the codec |
145 // has changed. | 98 // has changed. |
146 | 99 |
147 max_bit_rate_ = max_bit_rate; | 100 max_bit_rate_ = max_bit_rate; |
148 send_codec_type_ = send_codec_type; | |
149 video_target_bitrate_ = target_bitrate; | 101 video_target_bitrate_ = target_bitrate; |
150 float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f; | 102 float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f; |
151 loss_prot_logic_->UpdateBitRate(target_bitrate_kbps); | |
152 loss_prot_logic_->UpdateFrameRate(static_cast<float>(frame_rate)); | |
153 loss_prot_logic_->UpdateFrameSize(width, height); | |
154 loss_prot_logic_->UpdateNumLayers(num_layers); | |
155 frame_dropper_->Reset(); | 103 frame_dropper_->Reset(); |
156 frame_dropper_->SetRates(target_bitrate_kbps, static_cast<float>(frame_rate)); | 104 frame_dropper_->SetRates(target_bitrate_kbps, static_cast<float>(frame_rate)); |
157 user_frame_rate_ = static_cast<float>(frame_rate); | 105 user_frame_rate_ = static_cast<float>(frame_rate); |
158 codec_width_ = width; | 106 codec_width_ = width; |
159 codec_height_ = height; | 107 codec_height_ = height; |
160 num_layers_ = (num_layers <= 1) ? 1 : num_layers; // Can also be zero. | 108 num_layers_ = (num_layers <= 1) ? 1 : num_layers; // Can also be zero. |
161 max_payload_size_ = mtu; | 109 max_payload_size_ = mtu; |
162 } | 110 } |
163 | 111 |
164 uint32_t MediaOptimization::SetTargetRates( | 112 uint32_t MediaOptimization::SetTargetRates(uint32_t target_bitrate, |
165 uint32_t target_bitrate, | 113 uint8_t fraction_lost, |
166 uint8_t fraction_lost, | 114 int64_t round_trip_time_ms) { |
167 int64_t round_trip_time_ms, | |
168 VCMProtectionCallback* protection_callback) { | |
169 CriticalSectionScoped lock(crit_sect_.get()); | 115 CriticalSectionScoped lock(crit_sect_.get()); |
170 VCMProtectionMethod* selected_method = loss_prot_logic_->SelectedMethod(); | |
171 float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f; | |
172 loss_prot_logic_->UpdateBitRate(target_bitrate_kbps); | |
173 loss_prot_logic_->UpdateRtt(round_trip_time_ms); | |
174 | 116 |
175 // Get frame rate for encoder: this is the actual/sent frame rate. | 117 // Get frame rate for encoder: this is the actual/sent frame rate. |
176 float actual_frame_rate = SentFrameRateInternal(); | 118 float actual_frame_rate = SentFrameRateInternal(); |
177 | 119 |
178 // Sanity check. | 120 // Sanity check. |
179 if (actual_frame_rate < 1.0) { | 121 if (actual_frame_rate < 1.0) { |
180 actual_frame_rate = 1.0; | 122 actual_frame_rate = 1.0; |
181 } | 123 } |
182 | 124 |
183 // Update frame rate for the loss protection logic class: frame rate should | |
184 // be the actual/sent rate. | |
185 loss_prot_logic_->UpdateFrameRate(actual_frame_rate); | |
186 | |
187 fraction_lost_ = fraction_lost; | 125 fraction_lost_ = fraction_lost; |
188 | 126 |
189 // Returns the filtered packet loss, used for the protection setting. | 127 video_target_bitrate_ = target_bitrate; |
190 // The filtered loss may be the received loss (no filter), or some | |
191 // filtered value (average or max window filter). | |
192 // Use max window filter for now. | |
193 FilterPacketLossMode filter_mode = kMaxFilter; | |
194 uint8_t packet_loss_enc = loss_prot_logic_->FilteredLoss( | |
195 clock_->TimeInMilliseconds(), filter_mode, fraction_lost); | |
196 | |
197 // For now use the filtered loss for computing the robustness settings. | |
198 loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc); | |
199 | |
200 // Rate cost of the protection methods. | |
201 float protection_overhead_rate = 0.0f; | |
202 | |
203 // Update protection settings, when applicable. | |
204 if (loss_prot_logic_->SelectedType() != kNone) { | |
205 // Update method will compute the robustness settings for the given | |
206 // protection method and the overhead cost | |
207 // the protection method is set by the user via SetVideoProtection. | |
208 loss_prot_logic_->UpdateMethod(); | |
209 | |
210 // Update protection callback with protection settings. | |
211 uint32_t sent_video_rate_bps = 0; | |
212 uint32_t sent_nack_rate_bps = 0; | |
213 uint32_t sent_fec_rate_bps = 0; | |
214 // Get the bit cost of protection method, based on the amount of | |
215 // overhead data actually transmitted (including headers) the last | |
216 // second. | |
217 if (protection_callback) { | |
218 UpdateProtectionCallback(selected_method, &sent_video_rate_bps, | |
219 &sent_nack_rate_bps, &sent_fec_rate_bps, | |
220 protection_callback); | |
221 } | |
222 uint32_t sent_total_rate_bps = | |
223 sent_video_rate_bps + sent_nack_rate_bps + sent_fec_rate_bps; | |
224 // Estimate the overhead costs of the next second as staying the same | |
225 // wrt the source bitrate. | |
226 if (sent_total_rate_bps > 0) { | |
227 protection_overhead_rate = | |
228 static_cast<float>(sent_nack_rate_bps + sent_fec_rate_bps) / | |
229 sent_total_rate_bps; | |
230 } | |
231 // Cap the overhead estimate to 50%. | |
232 if (protection_overhead_rate > 0.5) | |
233 protection_overhead_rate = 0.5; | |
234 | |
235 // Get the effective packet loss for encoder ER when applicable. Should be | |
236 // passed to encoder via fraction_lost. | |
237 packet_loss_enc = selected_method->RequiredPacketLossER(); | |
238 } | |
239 | |
240 // Source coding rate: total rate - protection overhead. | |
241 video_target_bitrate_ = target_bitrate * (1.0 - protection_overhead_rate); | |
242 | 128 |
243 // Cap target video bitrate to codec maximum. | 129 // Cap target video bitrate to codec maximum. |
244 if (max_bit_rate_ > 0 && video_target_bitrate_ > max_bit_rate_) { | 130 if (max_bit_rate_ > 0 && video_target_bitrate_ > max_bit_rate_) { |
245 video_target_bitrate_ = max_bit_rate_; | 131 video_target_bitrate_ = max_bit_rate_; |
246 } | 132 } |
247 | 133 |
248 // Update encoding rates following protection settings. | 134 // Update encoding rates following protection settings. |
249 float target_video_bitrate_kbps = | 135 float target_video_bitrate_kbps = |
250 static_cast<float>(video_target_bitrate_) / 1000.0f; | 136 static_cast<float>(video_target_bitrate_) / 1000.0f; |
251 frame_dropper_->SetRates(target_video_bitrate_kbps, incoming_frame_rate_); | 137 frame_dropper_->SetRates(target_video_bitrate_kbps, incoming_frame_rate_); |
252 | 138 |
253 CheckSuspendConditions(); | 139 CheckSuspendConditions(); |
254 | 140 |
255 return video_target_bitrate_; | 141 return video_target_bitrate_; |
256 } | 142 } |
257 | 143 |
258 void MediaOptimization::SetProtectionMethod(VCMProtectionMethodEnum method) { | |
259 CriticalSectionScoped lock(crit_sect_.get()); | |
260 loss_prot_logic_->SetMethod(method); | |
261 } | |
262 | |
263 uint32_t MediaOptimization::InputFrameRate() { | 144 uint32_t MediaOptimization::InputFrameRate() { |
264 CriticalSectionScoped lock(crit_sect_.get()); | 145 CriticalSectionScoped lock(crit_sect_.get()); |
265 return InputFrameRateInternal(); | 146 return InputFrameRateInternal(); |
266 } | 147 } |
267 | 148 |
268 uint32_t MediaOptimization::InputFrameRateInternal() { | 149 uint32_t MediaOptimization::InputFrameRateInternal() { |
269 ProcessIncomingFrameRate(clock_->TimeInMilliseconds()); | 150 ProcessIncomingFrameRate(clock_->TimeInMilliseconds()); |
270 return uint32_t(incoming_frame_rate_ + 0.5f); | 151 return uint32_t(incoming_frame_rate_ + 0.5f); |
271 } | 152 } |
272 | 153 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 encoded_frame_samples_.back().size_bytes += encoded_length; | 185 encoded_frame_samples_.back().size_bytes += encoded_length; |
305 encoded_frame_samples_.back().time_complete_ms = now_ms; | 186 encoded_frame_samples_.back().time_complete_ms = now_ms; |
306 } else { | 187 } else { |
307 encoded_frame_samples_.push_back( | 188 encoded_frame_samples_.push_back( |
308 EncodedFrameSample(encoded_length, timestamp, now_ms)); | 189 EncodedFrameSample(encoded_length, timestamp, now_ms)); |
309 } | 190 } |
310 UpdateSentBitrate(now_ms); | 191 UpdateSentBitrate(now_ms); |
311 UpdateSentFramerate(); | 192 UpdateSentFramerate(); |
312 if (encoded_length > 0) { | 193 if (encoded_length > 0) { |
313 const bool delta_frame = encoded_image._frameType != kVideoFrameKey; | 194 const bool delta_frame = encoded_image._frameType != kVideoFrameKey; |
314 | |
315 frame_dropper_->Fill(encoded_length, delta_frame); | 195 frame_dropper_->Fill(encoded_length, delta_frame); |
316 if (max_payload_size_ > 0 && encoded_length > 0) { | |
317 const float min_packets_per_frame = | |
318 encoded_length / static_cast<float>(max_payload_size_); | |
319 if (delta_frame) { | |
320 loss_prot_logic_->UpdatePacketsPerFrame(min_packets_per_frame, | |
321 clock_->TimeInMilliseconds()); | |
322 } else { | |
323 loss_prot_logic_->UpdatePacketsPerFrameKey( | |
324 min_packets_per_frame, clock_->TimeInMilliseconds()); | |
325 } | |
326 } | |
327 if (!delta_frame && encoded_length > 0) { | |
328 loss_prot_logic_->UpdateKeyFrameSize(static_cast<float>(encoded_length)); | |
329 } | |
330 | |
331 // Updating counters. | |
332 if (delta_frame) { | |
333 delta_frame_cnt_++; | |
334 } else { | |
335 key_frame_cnt_++; | |
336 } | |
337 } | 196 } |
338 | 197 |
339 return VCM_OK; | 198 return VCM_OK; |
340 } | 199 } |
341 | 200 |
342 void MediaOptimization::EnableFrameDropper(bool enable) { | 201 void MediaOptimization::EnableFrameDropper(bool enable) { |
343 CriticalSectionScoped lock(crit_sect_.get()); | 202 CriticalSectionScoped lock(crit_sect_.get()); |
344 frame_dropper_->Enable(enable); | 203 frame_dropper_->Enable(enable); |
345 } | 204 } |
346 | 205 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 if (video_target_bitrate_ > | 327 if (video_target_bitrate_ > |
469 suspension_threshold_bps_ + suspension_window_bps_) { | 328 suspension_threshold_bps_ + suspension_window_bps_) { |
470 video_suspended_ = false; | 329 video_suspended_ = false; |
471 } | 330 } |
472 } | 331 } |
473 } | 332 } |
474 } | 333 } |
475 | 334 |
476 } // namespace media_optimization | 335 } // namespace media_optimization |
477 } // namespace webrtc | 336 } // namespace webrtc |
OLD | NEW |