Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1242)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/forward_error_correction.cc

Issue 1522463002: Add FEC producer fuzzing and a unittest for one of the issues found. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fixed fuzzer to have reasonable sequence numbers Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/forward_error_correction.h" 11 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
12 12
13 #include <assert.h>
14 #include <stdlib.h> 13 #include <stdlib.h>
15 #include <string.h> 14 #include <string.h>
16 15
17 #include <algorithm> 16 #include <algorithm>
18 #include <iterator> 17 #include <iterator>
19 18
19 #include "webrtc/base/checks.h"
20 #include "webrtc/base/logging.h" 20 #include "webrtc/base/logging.h"
21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" 21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
22 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" 22 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
23 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" 23 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h"
24 24
25 namespace webrtc { 25 namespace webrtc {
26 26
27 // FEC header size in bytes. 27 // FEC header size in bytes.
28 const uint8_t kFecHeaderSize = 10; 28 const uint8_t kFecHeaderSize = 10;
29 29
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 num_important_packets <= num_media_packets); 119 num_important_packets <= num_media_packets);
120 assert(fec_packet_list->empty()); 120 assert(fec_packet_list->empty());
121 121
122 if (num_media_packets > kMaxMediaPackets) { 122 if (num_media_packets > kMaxMediaPackets) {
123 LOG(LS_WARNING) << "Can't protect " << num_media_packets 123 LOG(LS_WARNING) << "Can't protect " << num_media_packets
124 << " media packets per frame. Max is " << kMaxMediaPackets; 124 << " media packets per frame. Max is " << kMaxMediaPackets;
125 return -1; 125 return -1;
126 } 126 }
127 127
128 bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear); 128 bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear);
129 int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 129 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
130 130
131 // Do some error checking on the media packets. 131 // Do some error checking on the media packets.
132 for (Packet* media_packet : media_packet_list) { 132 for (Packet* media_packet : media_packet_list) {
133 assert(media_packet); 133 assert(media_packet);
134 134
135 if (media_packet->length < kRtpHeaderSize) { 135 if (media_packet->length < kRtpHeaderSize) {
136 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " 136 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes "
137 << "is smaller than RTP header."; 137 << "is smaller than RTP header.";
138 return -1; 138 return -1;
139 } 139 }
(...skipping 19 matching lines...) Expand all
159 // packets. 159 // packets.
160 fec_packet_list->push_back(&generated_fec_packets_[i]); 160 fec_packet_list->push_back(&generated_fec_packets_[i]);
161 } 161 }
162 162
163 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); 163 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
164 164
165 // -- Generate packet masks -- 165 // -- Generate packet masks --
166 // Always allocate space for a large mask. 166 // Always allocate space for a large mask.
167 rtc::scoped_ptr<uint8_t[]> packet_mask( 167 rtc::scoped_ptr<uint8_t[]> packet_mask(
168 new uint8_t[num_fec_packets * kMaskSizeLBitSet]); 168 new uint8_t[num_fec_packets * kMaskSizeLBitSet]);
169 memset(packet_mask.get(), 0, num_fec_packets * num_maskBytes); 169 memset(packet_mask.get(), 0, num_fec_packets * num_mask_bytes);
170 internal::GeneratePacketMasks(num_media_packets, num_fec_packets, 170 internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
171 num_important_packets, use_unequal_protection, 171 num_important_packets, use_unequal_protection,
172 mask_table, packet_mask.get()); 172 mask_table, packet_mask.get());
173 173
174 int num_mask_bits = InsertZerosInBitMasks( 174 int num_mask_bits = InsertZerosInBitMasks(
175 media_packet_list, packet_mask.get(), num_maskBytes, num_fec_packets); 175 media_packet_list, packet_mask.get(), num_mask_bytes, num_fec_packets);
176
177 l_bit = (num_mask_bits > 8 * kMaskSizeLBitClear);
178 176
179 if (num_mask_bits < 0) { 177 if (num_mask_bits < 0) {
180 return -1; 178 return -1;
181 } 179 }
180 l_bit = (num_mask_bits > 8 * kMaskSizeLBitClear);
182 if (l_bit) { 181 if (l_bit) {
183 num_maskBytes = kMaskSizeLBitSet; 182 num_mask_bytes = kMaskSizeLBitSet;
184 } 183 }
185 184
186 GenerateFecBitStrings(media_packet_list, packet_mask.get(), num_fec_packets, 185 GenerateFecBitStrings(media_packet_list, packet_mask.get(), num_fec_packets,
187 l_bit); 186 l_bit);
188 GenerateFecUlpHeaders(media_packet_list, packet_mask.get(), l_bit, 187 GenerateFecUlpHeaders(media_packet_list, packet_mask.get(), l_bit,
189 num_fec_packets); 188 num_fec_packets);
190 189
191 return 0; 190 return 0;
192 } 191 }
193 192
194 int ForwardErrorCorrection::GetNumberOfFecPackets(int num_media_packets, 193 int ForwardErrorCorrection::GetNumberOfFecPackets(int num_media_packets,
195 int protection_factor) { 194 int protection_factor) {
196 // Result in Q0 with an unsigned round. 195 // Result in Q0 with an unsigned round.
197 int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8; 196 int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8;
198 // Generate at least one FEC packet if we need protection. 197 // Generate at least one FEC packet if we need protection.
199 if (protection_factor > 0 && num_fec_packets == 0) { 198 if (protection_factor > 0 && num_fec_packets == 0) {
200 num_fec_packets = 1; 199 num_fec_packets = 1;
201 } 200 }
202 assert(num_fec_packets <= num_media_packets); 201 assert(num_fec_packets <= num_media_packets);
203 return num_fec_packets; 202 return num_fec_packets;
204 } 203 }
205 204
206 void ForwardErrorCorrection::GenerateFecBitStrings( 205 void ForwardErrorCorrection::GenerateFecBitStrings(
207 const PacketList& media_packet_list, uint8_t* packet_mask, 206 const PacketList& media_packet_list, uint8_t* packet_mask,
208 int num_fec_packets, bool l_bit) { 207 int num_fec_packets, bool l_bit) {
209 if (media_packet_list.empty()) { 208 if (media_packet_list.empty()) {
210 return; 209 return;
211 } 210 }
212 uint8_t media_payload_length[2]; 211 uint8_t media_payload_length[2];
213 const int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 212 const int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
214 const uint16_t ulp_header_size = 213 const uint16_t ulp_header_size =
215 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 214 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear;
216 const uint16_t fec_rtp_offset = 215 const uint16_t fec_rtp_offset =
217 kFecHeaderSize + ulp_header_size - kRtpHeaderSize; 216 kFecHeaderSize + ulp_header_size - kRtpHeaderSize;
218 217
219 for (int i = 0; i < num_fec_packets; ++i) { 218 for (int i = 0; i < num_fec_packets; ++i) {
220 PacketList::const_iterator media_list_it = media_packet_list.begin(); 219 PacketList::const_iterator media_list_it = media_packet_list.begin();
221 uint32_t pkt_mask_idx = i * num_maskBytes; 220 uint32_t pkt_mask_idx = i * num_mask_bytes;
222 uint32_t media_pkt_idx = 0; 221 uint32_t media_pkt_idx = 0;
223 uint16_t fec_packet_length = 0; 222 uint16_t fec_packet_length = 0;
224 uint16_t prev_seq_num = ParseSequenceNumber((*media_list_it)->data); 223 uint16_t prev_seq_num = ParseSequenceNumber((*media_list_it)->data);
225 while (media_list_it != media_packet_list.end()) { 224 while (media_list_it != media_packet_list.end()) {
226 // Each FEC packet has a multiple byte mask. 225 // Each FEC packet has a multiple byte mask. Determine if this media
226 // packet should be included in FEC packet i.
227 if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { 227 if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) {
228 Packet* media_packet = *media_list_it; 228 Packet* media_packet = *media_list_it;
229 229
230 // Assign network-ordered media payload length. 230 // Assign network-ordered media payload length.
231 ByteWriter<uint16_t>::WriteBigEndian( 231 ByteWriter<uint16_t>::WriteBigEndian(
232 media_payload_length, media_packet->length - kRtpHeaderSize); 232 media_payload_length, media_packet->length - kRtpHeaderSize);
233 233
234 fec_packet_length = media_packet->length + fec_rtp_offset; 234 fec_packet_length = media_packet->length + fec_rtp_offset;
235 // On the first protected packet, we don't need to XOR. 235 // On the first protected packet, we don't need to XOR.
236 if (generated_fec_packets_[i].length == 0) { 236 if (generated_fec_packets_[i].length == 0) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 if (fec_packet_length > generated_fec_packets_[i].length) { 270 if (fec_packet_length > generated_fec_packets_[i].length) {
271 generated_fec_packets_[i].length = fec_packet_length; 271 generated_fec_packets_[i].length = fec_packet_length;
272 } 272 }
273 } 273 }
274 media_list_it++; 274 media_list_it++;
275 if (media_list_it != media_packet_list.end()) { 275 if (media_list_it != media_packet_list.end()) {
276 uint16_t seq_num = ParseSequenceNumber((*media_list_it)->data); 276 uint16_t seq_num = ParseSequenceNumber((*media_list_it)->data);
277 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); 277 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num);
278 prev_seq_num = seq_num; 278 prev_seq_num = seq_num;
279 } 279 }
280 if (media_pkt_idx == 8) { 280 pkt_mask_idx += media_pkt_idx / 8;
281 // Switch to the next mask byte. 281 media_pkt_idx %= 8;
282 media_pkt_idx = 0;
283 pkt_mask_idx++;
284 }
285 } 282 }
286 assert(generated_fec_packets_[i].length); 283 RTC_DCHECK_GT(generated_fec_packets_[i].length, 0u)
287 //Note: This shouldn't happen: means packet mask is wrong or poorly designed 284 << "Packet mask is wrong or poorly designed.";
288 } 285 }
289 } 286 }
290 287
291 int ForwardErrorCorrection::InsertZerosInBitMasks( 288 int ForwardErrorCorrection::InsertZerosInBitMasks(
292 const PacketList& media_packets, uint8_t* packet_mask, int num_mask_bytes, 289 const PacketList& media_packets, uint8_t* packet_mask, int num_mask_bytes,
293 int num_fec_packets) { 290 int num_fec_packets) {
294 uint8_t* new_mask = NULL; 291 uint8_t* new_mask = NULL;
295 if (media_packets.size() <= 1) { 292 if (media_packets.size() <= 1) {
296 return media_packets.size(); 293 return media_packets.size();
297 } 294 }
298 int last_seq_num = ParseSequenceNumber(media_packets.back()->data); 295 int last_seq_num = ParseSequenceNumber(media_packets.back()->data);
299 int first_seq_num = ParseSequenceNumber(media_packets.front()->data); 296 int first_seq_num = ParseSequenceNumber(media_packets.front()->data);
300 int total_missing_seq_nums = 297 int total_missing_seq_nums =
301 static_cast<uint16_t>(last_seq_num - first_seq_num) - 298 static_cast<uint16_t>(last_seq_num - first_seq_num) -
302 media_packets.size() + 1; 299 media_packets.size() + 1;
303 if (total_missing_seq_nums == 0) { 300 if (total_missing_seq_nums == 0) {
304 // All sequence numbers are covered by the packet mask. No zero insertion 301 // All sequence numbers are covered by the packet mask. No zero insertion
305 // required. 302 // required.
306 return media_packets.size(); 303 return media_packets.size();
307 } 304 }
305 // We can only protect 8 * kMaskSizeLBitSet packets.
306 if (total_missing_seq_nums + media_packets.size() > 8 * kMaskSizeLBitSet)
307 return -1;
308 // Allocate the new mask. 308 // Allocate the new mask.
309 int new_mask_bytes = kMaskSizeLBitClear; 309 int new_mask_bytes = kMaskSizeLBitClear;
310 if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) { 310 if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) {
311 new_mask_bytes = kMaskSizeLBitSet; 311 new_mask_bytes = kMaskSizeLBitSet;
312 } 312 }
313 new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet]; 313 new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet];
314 memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet); 314 memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet);
315 315
316 PacketList::const_iterator it = media_packets.begin(); 316 PacketList::const_iterator it = media_packets.begin();
317 uint16_t prev_seq_num = first_seq_num; 317 uint16_t prev_seq_num = first_seq_num;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 // 0 1 2 3 403 // 0 1 2 3
404 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 404 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
405 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 405 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406 // | Protection Length | mask | 406 // | Protection Length | mask |
407 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 407 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408 // | mask cont. (present only when L = 1) | 408 // | mask cont. (present only when L = 1) |
409 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 409 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
410 PacketList::const_iterator media_list_it = media_packet_list.begin(); 410 PacketList::const_iterator media_list_it = media_packet_list.begin();
411 Packet* media_packet = *media_list_it; 411 Packet* media_packet = *media_list_it;
412 assert(media_packet != NULL); 412 assert(media_packet != NULL);
413 int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 413 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
414 const uint16_t ulp_header_size = 414 const uint16_t ulp_header_size =
415 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 415 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear;
416 416
417 for (int i = 0; i < num_fec_packets; ++i) { 417 for (int i = 0; i < num_fec_packets; ++i) {
418 // -- FEC header -- 418 // -- FEC header --
419 generated_fec_packets_[i].data[0] &= 0x7f; // Set E to zero. 419 generated_fec_packets_[i].data[0] &= 0x7f; // Set E to zero.
420 if (l_bit == 0) { 420 if (l_bit == 0) {
421 generated_fec_packets_[i].data[0] &= 0xbf; // Clear the L bit. 421 generated_fec_packets_[i].data[0] &= 0xbf; // Clear the L bit.
422 } else { 422 } else {
423 generated_fec_packets_[i].data[0] |= 0x40; // Set the L bit. 423 generated_fec_packets_[i].data[0] |= 0x40; // Set the L bit.
424 } 424 }
425 // Two byte sequence number from first RTP packet to SN base. 425 // Two byte sequence number from first RTP packet to SN base.
426 // We use the same sequence number base for every FEC packet, 426 // We use the same sequence number base for every FEC packet,
427 // but that's not required in general. 427 // but that's not required in general.
428 memcpy(&generated_fec_packets_[i].data[2], &media_packet->data[2], 2); 428 memcpy(&generated_fec_packets_[i].data[2], &media_packet->data[2], 2);
429 429
430 // -- ULP header -- 430 // -- ULP header --
431 // Copy the payload size to the protection length field. 431 // Copy the payload size to the protection length field.
432 // (We protect the entire packet.) 432 // (We protect the entire packet.)
433 ByteWriter<uint16_t>::WriteBigEndian( 433 ByteWriter<uint16_t>::WriteBigEndian(
434 &generated_fec_packets_[i].data[10], 434 &generated_fec_packets_[i].data[10],
435 generated_fec_packets_[i].length - kFecHeaderSize - ulp_header_size); 435 generated_fec_packets_[i].length - kFecHeaderSize - ulp_header_size);
436 436
437 // Copy the packet mask. 437 // Copy the packet mask.
438 memcpy(&generated_fec_packets_[i].data[12], &packet_mask[i * num_maskBytes], 438 memcpy(&generated_fec_packets_[i].data[12],
439 num_maskBytes); 439 &packet_mask[i * num_mask_bytes], num_mask_bytes);
440 } 440 }
441 } 441 }
442 442
443 void ForwardErrorCorrection::ResetState( 443 void ForwardErrorCorrection::ResetState(
444 RecoveredPacketList* recovered_packet_list) { 444 RecoveredPacketList* recovered_packet_list) {
445 fec_packet_received_ = false; 445 fec_packet_received_ = false;
446 446
447 // Free the memory for any existing recovered packets, if the user hasn't. 447 // Free the memory for any existing recovered packets, if the user hasn't.
448 while (!recovered_packet_list->empty()) { 448 while (!recovered_packet_list->empty()) {
449 delete recovered_packet_list->front(); 449 delete recovered_packet_list->front();
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 } 840 }
841 InsertPackets(received_packet_list, recovered_packet_list); 841 InsertPackets(received_packet_list, recovered_packet_list);
842 AttemptRecover(recovered_packet_list); 842 AttemptRecover(recovered_packet_list);
843 return 0; 843 return 0;
844 } 844 }
845 845
846 size_t ForwardErrorCorrection::PacketOverhead() { 846 size_t ForwardErrorCorrection::PacketOverhead() {
847 return kFecHeaderSize + kUlpHeaderSizeLBitSet; 847 return kFecHeaderSize + kUlpHeaderSizeLBitSet;
848 } 848 }
849 } // namespace webrtc 849 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698