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