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 "modules/video_coding/fec_controller_default.h" // NOLINT
12
13 #include <stdlib.h>
14
15 #include <algorithm>
16 #include <string>
17
18 #include "modules/include/module_fec_types.h"
19 #include "rtc_base/logging.h"
20 #include "system_wrappers/include/field_trial.h"
21
22 namespace webrtc {
23
24 const float kProtectionOverheadRateThreshold = 0.5;
25
FecControllerDefault(Clock * clock,VCMProtectionCallback * protection_callback)26 FecControllerDefault::FecControllerDefault(
27 Clock* clock,
28 VCMProtectionCallback* protection_callback)
29 : clock_(clock),
30 protection_callback_(protection_callback),
31 loss_prot_logic_(new media_optimization::VCMLossProtectionLogic(
32 clock_->TimeInMilliseconds())),
33 max_payload_size_(1460),
34 overhead_threshold_(GetProtectionOverheadRateThreshold()) {}
35
FecControllerDefault(Clock * clock)36 FecControllerDefault::FecControllerDefault(Clock* clock)
37 : clock_(clock),
38 loss_prot_logic_(new media_optimization::VCMLossProtectionLogic(
39 clock_->TimeInMilliseconds())),
40 max_payload_size_(1460),
41 overhead_threshold_(GetProtectionOverheadRateThreshold()) {}
42
~FecControllerDefault(void)43 FecControllerDefault::~FecControllerDefault(void) {
44 loss_prot_logic_->Release();
45 }
46
SetProtectionCallback(VCMProtectionCallback * protection_callback)47 void FecControllerDefault::SetProtectionCallback(
48 VCMProtectionCallback* protection_callback) {
49 protection_callback_ = protection_callback;
50 }
51
SetEncodingData(size_t width,size_t height,size_t num_temporal_layers,size_t max_payload_size)52 void FecControllerDefault::SetEncodingData(size_t width,
53 size_t height,
54 size_t num_temporal_layers,
55 size_t max_payload_size) {
56 MutexLock lock(&mutex_);
57 loss_prot_logic_->UpdateFrameSize(width, height);
58 loss_prot_logic_->UpdateNumLayers(num_temporal_layers);
59 max_payload_size_ = max_payload_size;
60 }
61
GetProtectionOverheadRateThreshold()62 float FecControllerDefault::GetProtectionOverheadRateThreshold() {
63 float overhead_threshold =
64 strtof(webrtc::field_trial::FindFullName(
65 "WebRTC-ProtectionOverheadRateThreshold")
66 .c_str(),
67 nullptr);
68 if (overhead_threshold > 0 && overhead_threshold <= 1) {
69 RTC_LOG(LS_INFO) << "ProtectionOverheadRateThreshold is set to "
70 << overhead_threshold;
71 return overhead_threshold;
72 } else if (overhead_threshold < 0 || overhead_threshold > 1) {
73 RTC_LOG(WARNING) << "ProtectionOverheadRateThreshold field trial is set to "
74 "an invalid value, expecting a value between (0, 1].";
75 }
76 // WebRTC-ProtectionOverheadRateThreshold field trial string is not found, use
77 // the default value.
78 return kProtectionOverheadRateThreshold;
79 }
80
UpdateFecRates(uint32_t estimated_bitrate_bps,int actual_framerate_fps,uint8_t fraction_lost,std::vector<bool> loss_mask_vector,int64_t round_trip_time_ms)81 uint32_t FecControllerDefault::UpdateFecRates(
82 uint32_t estimated_bitrate_bps,
83 int actual_framerate_fps,
84 uint8_t fraction_lost,
85 std::vector<bool> loss_mask_vector,
86 int64_t round_trip_time_ms) {
87 float target_bitrate_kbps =
88 static_cast<float>(estimated_bitrate_bps) / 1000.0f;
89 // Sanity check.
90 if (actual_framerate_fps < 1.0) {
91 actual_framerate_fps = 1.0;
92 }
93 FecProtectionParams delta_fec_params;
94 FecProtectionParams key_fec_params;
95 {
96 MutexLock lock(&mutex_);
97 loss_prot_logic_->UpdateBitRate(target_bitrate_kbps);
98 loss_prot_logic_->UpdateRtt(round_trip_time_ms);
99 // Update frame rate for the loss protection logic class: frame rate should
100 // be the actual/sent rate.
101 loss_prot_logic_->UpdateFrameRate(actual_framerate_fps);
102 // Returns the filtered packet loss, used for the protection setting.
103 // The filtered loss may be the received loss (no filter), or some
104 // filtered value (average or max window filter).
105 // Use max window filter for now.
106 media_optimization::FilterPacketLossMode filter_mode =
107 media_optimization::kMaxFilter;
108 uint8_t packet_loss_enc = loss_prot_logic_->FilteredLoss(
109 clock_->TimeInMilliseconds(), filter_mode, fraction_lost);
110 // For now use the filtered loss for computing the robustness settings.
111 loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc);
112 if (loss_prot_logic_->SelectedType() == media_optimization::kNone) {
113 return estimated_bitrate_bps;
114 }
115 // Update method will compute the robustness settings for the given
116 // protection method and the overhead cost
117 // the protection method is set by the user via SetVideoProtection.
118 loss_prot_logic_->UpdateMethod();
119 // Get the bit cost of protection method, based on the amount of
120 // overhead data actually transmitted (including headers) the last
121 // second.
122 // Get the FEC code rate for Key frames (set to 0 when NA).
123 key_fec_params.fec_rate =
124 loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorK();
125 // Get the FEC code rate for Delta frames (set to 0 when NA).
126 delta_fec_params.fec_rate =
127 loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorD();
128 // The RTP module currently requires the same |max_fec_frames| for both
129 // key and delta frames.
130 delta_fec_params.max_fec_frames =
131 loss_prot_logic_->SelectedMethod()->MaxFramesFec();
132 key_fec_params.max_fec_frames =
133 loss_prot_logic_->SelectedMethod()->MaxFramesFec();
134 }
135 // Set the FEC packet mask type. |kFecMaskBursty| is more effective for
136 // consecutive losses and little/no packet re-ordering. As we currently
137 // do not have feedback data on the degree of correlated losses and packet
138 // re-ordering, we keep default setting to |kFecMaskRandom| for now.
139 delta_fec_params.fec_mask_type = kFecMaskRandom;
140 key_fec_params.fec_mask_type = kFecMaskRandom;
141 // Update protection callback with protection settings.
142 uint32_t sent_video_rate_bps = 0;
143 uint32_t sent_nack_rate_bps = 0;
144 uint32_t sent_fec_rate_bps = 0;
145 // Rate cost of the protection methods.
146 float protection_overhead_rate = 0.0f;
147 // TODO(Marco): Pass FEC protection values per layer.
148 protection_callback_->ProtectionRequest(
149 &delta_fec_params, &key_fec_params, &sent_video_rate_bps,
150 &sent_nack_rate_bps, &sent_fec_rate_bps);
151 uint32_t sent_total_rate_bps =
152 sent_video_rate_bps + sent_nack_rate_bps + sent_fec_rate_bps;
153 // Estimate the overhead costs of the next second as staying the same
154 // wrt the source bitrate.
155 if (sent_total_rate_bps > 0) {
156 protection_overhead_rate =
157 static_cast<float>(sent_nack_rate_bps + sent_fec_rate_bps) /
158 sent_total_rate_bps;
159 }
160 // Cap the overhead estimate to a threshold, default is 50%.
161 protection_overhead_rate =
162 std::min(protection_overhead_rate, overhead_threshold_);
163 // Source coding rate: total rate - protection overhead.
164 return estimated_bitrate_bps * (1.0 - protection_overhead_rate);
165 }
166
SetProtectionMethod(bool enable_fec,bool enable_nack)167 void FecControllerDefault::SetProtectionMethod(bool enable_fec,
168 bool enable_nack) {
169 media_optimization::VCMProtectionMethodEnum method(media_optimization::kNone);
170 if (enable_fec && enable_nack) {
171 method = media_optimization::kNackFec;
172 } else if (enable_nack) {
173 method = media_optimization::kNack;
174 } else if (enable_fec) {
175 method = media_optimization::kFec;
176 }
177 MutexLock lock(&mutex_);
178 loss_prot_logic_->SetMethod(method);
179 }
180
UpdateWithEncodedData(const size_t encoded_image_length,const VideoFrameType encoded_image_frametype)181 void FecControllerDefault::UpdateWithEncodedData(
182 const size_t encoded_image_length,
183 const VideoFrameType encoded_image_frametype) {
184 const size_t encoded_length = encoded_image_length;
185 MutexLock lock(&mutex_);
186 if (encoded_length > 0) {
187 const bool delta_frame =
188 encoded_image_frametype != VideoFrameType::kVideoFrameKey;
189 if (max_payload_size_ > 0 && encoded_length > 0) {
190 const float min_packets_per_frame =
191 encoded_length / static_cast<float>(max_payload_size_);
192 if (delta_frame) {
193 loss_prot_logic_->UpdatePacketsPerFrame(min_packets_per_frame,
194 clock_->TimeInMilliseconds());
195 } else {
196 loss_prot_logic_->UpdatePacketsPerFrameKey(
197 min_packets_per_frame, clock_->TimeInMilliseconds());
198 }
199 }
200 if (!delta_frame && encoded_length > 0) {
201 loss_prot_logic_->UpdateKeyFrameSize(static_cast<float>(encoded_length));
202 }
203 }
204 }
205
UseLossVectorMask()206 bool FecControllerDefault::UseLossVectorMask() {
207 return false;
208 }
209
210 } // namespace webrtc
211