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/rtp_rtcp/source/producer_fec.h" | 11 #include "webrtc/modules/rtp_rtcp/source/producer_fec.h" |
12 | 12 |
13 #include <memory> | 13 #include <memory> |
14 #include <utility> | 14 #include <utility> |
15 | 15 |
| 16 #include "webrtc/base/basictypes.h" |
| 17 #include "webrtc/base/checks.h" |
16 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 18 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
17 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" | 19 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" |
18 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | 20 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" |
19 | 21 |
20 namespace webrtc { | 22 namespace webrtc { |
21 | 23 |
22 enum { kREDForFECHeaderLength = 1 }; | 24 constexpr size_t kRedForFecHeaderLength = 1; |
| 25 |
23 // This controls the maximum amount of excess overhead (actual - target) | 26 // This controls the maximum amount of excess overhead (actual - target) |
24 // allowed in order to trigger GenerateFec(), before |params_.max_fec_frames| | 27 // allowed in order to trigger GenerateFec(), before |params_.max_fec_frames| |
25 // is reached. Overhead here is defined as relative to number of media packets. | 28 // is reached. Overhead here is defined as relative to number of media packets. |
26 enum { kMaxExcessOverhead = 50 }; // Q8. | 29 constexpr int kMaxExcessOverhead = 50; // Q8. |
| 30 |
27 // This is the minimum number of media packets required (above some protection | 31 // This is the minimum number of media packets required (above some protection |
28 // level) in order to trigger GenerateFec(), before |params_.max_fec_frames| is | 32 // level) in order to trigger GenerateFec(), before |params_.max_fec_frames| is |
29 // reached. | 33 // reached. |
30 enum { kMinimumMediaPackets = 4 }; | 34 constexpr size_t kMinMediaPackets = 4; |
| 35 |
31 // Threshold on the received FEC protection level, above which we enforce at | 36 // Threshold on the received FEC protection level, above which we enforce at |
32 // least |kMinimumMediaPackets| packets for the FEC code. Below this | 37 // least |kMinMediaPackets| packets for the FEC code. Below this |
33 // threshold |kMinimumMediaPackets| is set to default value of 1. | 38 // threshold |kMinMediaPackets| is set to default value of 1. |
34 enum { kHighProtectionThreshold = 80 }; // Corresponds to ~30 overhead, range | 39 // |
35 // is 0 to 255, where 255 corresponds to 100% overhead (relative to number of | 40 // The range is between 0 and 255, where 255 corresponds to 100% overhead |
36 // media packets). | 41 // (relative to the number of protected media packets). |
| 42 constexpr uint8_t kHighProtectionThreshold = 80; |
| 43 |
| 44 // This threshold is used to adapt the |kMinMediaPackets| threshold, based |
| 45 // on the average number of packets per frame seen so far. When there are few |
| 46 // packets per frame (as given by this threshold), at least |
| 47 // |kMinMediaPackets| + 1 packets are sent to the FEC code. |
| 48 constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f; |
37 | 49 |
38 RedPacket::RedPacket(size_t length) | 50 RedPacket::RedPacket(size_t length) |
39 : data_(new uint8_t[length]), | 51 : data_(new uint8_t[length]), |
40 length_(length), | 52 length_(length), |
41 header_length_(0) { | 53 header_length_(0) { |
42 } | 54 } |
43 | 55 |
44 RedPacket::~RedPacket() { | 56 void RedPacket::CreateHeader(const uint8_t* rtp_header, |
45 delete [] data_; | 57 size_t header_length, |
46 } | 58 int red_payload_type, |
47 | 59 int payload_type) { |
48 void RedPacket::CreateHeader(const uint8_t* rtp_header, size_t header_length, | 60 RTC_DCHECK_LT(header_length + kRedForFecHeaderLength, length_); |
49 int red_pl_type, int pl_type) { | 61 memcpy(data_.get(), rtp_header, header_length); |
50 assert(header_length + kREDForFECHeaderLength <= length_); | |
51 memcpy(data_, rtp_header, header_length); | |
52 // Replace payload type. | 62 // Replace payload type. |
53 data_[1] &= 0x80; | 63 data_[1] &= 0x80; |
54 data_[1] += red_pl_type; | 64 data_[1] += red_payload_type; |
55 // Add RED header | 65 // Add RED header |
56 // f-bit always 0 | 66 // f-bit always 0 |
57 data_[header_length] = static_cast<uint8_t>(pl_type); | 67 data_[header_length] = static_cast<uint8_t>(payload_type); |
58 header_length_ = header_length + kREDForFECHeaderLength; | 68 header_length_ = header_length + kRedForFecHeaderLength; |
59 } | 69 } |
60 | 70 |
61 void RedPacket::SetSeqNum(int seq_num) { | 71 void RedPacket::SetSeqNum(int seq_num) { |
62 assert(seq_num >= 0 && seq_num < (1<<16)); | 72 RTC_DCHECK_GE(seq_num, 0); |
| 73 RTC_DCHECK_LT(seq_num, 1 << 16); |
63 | 74 |
64 ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num); | 75 ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num); |
65 } | 76 } |
66 | 77 |
67 void RedPacket::AssignPayload(const uint8_t* payload, size_t length) { | 78 void RedPacket::AssignPayload(const uint8_t* payload, size_t length) { |
68 assert(header_length_ + length <= length_); | 79 RTC_DCHECK_LE(header_length_ + length, length_); |
69 memcpy(data_ + header_length_, payload, length); | 80 memcpy(data_.get() + header_length_, payload, length); |
70 } | 81 } |
71 | 82 |
72 void RedPacket::ClearMarkerBit() { | 83 void RedPacket::ClearMarkerBit() { |
73 data_[1] &= 0x7F; | 84 data_[1] &= 0x7F; |
74 } | 85 } |
75 | 86 |
76 uint8_t* RedPacket::data() const { | 87 uint8_t* RedPacket::data() const { |
77 return data_; | 88 return data_.get(); |
78 } | 89 } |
79 | 90 |
80 size_t RedPacket::length() const { | 91 size_t RedPacket::length() const { |
81 return length_; | 92 return length_; |
82 } | 93 } |
83 | 94 |
84 ProducerFec::ProducerFec(ForwardErrorCorrection* fec) | 95 ProducerFec::ProducerFec(ForwardErrorCorrection* fec) |
85 : fec_(fec), | 96 : fec_(fec), |
86 media_packets_fec_(), | 97 media_packets_(), |
87 fec_packets_(), | 98 generated_fec_packets_(), |
88 num_frames_(0), | 99 num_protected_frames_(0), |
89 num_first_partition_(0), | 100 num_important_packets_(0), |
90 minimum_media_packets_fec_(1), | 101 min_num_media_packets_(1), |
91 params_(), | 102 params_(), |
92 new_params_() { | 103 new_params_() { |
93 memset(¶ms_, 0, sizeof(params_)); | 104 memset(¶ms_, 0, sizeof(params_)); |
94 memset(&new_params_, 0, sizeof(new_params_)); | 105 memset(&new_params_, 0, sizeof(new_params_)); |
95 } | 106 } |
96 | 107 |
97 ProducerFec::~ProducerFec() { | 108 ProducerFec::~ProducerFec() { |
98 DeletePackets(); | 109 DeleteMediaPackets(); |
| 110 } |
| 111 |
| 112 std::unique_ptr<RedPacket> ProducerFec::BuildRedPacket( |
| 113 const uint8_t* data_buffer, |
| 114 size_t payload_length, |
| 115 size_t rtp_header_length, |
| 116 int red_payload_type) { |
| 117 std::unique_ptr<RedPacket> red_packet(new RedPacket( |
| 118 payload_length + kRedForFecHeaderLength + rtp_header_length)); |
| 119 int payload_type = data_buffer[1] & 0x7f; |
| 120 red_packet->CreateHeader(data_buffer, rtp_header_length, red_payload_type, |
| 121 payload_type); |
| 122 red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length); |
| 123 return red_packet; |
99 } | 124 } |
100 | 125 |
101 void ProducerFec::SetFecParameters(const FecProtectionParams* params, | 126 void ProducerFec::SetFecParameters(const FecProtectionParams* params, |
102 int num_first_partition) { | 127 int num_important_packets) { |
103 // Number of first partition packets cannot exceed kMaxMediaPackets | 128 // Number of important packets (i.e. number of packets receiving additional |
104 assert(params->fec_rate >= 0 && params->fec_rate < 256); | 129 // protection in 'unequal protection mode') cannot exceed kMaxMediaPackets. |
105 if (num_first_partition > | 130 RTC_DCHECK_GE(params->fec_rate, 0); |
| 131 RTC_DCHECK_LE(params->fec_rate, 255); |
| 132 if (num_important_packets > |
106 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) { | 133 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) { |
107 num_first_partition = | 134 num_important_packets = ForwardErrorCorrection::kMaxMediaPackets; |
108 ForwardErrorCorrection::kMaxMediaPackets; | |
109 } | 135 } |
110 // Store the new params and apply them for the next set of FEC packets being | 136 // Store the new params and apply them for the next set of FEC packets being |
111 // produced. | 137 // produced. |
112 new_params_ = *params; | 138 new_params_ = *params; |
113 num_first_partition_ = num_first_partition; | 139 num_important_packets_ = num_important_packets; |
114 if (params->fec_rate > kHighProtectionThreshold) { | 140 if (params->fec_rate > kHighProtectionThreshold) { |
115 minimum_media_packets_fec_ = kMinimumMediaPackets; | 141 min_num_media_packets_ = kMinMediaPackets; |
116 } else { | 142 } else { |
117 minimum_media_packets_fec_ = 1; | 143 min_num_media_packets_ = 1; |
118 } | 144 } |
119 } | 145 } |
120 | 146 |
121 RedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer, | |
122 size_t payload_length, | |
123 size_t rtp_header_length, | |
124 int red_pl_type) { | |
125 RedPacket* red_packet = new RedPacket( | |
126 payload_length + kREDForFECHeaderLength + rtp_header_length); | |
127 int pl_type = data_buffer[1] & 0x7f; | |
128 red_packet->CreateHeader(data_buffer, rtp_header_length, | |
129 red_pl_type, pl_type); | |
130 red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length); | |
131 return red_packet; | |
132 } | |
133 | |
134 int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer, | 147 int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer, |
135 size_t payload_length, | 148 size_t payload_length, |
136 size_t rtp_header_length) { | 149 size_t rtp_header_length) { |
137 assert(fec_packets_.empty()); | 150 RTC_DCHECK(generated_fec_packets_.empty()); |
138 if (media_packets_fec_.empty()) { | 151 if (media_packets_.empty()) { |
139 params_ = new_params_; | 152 params_ = new_params_; |
140 } | 153 } |
141 bool complete_frame = false; | 154 bool complete_frame = false; |
142 const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false; | 155 const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false; |
143 if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) { | 156 if (media_packets_.size() < ForwardErrorCorrection::kMaxMediaPackets) { |
144 // Generic FEC can only protect up to kMaxMediaPackets packets. | 157 // Generic FEC can only protect up to |kMaxMediaPackets| packets. |
145 std::unique_ptr<ForwardErrorCorrection::Packet> packet( | 158 std::unique_ptr<ForwardErrorCorrection::Packet> packet( |
146 new ForwardErrorCorrection::Packet()); | 159 new ForwardErrorCorrection::Packet()); |
147 packet->length = payload_length + rtp_header_length; | 160 packet->length = payload_length + rtp_header_length; |
148 memcpy(packet->data, data_buffer, packet->length); | 161 memcpy(packet->data, data_buffer, packet->length); |
149 media_packets_fec_.push_back(std::move(packet)); | 162 media_packets_.push_back(std::move(packet)); |
150 } | 163 } |
151 if (marker_bit) { | 164 if (marker_bit) { |
152 ++num_frames_; | 165 ++num_protected_frames_; |
153 complete_frame = true; | 166 complete_frame = true; |
154 } | 167 } |
155 // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as: | 168 // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as: |
156 // (1) the excess overhead (actual overhead - requested/target overhead) is | 169 // (1) the excess overhead (actual overhead - requested/target overhead) is |
157 // less than |kMaxExcessOverhead|, and | 170 // less than |kMaxExcessOverhead|, and |
158 // (2) at least |minimum_media_packets_fec_| media packets is reached. | 171 // (2) at least |min_num_media_packets_| media packets is reached. |
159 if (complete_frame && | 172 if (complete_frame && |
160 (num_frames_ == params_.max_fec_frames || | 173 (num_protected_frames_ == params_.max_fec_frames || |
161 (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) { | 174 (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) { |
162 assert(num_first_partition_ <= | 175 RTC_DCHECK_LE(num_important_packets_, |
163 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)); | 176 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)); |
164 // TODO(pbos): Consider whether unequal protection should be enabled or not, | 177 // TODO(pbos): Consider whether unequal protection should be enabled or not, |
165 // it is currently always disabled. | 178 // it is currently always disabled. |
166 int ret = fec_->GenerateFec(media_packets_fec_, params_.fec_rate, | 179 // |
167 num_first_partition_, false, | 180 // Since unequal protection is disabled, the value of |
168 params_.fec_mask_type, &fec_packets_); | 181 // |num_important_packets_| has no importance when calling GenerateFec(). |
169 if (fec_packets_.empty()) { | 182 constexpr bool kUseUnequalProtection = false; |
170 num_frames_ = 0; | 183 int ret = fec_->GenerateFec(media_packets_, params_.fec_rate, |
171 DeletePackets(); | 184 num_important_packets_, kUseUnequalProtection, |
| 185 params_.fec_mask_type, &generated_fec_packets_); |
| 186 if (generated_fec_packets_.empty()) { |
| 187 num_protected_frames_ = 0; |
| 188 DeleteMediaPackets(); |
172 } | 189 } |
173 return ret; | 190 return ret; |
174 } | 191 } |
175 return 0; | 192 return 0; |
176 } | 193 } |
177 | 194 |
178 // Returns true if the excess overhead (actual - target) for the FEC is below | 195 bool ProducerFec::ExcessOverheadBelowMax() const { |
179 // the amount |kMaxExcessOverhead|. This effects the lower protection level | |
180 // cases and low number of media packets/frame. The target overhead is given by | |
181 // |params_.fec_rate|, and is only achievable in the limit of large number of | |
182 // media packets. | |
183 bool ProducerFec::ExcessOverheadBelowMax() { | |
184 return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead); | 196 return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead); |
185 } | 197 } |
186 | 198 |
187 // Returns true if the media packet list for the FEC is at least | 199 bool ProducerFec::MinimumMediaPacketsReached() const { |
188 // |minimum_media_packets_fec_|. This condition tries to capture the effect | 200 float average_num_packets_per_frame = |
189 // that, for the same amount of protection/overhead, longer codes | 201 static_cast<float>(media_packets_.size()) / num_protected_frames_; |
190 // (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses. | 202 int num_media_packets = static_cast<int>(media_packets_.size()); |
191 bool ProducerFec::MinimumMediaPacketsReached() { | 203 if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) { |
192 float avg_num_packets_frame = static_cast<float>(media_packets_fec_.size()) / | 204 return num_media_packets >= min_num_media_packets_; |
193 num_frames_; | |
194 if (avg_num_packets_frame < 2.0f) { | |
195 return (static_cast<int>(media_packets_fec_.size()) >= | |
196 minimum_media_packets_fec_); | |
197 } else { | 205 } else { |
198 // For larger rates (more packets/frame), increase the threshold. | 206 // For larger rates (more packets/frame), increase the threshold. |
199 return (static_cast<int>(media_packets_fec_.size()) >= | 207 // TODO(brandtr): Investigate what impact this adaptation has. |
200 minimum_media_packets_fec_ + 1); | 208 return num_media_packets >= min_num_media_packets_ + 1; |
201 } | 209 } |
202 } | 210 } |
203 | 211 |
204 bool ProducerFec::FecAvailable() const { | 212 bool ProducerFec::FecAvailable() const { |
205 return !fec_packets_.empty(); | 213 return !generated_fec_packets_.empty(); |
206 } | 214 } |
207 | 215 |
208 size_t ProducerFec::NumAvailableFecPackets() const { | 216 size_t ProducerFec::NumAvailableFecPackets() const { |
209 return fec_packets_.size(); | 217 return generated_fec_packets_.size(); |
210 } | 218 } |
211 | 219 |
212 std::vector<RedPacket*> ProducerFec::GetFecPackets(int red_pl_type, | 220 std::vector<std::unique_ptr<RedPacket>> ProducerFec::GetFecPacketsAsRed( |
213 int fec_pl_type, | 221 int red_payload_type, |
214 uint16_t first_seq_num, | 222 int ulpfec_payload_type, |
215 size_t rtp_header_length) { | 223 uint16_t first_seq_num, |
216 std::vector<RedPacket*> fec_packets; | 224 size_t rtp_header_length) { |
217 fec_packets.reserve(fec_packets_.size()); | 225 std::vector<std::unique_ptr<RedPacket>> red_packets; |
218 uint16_t sequence_number = first_seq_num; | 226 red_packets.reserve(generated_fec_packets_.size()); |
219 while (!fec_packets_.empty()) { | 227 RTC_DCHECK(!media_packets_.empty()); |
220 // Build FEC packet. The FEC packets in |fec_packets_| doesn't | 228 ForwardErrorCorrection::Packet* last_media_packet = |
221 // have RTP headers, so we're reusing the header from the last | 229 media_packets_.back().get(); |
222 // media packet. | 230 uint16_t seq_num = first_seq_num; |
223 ForwardErrorCorrection::Packet* packet_to_send = fec_packets_.front(); | 231 for (const auto& fec_packet : generated_fec_packets_) { |
224 ForwardErrorCorrection::Packet* last_media_packet = | 232 // Wrap FEC packet (including FEC headers) in a RED packet. Since the |
225 media_packets_fec_.back().get(); | 233 // FEC packets in |generated_fec_packets_| don't have RTP headers, we |
| 234 // reuse the header from the last media packet. |
| 235 std::unique_ptr<RedPacket> red_packet(new RedPacket( |
| 236 fec_packet->length + kRedForFecHeaderLength + rtp_header_length)); |
| 237 red_packet->CreateHeader(last_media_packet->data, rtp_header_length, |
| 238 red_payload_type, ulpfec_payload_type); |
| 239 red_packet->SetSeqNum(seq_num++); |
| 240 red_packet->ClearMarkerBit(); |
| 241 red_packet->AssignPayload(fec_packet->data, fec_packet->length); |
226 | 242 |
227 RedPacket* red_packet = new RedPacket( | 243 red_packets.push_back(std::move(red_packet)); |
228 packet_to_send->length + kREDForFECHeaderLength + rtp_header_length); | 244 } |
229 red_packet->CreateHeader(last_media_packet->data, rtp_header_length, | |
230 red_pl_type, fec_pl_type); | |
231 red_packet->SetSeqNum(sequence_number++); | |
232 red_packet->ClearMarkerBit(); | |
233 red_packet->AssignPayload(packet_to_send->data, packet_to_send->length); | |
234 | 245 |
235 fec_packets.push_back(red_packet); | 246 // Reset state. |
| 247 DeleteMediaPackets(); |
| 248 generated_fec_packets_.clear(); |
| 249 num_protected_frames_ = 0; |
236 | 250 |
237 fec_packets_.pop_front(); | 251 return red_packets; |
238 } | |
239 DeletePackets(); | |
240 num_frames_ = 0; | |
241 return fec_packets; | |
242 } | 252 } |
243 | 253 |
244 int ProducerFec::Overhead() const { | 254 int ProducerFec::Overhead() const { |
245 // Overhead is defined as relative to the number of media packets, and not | 255 // Overhead is defined as relative to the number of media packets, and not |
246 // relative to total number of packets. This definition is inhereted from the | 256 // relative to total number of packets. This definition is inherited from the |
247 // protection factor produced by video_coding module and how the FEC | 257 // protection factor produced by video_coding module and how the FEC |
248 // generation is implemented. | 258 // generation is implemented. |
249 assert(!media_packets_fec_.empty()); | 259 RTC_DCHECK(!media_packets_.empty()); |
250 int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_fec_.size(), | 260 int num_fec_packets = |
251 params_.fec_rate); | 261 fec_->GetNumberOfFecPackets(media_packets_.size(), params_.fec_rate); |
252 // Return the overhead in Q8. | 262 // Return the overhead in Q8. |
253 return (num_fec_packets << 8) / media_packets_fec_.size(); | 263 return (num_fec_packets << 8) / media_packets_.size(); |
254 } | 264 } |
255 | 265 |
256 void ProducerFec::DeletePackets() { | 266 void ProducerFec::DeleteMediaPackets() { |
257 media_packets_fec_.clear(); | 267 media_packets_.clear(); |
258 } | 268 } |
259 | 269 |
260 } // namespace webrtc | 270 } // namespace webrtc |
OLD | NEW |