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