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/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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |