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

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: Added comment 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
« no previous file with comments | « no previous file | webrtc/modules/rtp_rtcp/source/producer_fec_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 // | FEC Level 0 Payload | 105 // | FEC Level 0 Payload |
106 // | | 106 // | |
107 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 107 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108 int32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list, 108 int32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list,
109 uint8_t protection_factor, 109 uint8_t protection_factor,
110 int num_important_packets, 110 int num_important_packets,
111 bool use_unequal_protection, 111 bool use_unequal_protection,
112 FecMaskType fec_mask_type, 112 FecMaskType fec_mask_type,
113 PacketList* fec_packet_list) { 113 PacketList* fec_packet_list) {
114 const uint16_t num_media_packets = media_packet_list.size(); 114 const uint16_t num_media_packets = media_packet_list.size();
115
116 // Sanity check arguments. 115 // Sanity check arguments.
117 assert(num_media_packets > 0); 116 assert(num_media_packets > 0);
118 assert(num_important_packets >= 0 && 117 assert(num_important_packets >= 0 &&
119 num_important_packets <= num_media_packets); 118 num_important_packets <= num_media_packets);
120 assert(fec_packet_list->empty()); 119 assert(fec_packet_list->empty());
121 120
122 if (num_media_packets > kMaxMediaPackets) { 121 if (num_media_packets > kMaxMediaPackets) {
123 LOG(LS_WARNING) << "Can't protect " << num_media_packets 122 LOG(LS_WARNING) << "Can't protect " << num_media_packets
124 << " media packets per frame. Max is " << kMaxMediaPackets; 123 << " media packets per frame. Max is " << kMaxMediaPackets;
125 return -1; 124 return -1;
126 } 125 }
127 126
128 bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear); 127 bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear);
129 int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 128 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
130 129
131 // Do some error checking on the media packets. 130 // Do some error checking on the media packets.
132 for (Packet* media_packet : media_packet_list) { 131 for (Packet* media_packet : media_packet_list) {
133 assert(media_packet); 132 assert(media_packet);
134 133
135 if (media_packet->length < kRtpHeaderSize) { 134 if (media_packet->length < kRtpHeaderSize) {
136 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " 135 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes "
137 << "is smaller than RTP header."; 136 << "is smaller than RTP header.";
138 return -1; 137 return -1;
139 } 138 }
(...skipping 19 matching lines...) Expand all
159 // packets. 158 // packets.
160 fec_packet_list->push_back(&generated_fec_packets_[i]); 159 fec_packet_list->push_back(&generated_fec_packets_[i]);
161 } 160 }
162 161
163 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); 162 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
164 163
165 // -- Generate packet masks -- 164 // -- Generate packet masks --
166 // Always allocate space for a large mask. 165 // Always allocate space for a large mask.
167 rtc::scoped_ptr<uint8_t[]> packet_mask( 166 rtc::scoped_ptr<uint8_t[]> packet_mask(
168 new uint8_t[num_fec_packets * kMaskSizeLBitSet]); 167 new uint8_t[num_fec_packets * kMaskSizeLBitSet]);
169 memset(packet_mask.get(), 0, num_fec_packets * num_maskBytes); 168 memset(packet_mask.get(), 0, num_fec_packets * num_mask_bytes);
170 internal::GeneratePacketMasks(num_media_packets, num_fec_packets, 169 internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
171 num_important_packets, use_unequal_protection, 170 num_important_packets, use_unequal_protection,
172 mask_table, packet_mask.get()); 171 mask_table, packet_mask.get());
173 172
174 int num_mask_bits = InsertZerosInBitMasks( 173 int num_mask_bits = InsertZerosInBitMasks(
175 media_packet_list, packet_mask.get(), num_maskBytes, num_fec_packets); 174 media_packet_list, packet_mask.get(), num_mask_bytes, num_fec_packets);
176
177 l_bit = (num_mask_bits > 8 * kMaskSizeLBitClear);
178 175
179 if (num_mask_bits < 0) { 176 if (num_mask_bits < 0) {
180 return -1; 177 return -1;
181 } 178 }
179 l_bit = (num_mask_bits > 8 * kMaskSizeLBitClear);
182 if (l_bit) { 180 if (l_bit) {
183 num_maskBytes = kMaskSizeLBitSet; 181 num_mask_bytes = kMaskSizeLBitSet;
184 } 182 }
185 183
186 GenerateFecBitStrings(media_packet_list, packet_mask.get(), num_fec_packets, 184 GenerateFecBitStrings(media_packet_list, packet_mask.get(), num_fec_packets,
187 l_bit); 185 l_bit);
188 GenerateFecUlpHeaders(media_packet_list, packet_mask.get(), l_bit, 186 GenerateFecUlpHeaders(media_packet_list, packet_mask.get(), l_bit,
189 num_fec_packets); 187 num_fec_packets);
190 188
191 return 0; 189 return 0;
192 } 190 }
193 191
(...skipping 11 matching lines...) Expand all
205 203
206 void ForwardErrorCorrection::GenerateFecBitStrings( 204 void ForwardErrorCorrection::GenerateFecBitStrings(
207 const PacketList& media_packet_list, 205 const PacketList& media_packet_list,
208 uint8_t* packet_mask, 206 uint8_t* packet_mask,
209 int num_fec_packets, 207 int num_fec_packets,
210 bool l_bit) { 208 bool l_bit) {
211 if (media_packet_list.empty()) { 209 if (media_packet_list.empty()) {
212 return; 210 return;
213 } 211 }
214 uint8_t media_payload_length[2]; 212 uint8_t media_payload_length[2];
215 const int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 213 const int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
216 const uint16_t ulp_header_size = 214 const uint16_t ulp_header_size =
217 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 215 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear;
218 const uint16_t fec_rtp_offset = 216 const uint16_t fec_rtp_offset =
219 kFecHeaderSize + ulp_header_size - kRtpHeaderSize; 217 kFecHeaderSize + ulp_header_size - kRtpHeaderSize;
220 218
221 for (int i = 0; i < num_fec_packets; ++i) { 219 for (int i = 0; i < num_fec_packets; ++i) {
222 PacketList::const_iterator media_list_it = media_packet_list.begin(); 220 PacketList::const_iterator media_list_it = media_packet_list.begin();
223 uint32_t pkt_mask_idx = i * num_maskBytes; 221 uint32_t pkt_mask_idx = i * num_mask_bytes;
224 uint32_t media_pkt_idx = 0; 222 uint32_t media_pkt_idx = 0;
225 uint16_t fec_packet_length = 0; 223 uint16_t fec_packet_length = 0;
226 uint16_t prev_seq_num = ParseSequenceNumber((*media_list_it)->data); 224 uint16_t prev_seq_num = ParseSequenceNumber((*media_list_it)->data);
227 while (media_list_it != media_packet_list.end()) { 225 while (media_list_it != media_packet_list.end()) {
228 // Each FEC packet has a multiple byte mask. 226 // Each FEC packet has a multiple byte mask. Determine if this media
227 // packet should be included in FEC packet i.
229 if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { 228 if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) {
230 Packet* media_packet = *media_list_it; 229 Packet* media_packet = *media_list_it;
231 230
232 // Assign network-ordered media payload length. 231 // Assign network-ordered media payload length.
233 ByteWriter<uint16_t>::WriteBigEndian( 232 ByteWriter<uint16_t>::WriteBigEndian(
234 media_payload_length, media_packet->length - kRtpHeaderSize); 233 media_payload_length, media_packet->length - kRtpHeaderSize);
235 234
236 fec_packet_length = media_packet->length + fec_rtp_offset; 235 fec_packet_length = media_packet->length + fec_rtp_offset;
237 // On the first protected packet, we don't need to XOR. 236 // On the first protected packet, we don't need to XOR.
238 if (generated_fec_packets_[i].length == 0) { 237 if (generated_fec_packets_[i].length == 0) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 if (fec_packet_length > generated_fec_packets_[i].length) { 271 if (fec_packet_length > generated_fec_packets_[i].length) {
273 generated_fec_packets_[i].length = fec_packet_length; 272 generated_fec_packets_[i].length = fec_packet_length;
274 } 273 }
275 } 274 }
276 media_list_it++; 275 media_list_it++;
277 if (media_list_it != media_packet_list.end()) { 276 if (media_list_it != media_packet_list.end()) {
278 uint16_t seq_num = ParseSequenceNumber((*media_list_it)->data); 277 uint16_t seq_num = ParseSequenceNumber((*media_list_it)->data);
279 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); 278 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num);
280 prev_seq_num = seq_num; 279 prev_seq_num = seq_num;
281 } 280 }
282 if (media_pkt_idx == 8) { 281 pkt_mask_idx += media_pkt_idx / 8;
283 // Switch to the next mask byte. 282 media_pkt_idx %= 8;
284 media_pkt_idx = 0;
285 pkt_mask_idx++;
286 }
287 } 283 }
288 assert(generated_fec_packets_[i].length); 284 RTC_DCHECK_GT(generated_fec_packets_[i].length, 0u)
289 // Note: This shouldn't happen: means packet mask is wrong or poorly 285 << "Packet mask is wrong or poorly designed.";
290 // designed
291 } 286 }
292 } 287 }
293 288
294 int ForwardErrorCorrection::InsertZerosInBitMasks( 289 int ForwardErrorCorrection::InsertZerosInBitMasks(
295 const PacketList& media_packets, 290 const PacketList& media_packets,
296 uint8_t* packet_mask, 291 uint8_t* packet_mask,
297 int num_mask_bytes, 292 int num_mask_bytes,
298 int num_fec_packets) { 293 int num_fec_packets) {
299 uint8_t* new_mask = NULL; 294 uint8_t* new_mask = NULL;
300 if (media_packets.size() <= 1) { 295 if (media_packets.size() <= 1) {
301 return media_packets.size(); 296 return media_packets.size();
302 } 297 }
303 int last_seq_num = ParseSequenceNumber(media_packets.back()->data); 298 int last_seq_num = ParseSequenceNumber(media_packets.back()->data);
304 int first_seq_num = ParseSequenceNumber(media_packets.front()->data); 299 int first_seq_num = ParseSequenceNumber(media_packets.front()->data);
305 int total_missing_seq_nums = 300 int total_missing_seq_nums =
306 static_cast<uint16_t>(last_seq_num - first_seq_num) - 301 static_cast<uint16_t>(last_seq_num - first_seq_num) -
307 media_packets.size() + 1; 302 media_packets.size() + 1;
308 if (total_missing_seq_nums == 0) { 303 if (total_missing_seq_nums == 0) {
309 // All sequence numbers are covered by the packet mask. No zero insertion 304 // All sequence numbers are covered by the packet mask. No zero insertion
310 // required. 305 // required.
311 return media_packets.size(); 306 return media_packets.size();
312 } 307 }
308 // We can only protect 8 * kMaskSizeLBitSet packets.
309 if (total_missing_seq_nums + media_packets.size() > 8 * kMaskSizeLBitSet)
310 return -1;
313 // Allocate the new mask. 311 // Allocate the new mask.
314 int new_mask_bytes = kMaskSizeLBitClear; 312 int new_mask_bytes = kMaskSizeLBitClear;
315 if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) { 313 if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) {
316 new_mask_bytes = kMaskSizeLBitSet; 314 new_mask_bytes = kMaskSizeLBitSet;
317 } 315 }
318 new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet]; 316 new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet];
319 memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet); 317 memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet);
320 318
321 PacketList::const_iterator it = media_packets.begin(); 319 PacketList::const_iterator it = media_packets.begin();
322 uint16_t prev_seq_num = first_seq_num; 320 uint16_t prev_seq_num = first_seq_num;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 // 0 1 2 3 412 // 0 1 2 3
415 // 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 413 // 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
416 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 414 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417 // | Protection Length | mask | 415 // | Protection Length | mask |
418 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 416 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
419 // | mask cont. (present only when L = 1) | 417 // | mask cont. (present only when L = 1) |
420 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 418 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421 PacketList::const_iterator media_list_it = media_packet_list.begin(); 419 PacketList::const_iterator media_list_it = media_packet_list.begin();
422 Packet* media_packet = *media_list_it; 420 Packet* media_packet = *media_list_it;
423 assert(media_packet != NULL); 421 assert(media_packet != NULL);
424 int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 422 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
425 const uint16_t ulp_header_size = 423 const uint16_t ulp_header_size =
426 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 424 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear;
427 425
428 for (int i = 0; i < num_fec_packets; ++i) { 426 for (int i = 0; i < num_fec_packets; ++i) {
429 // -- FEC header -- 427 // -- FEC header --
430 generated_fec_packets_[i].data[0] &= 0x7f; // Set E to zero. 428 generated_fec_packets_[i].data[0] &= 0x7f; // Set E to zero.
431 if (l_bit == 0) { 429 if (l_bit == 0) {
432 generated_fec_packets_[i].data[0] &= 0xbf; // Clear the L bit. 430 generated_fec_packets_[i].data[0] &= 0xbf; // Clear the L bit.
433 } else { 431 } else {
434 generated_fec_packets_[i].data[0] |= 0x40; // Set the L bit. 432 generated_fec_packets_[i].data[0] |= 0x40; // Set the L bit.
435 } 433 }
436 // Two byte sequence number from first RTP packet to SN base. 434 // Two byte sequence number from first RTP packet to SN base.
437 // We use the same sequence number base for every FEC packet, 435 // We use the same sequence number base for every FEC packet,
438 // but that's not required in general. 436 // but that's not required in general.
439 memcpy(&generated_fec_packets_[i].data[2], &media_packet->data[2], 2); 437 memcpy(&generated_fec_packets_[i].data[2], &media_packet->data[2], 2);
440 438
441 // -- ULP header -- 439 // -- ULP header --
442 // Copy the payload size to the protection length field. 440 // Copy the payload size to the protection length field.
443 // (We protect the entire packet.) 441 // (We protect the entire packet.)
444 ByteWriter<uint16_t>::WriteBigEndian( 442 ByteWriter<uint16_t>::WriteBigEndian(
445 &generated_fec_packets_[i].data[10], 443 &generated_fec_packets_[i].data[10],
446 generated_fec_packets_[i].length - kFecHeaderSize - ulp_header_size); 444 generated_fec_packets_[i].length - kFecHeaderSize - ulp_header_size);
447 445
448 // Copy the packet mask. 446 // Copy the packet mask.
449 memcpy(&generated_fec_packets_[i].data[12], &packet_mask[i * num_maskBytes], 447 memcpy(&generated_fec_packets_[i].data[12],
450 num_maskBytes); 448 &packet_mask[i * num_mask_bytes], num_mask_bytes);
451 } 449 }
452 } 450 }
453 451
454 void ForwardErrorCorrection::ResetState( 452 void ForwardErrorCorrection::ResetState(
455 RecoveredPacketList* recovered_packet_list) { 453 RecoveredPacketList* recovered_packet_list) {
456 fec_packet_received_ = false; 454 fec_packet_received_ = false;
457 455
458 // Free the memory for any existing recovered packets, if the user hasn't. 456 // Free the memory for any existing recovered packets, if the user hasn't.
459 while (!recovered_packet_list->empty()) { 457 while (!recovered_packet_list->empty()) {
460 delete recovered_packet_list->front(); 458 delete recovered_packet_list->front();
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 } 850 }
853 InsertPackets(received_packet_list, recovered_packet_list); 851 InsertPackets(received_packet_list, recovered_packet_list);
854 AttemptRecover(recovered_packet_list); 852 AttemptRecover(recovered_packet_list);
855 return 0; 853 return 0;
856 } 854 }
857 855
858 size_t ForwardErrorCorrection::PacketOverhead() { 856 size_t ForwardErrorCorrection::PacketOverhead() {
859 return kFecHeaderSize + kUlpHeaderSizeLBitSet; 857 return kFecHeaderSize + kUlpHeaderSizeLBitSet;
860 } 858 }
861 } // namespace webrtc 859 } // namespace webrtc
OLDNEW
« no previous file with comments | « no previous file | webrtc/modules/rtp_rtcp/source/producer_fec_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698