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