| 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/fec_test_helper.h" | 11 #include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h" |
| 12 | 12 |
| 13 #include <memory> |
| 14 #include <utility> |
| 15 |
| 13 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 16 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
| 14 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | 17 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" |
| 15 | 18 |
| 16 namespace webrtc { | 19 namespace webrtc { |
| 20 namespace test { |
| 21 namespace fec { |
| 22 |
| 23 namespace { |
| 24 constexpr uint8_t kFecPayloadType = 96; |
| 25 constexpr uint8_t kRedPayloadType = 97; |
| 26 constexpr uint8_t kVp8PayloadType = 120; |
| 27 } // namespace |
| 17 | 28 |
| 18 FrameGenerator::FrameGenerator() | 29 FrameGenerator::FrameGenerator() |
| 19 : num_packets_(0), seq_num_(0), timestamp_(0) {} | 30 : num_packets_(0), seq_num_(0), timestamp_(0) {} |
| 20 | 31 |
| 21 void FrameGenerator::NewFrame(int num_packets) { | 32 void FrameGenerator::NewFrame(int num_packets) { |
| 22 num_packets_ = num_packets; | 33 num_packets_ = num_packets; |
| 23 timestamp_ += 3000; | 34 timestamp_ += 3000; |
| 24 } | 35 } |
| 25 | 36 |
| 26 uint16_t FrameGenerator::NextSeqNum() { return ++seq_num_; } | 37 uint16_t FrameGenerator::NextSeqNum() { return ++seq_num_; } |
| 27 | 38 |
| 28 test::RawRtpPacket* FrameGenerator::NextPacket(int offset, size_t length) { | 39 RawRtpPacket* FrameGenerator::NextPacket(int offset, size_t length) { |
| 29 test::RawRtpPacket* rtp_packet = new test::RawRtpPacket; | 40 RawRtpPacket* rtp_packet = new RawRtpPacket; |
| 30 for (size_t i = 0; i < length; ++i) | 41 for (size_t i = 0; i < length; ++i) |
| 31 rtp_packet->data[i + kRtpHeaderSize] = offset + i; | 42 rtp_packet->data[i + kRtpHeaderSize] = offset + i; |
| 32 rtp_packet->length = length + kRtpHeaderSize; | 43 rtp_packet->length = length + kRtpHeaderSize; |
| 33 memset(&rtp_packet->header, 0, sizeof(WebRtcRTPHeader)); | 44 memset(&rtp_packet->header, 0, sizeof(WebRtcRTPHeader)); |
| 34 rtp_packet->header.frameType = kVideoFrameDelta; | 45 rtp_packet->header.frameType = kVideoFrameDelta; |
| 35 rtp_packet->header.header.headerLength = kRtpHeaderSize; | 46 rtp_packet->header.header.headerLength = kRtpHeaderSize; |
| 36 rtp_packet->header.header.markerBit = (num_packets_ == 1); | 47 rtp_packet->header.header.markerBit = (num_packets_ == 1); |
| 37 rtp_packet->header.header.sequenceNumber = seq_num_; | 48 rtp_packet->header.header.sequenceNumber = seq_num_; |
| 38 rtp_packet->header.header.timestamp = timestamp_; | 49 rtp_packet->header.header.timestamp = timestamp_; |
| 39 rtp_packet->header.header.payloadType = kVp8PayloadType; | 50 rtp_packet->header.header.payloadType = kVp8PayloadType; |
| 40 BuildRtpHeader(rtp_packet->data, &rtp_packet->header.header); | 51 BuildRtpHeader(rtp_packet->data, &rtp_packet->header.header); |
| 41 ++seq_num_; | 52 ++seq_num_; |
| 42 --num_packets_; | 53 --num_packets_; |
| 43 return rtp_packet; | 54 return rtp_packet; |
| 44 } | 55 } |
| 45 | 56 |
| 46 // Creates a new RtpPacket with the RED header added to the packet. | 57 // Creates a new RtpPacket with the RED header added to the packet. |
| 47 test::RawRtpPacket* FrameGenerator::BuildMediaRedPacket( | 58 RawRtpPacket* FrameGenerator::BuildMediaRedPacket(const RawRtpPacket* packet) { |
| 48 const test::RawRtpPacket* packet) { | |
| 49 const size_t kHeaderLength = packet->header.header.headerLength; | 59 const size_t kHeaderLength = packet->header.header.headerLength; |
| 50 test::RawRtpPacket* red_packet = new test::RawRtpPacket; | 60 RawRtpPacket* red_packet = new RawRtpPacket; |
| 51 red_packet->header = packet->header; | 61 red_packet->header = packet->header; |
| 52 red_packet->length = packet->length + 1; // 1 byte RED header. | 62 red_packet->length = packet->length + 1; // 1 byte RED header. |
| 53 memset(red_packet->data, 0, red_packet->length); | 63 memset(red_packet->data, 0, red_packet->length); |
| 54 // Copy RTP header. | 64 // Copy RTP header. |
| 55 memcpy(red_packet->data, packet->data, kHeaderLength); | 65 memcpy(red_packet->data, packet->data, kHeaderLength); |
| 56 SetRedHeader(red_packet, red_packet->data[1] & 0x7f, kHeaderLength); | 66 SetRedHeader(red_packet, red_packet->data[1] & 0x7f, kHeaderLength); |
| 57 memcpy(red_packet->data + kHeaderLength + 1, packet->data + kHeaderLength, | 67 memcpy(red_packet->data + kHeaderLength + 1, packet->data + kHeaderLength, |
| 58 packet->length - kHeaderLength); | 68 packet->length - kHeaderLength); |
| 59 return red_packet; | 69 return red_packet; |
| 60 } | 70 } |
| 61 | 71 |
| 62 // Creates a new RtpPacket with FEC payload and red header. Does this by | 72 // Creates a new RtpPacket with FEC payload and RED header. Does this by |
| 63 // creating a new fake media RtpPacket, clears the marker bit and adds a RED | 73 // creating a new fake media RtpPacket, clears the marker bit and adds a RED |
| 64 // header. Finally replaces the payload with the content of |packet->data|. | 74 // header. Finally replaces the payload with the content of |packet->data|. |
| 65 test::RawRtpPacket* FrameGenerator::BuildFecRedPacket( | 75 RawRtpPacket* FrameGenerator::BuildFecRedPacket( |
| 66 const ForwardErrorCorrection::Packet* packet) { | 76 const ForwardErrorCorrection::Packet* packet) { |
| 67 // Create a fake media packet to get a correct header. 1 byte RED header. | 77 // Create a fake media packet to get a correct header. 1 byte RED header. |
| 68 ++num_packets_; | 78 ++num_packets_; |
| 69 test::RawRtpPacket* red_packet = NextPacket(0, packet->length + 1); | 79 RawRtpPacket* red_packet = NextPacket(0, packet->length + 1); |
| 70 red_packet->data[1] &= ~0x80; // Clear marker bit. | 80 red_packet->data[1] &= ~0x80; // Clear marker bit. |
| 71 const size_t kHeaderLength = red_packet->header.header.headerLength; | 81 const size_t kHeaderLength = red_packet->header.header.headerLength; |
| 72 SetRedHeader(red_packet, kFecPayloadType, kHeaderLength); | 82 SetRedHeader(red_packet, kFecPayloadType, kHeaderLength); |
| 73 memcpy(red_packet->data + kHeaderLength + 1, packet->data, packet->length); | 83 memcpy(red_packet->data + kHeaderLength + 1, packet->data, packet->length); |
| 74 red_packet->length = kHeaderLength + 1 + packet->length; | 84 red_packet->length = kHeaderLength + 1 + packet->length; |
| 75 return red_packet; | 85 return red_packet; |
| 76 } | 86 } |
| 77 | 87 |
| 78 void FrameGenerator::SetRedHeader(ForwardErrorCorrection::Packet* red_packet, | 88 void FrameGenerator::SetRedHeader(ForwardErrorCorrection::Packet* red_packet, |
| 79 uint8_t payload_type, | 89 uint8_t payload_type, |
| 80 size_t header_length) const { | 90 size_t header_length) const { |
| 81 // Replace pltype. | 91 // Replace pltype. |
| 82 red_packet->data[1] &= 0x80; // Reset. | 92 red_packet->data[1] &= 0x80; // Reset. |
| 83 red_packet->data[1] += kRedPayloadType; // Replace. | 93 red_packet->data[1] += kRedPayloadType; // Replace. |
| 84 | 94 |
| 85 // Add RED header, f-bit always 0. | 95 // Add RED header, f-bit always 0. |
| 86 red_packet->data[header_length] = payload_type; | 96 red_packet->data[header_length] = payload_type; |
| 87 } | 97 } |
| 88 | 98 |
| 89 void FrameGenerator::BuildRtpHeader(uint8_t* data, const RTPHeader* header) { | 99 void FrameGenerator::BuildRtpHeader(uint8_t* data, const RTPHeader* header) { |
| 90 data[0] = 0x80; // Version 2. | 100 data[0] = 0x80; // Version 2. |
| 91 data[1] = header->payloadType; | 101 data[1] = header->payloadType; |
| 92 data[1] |= (header->markerBit ? kRtpMarkerBitMask : 0); | 102 data[1] |= (header->markerBit ? kRtpMarkerBitMask : 0); |
| 93 ByteWriter<uint16_t>::WriteBigEndian(data + 2, header->sequenceNumber); | 103 ByteWriter<uint16_t>::WriteBigEndian(data + 2, header->sequenceNumber); |
| 94 ByteWriter<uint32_t>::WriteBigEndian(data + 4, header->timestamp); | 104 ByteWriter<uint32_t>::WriteBigEndian(data + 4, header->timestamp); |
| 95 ByteWriter<uint32_t>::WriteBigEndian(data + 8, header->ssrc); | 105 ByteWriter<uint32_t>::WriteBigEndian(data + 8, header->ssrc); |
| 96 } | 106 } |
| 97 | 107 |
| 108 ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( |
| 109 int num_media_packets, |
| 110 uint16_t start_seq_num) { |
| 111 RTC_DCHECK_GT(num_media_packets, 0); |
| 112 uint16_t seq_num = start_seq_num; |
| 113 int time_stamp = random_->Rand<int>(); |
| 114 |
| 115 ForwardErrorCorrection::PacketList media_packets; |
| 116 |
| 117 for (int i = 0; i < num_media_packets; ++i) { |
| 118 std::unique_ptr<ForwardErrorCorrection::Packet> media_packet( |
| 119 new ForwardErrorCorrection::Packet()); |
| 120 media_packet->length = random_->Rand(min_packet_size_, max_packet_size_); |
| 121 |
| 122 // Generate random values for the first 2 bytes |
| 123 media_packet->data[0] = random_->Rand<uint8_t>(); |
| 124 media_packet->data[1] = random_->Rand<uint8_t>(); |
| 125 |
| 126 // The first two bits are assumed to be 10 by the FEC encoder. |
| 127 // In fact the FEC decoder will set the two first bits to 10 regardless of |
| 128 // what they actually were. Set the first two bits to 10 so that a memcmp |
| 129 // can be performed for the whole restored packet. |
| 130 media_packet->data[0] |= 0x80; |
| 131 media_packet->data[0] &= 0xbf; |
| 132 |
| 133 // FEC is applied to a whole frame. |
| 134 // A frame is signaled by multiple packets without the marker bit set |
| 135 // followed by the last packet of the frame for which the marker bit is set. |
| 136 // Only push one (fake) frame to the FEC. |
| 137 media_packet->data[1] &= 0x7f; |
| 138 |
| 139 webrtc::ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2], |
| 140 seq_num); |
| 141 webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4], |
| 142 time_stamp); |
| 143 webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], ssrc_); |
| 144 |
| 145 // Generate random values for payload. |
| 146 for (size_t j = 12; j < media_packet->length; ++j) { |
| 147 media_packet->data[j] = random_->Rand<uint8_t>(); |
| 148 } |
| 149 seq_num++; |
| 150 media_packets.push_back(std::move(media_packet)); |
| 151 } |
| 152 // Last packet, set marker bit. |
| 153 ForwardErrorCorrection::Packet* media_packet = media_packets.back().get(); |
| 154 RTC_DCHECK(media_packet); |
| 155 media_packet->data[1] |= 0x80; |
| 156 |
| 157 fec_seq_num_ = seq_num; |
| 158 |
| 159 return media_packets; |
| 160 } |
| 161 |
| 162 ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( |
| 163 int num_media_packets) { |
| 164 return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>()); |
| 165 } |
| 166 |
| 167 uint16_t MediaPacketGenerator::GetFecSeqNum() { |
| 168 return fec_seq_num_; |
| 169 } |
| 170 |
| 171 } // namespace fec |
| 172 } // namespace test |
| 98 } // namespace webrtc | 173 } // namespace webrtc |
| OLD | NEW |