stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 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 |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "modules/rtp_rtcp/source/fec_test_helper.h" |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 12 | |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 13 | #include <memory> |
| 14 | #include <utility> |
| 15 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 16 | #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
| 17 | #include "modules/rtp_rtcp/source/byte_io.h" |
| 18 | #include "modules/rtp_rtcp/source/rtp_utility.h" |
| 19 | #include "rtc_base/checks.h" |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 20 | |
| 21 | namespace webrtc { |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 22 | namespace test { |
| 23 | namespace fec { |
| 24 | |
| 25 | namespace { |
| 26 | constexpr uint8_t kFecPayloadType = 96; |
| 27 | constexpr uint8_t kRedPayloadType = 97; |
| 28 | constexpr uint8_t kVp8PayloadType = 120; |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 29 | |
| 30 | constexpr int kPacketTimestampIncrement = 3000; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 31 | } // namespace |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 32 | |
Danil Chapovalov | dd7e284 | 2018-03-09 15:37:03 +0000 | [diff] [blame^] | 33 | MediaPacketGenerator::MediaPacketGenerator(uint32_t min_packet_size, |
| 34 | uint32_t max_packet_size, |
| 35 | uint32_t ssrc, |
| 36 | Random* random) |
| 37 | : min_packet_size_(min_packet_size), |
| 38 | max_packet_size_(max_packet_size), |
| 39 | ssrc_(ssrc), |
| 40 | random_(random) {} |
| 41 | |
| 42 | MediaPacketGenerator::~MediaPacketGenerator() = default; |
| 43 | |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 44 | ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( |
| 45 | int num_media_packets, |
| 46 | uint16_t start_seq_num) { |
| 47 | RTC_DCHECK_GT(num_media_packets, 0); |
| 48 | uint16_t seq_num = start_seq_num; |
| 49 | int time_stamp = random_->Rand<int>(); |
| 50 | |
| 51 | ForwardErrorCorrection::PacketList media_packets; |
| 52 | |
| 53 | for (int i = 0; i < num_media_packets; ++i) { |
| 54 | std::unique_ptr<ForwardErrorCorrection::Packet> media_packet( |
| 55 | new ForwardErrorCorrection::Packet()); |
| 56 | media_packet->length = random_->Rand(min_packet_size_, max_packet_size_); |
| 57 | |
| 58 | // Generate random values for the first 2 bytes |
| 59 | media_packet->data[0] = random_->Rand<uint8_t>(); |
| 60 | media_packet->data[1] = random_->Rand<uint8_t>(); |
| 61 | |
| 62 | // The first two bits are assumed to be 10 by the FEC encoder. |
| 63 | // In fact the FEC decoder will set the two first bits to 10 regardless of |
| 64 | // what they actually were. Set the first two bits to 10 so that a memcmp |
| 65 | // can be performed for the whole restored packet. |
| 66 | media_packet->data[0] |= 0x80; |
| 67 | media_packet->data[0] &= 0xbf; |
| 68 | |
| 69 | // FEC is applied to a whole frame. |
| 70 | // A frame is signaled by multiple packets without the marker bit set |
| 71 | // followed by the last packet of the frame for which the marker bit is set. |
| 72 | // Only push one (fake) frame to the FEC. |
| 73 | media_packet->data[1] &= 0x7f; |
| 74 | |
| 75 | webrtc::ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2], |
| 76 | seq_num); |
| 77 | webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4], |
| 78 | time_stamp); |
| 79 | webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], ssrc_); |
| 80 | |
| 81 | // Generate random values for payload. |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 82 | for (size_t j = 12; j < media_packet->length; ++j) |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 83 | media_packet->data[j] = random_->Rand<uint8_t>(); |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 84 | seq_num++; |
| 85 | media_packets.push_back(std::move(media_packet)); |
| 86 | } |
| 87 | // Last packet, set marker bit. |
| 88 | ForwardErrorCorrection::Packet* media_packet = media_packets.back().get(); |
| 89 | RTC_DCHECK(media_packet); |
| 90 | media_packet->data[1] |= 0x80; |
| 91 | |
brandtr | d726a3f | 2017-06-29 02:45:35 -0700 | [diff] [blame] | 92 | next_seq_num_ = seq_num; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 93 | |
| 94 | return media_packets; |
| 95 | } |
| 96 | |
| 97 | ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( |
| 98 | int num_media_packets) { |
| 99 | return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>()); |
| 100 | } |
| 101 | |
brandtr | d726a3f | 2017-06-29 02:45:35 -0700 | [diff] [blame] | 102 | uint16_t MediaPacketGenerator::GetNextSeqNum() { |
| 103 | return next_seq_num_; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 104 | } |
| 105 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 106 | AugmentedPacketGenerator::AugmentedPacketGenerator(uint32_t ssrc) |
| 107 | : num_packets_(0), ssrc_(ssrc), seq_num_(0), timestamp_(0) {} |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 108 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 109 | void AugmentedPacketGenerator::NewFrame(size_t num_packets) { |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 110 | num_packets_ = num_packets; |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 111 | timestamp_ += kPacketTimestampIncrement; |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 112 | } |
| 113 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 114 | uint16_t AugmentedPacketGenerator::NextPacketSeqNum() { |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 115 | return ++seq_num_; |
| 116 | } |
| 117 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 118 | std::unique_ptr<AugmentedPacket> AugmentedPacketGenerator::NextPacket( |
| 119 | size_t offset, |
| 120 | size_t length) { |
| 121 | std::unique_ptr<AugmentedPacket> packet(new AugmentedPacket()); |
| 122 | |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 123 | for (size_t i = 0; i < length; ++i) |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 124 | packet->data[i + kRtpHeaderSize] = offset + i; |
| 125 | packet->length = length + kRtpHeaderSize; |
| 126 | memset(&packet->header, 0, sizeof(WebRtcRTPHeader)); |
| 127 | packet->header.frameType = kVideoFrameDelta; |
| 128 | packet->header.header.headerLength = kRtpHeaderSize; |
| 129 | packet->header.header.markerBit = (num_packets_ == 1); |
| 130 | packet->header.header.payloadType = kVp8PayloadType; |
| 131 | packet->header.header.sequenceNumber = seq_num_; |
| 132 | packet->header.header.timestamp = timestamp_; |
| 133 | packet->header.header.ssrc = ssrc_; |
| 134 | WriteRtpHeader(packet->header.header, packet->data); |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 135 | ++seq_num_; |
| 136 | --num_packets_; |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 137 | |
| 138 | return packet; |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 139 | } |
| 140 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 141 | void AugmentedPacketGenerator::WriteRtpHeader(const RTPHeader& header, |
| 142 | uint8_t* data) { |
| 143 | data[0] = 0x80; // Version 2. |
| 144 | data[1] = header.payloadType; |
| 145 | data[1] |= (header.markerBit ? kRtpMarkerBitMask : 0); |
| 146 | ByteWriter<uint16_t>::WriteBigEndian(data + 2, header.sequenceNumber); |
| 147 | ByteWriter<uint32_t>::WriteBigEndian(data + 4, header.timestamp); |
| 148 | ByteWriter<uint32_t>::WriteBigEndian(data + 8, header.ssrc); |
| 149 | } |
| 150 | |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 151 | FlexfecPacketGenerator::FlexfecPacketGenerator(uint32_t media_ssrc, |
| 152 | uint32_t flexfec_ssrc) |
| 153 | : AugmentedPacketGenerator(media_ssrc), |
| 154 | flexfec_ssrc_(flexfec_ssrc), |
| 155 | flexfec_seq_num_(0), |
| 156 | flexfec_timestamp_(0) {} |
| 157 | |
| 158 | std::unique_ptr<AugmentedPacket> FlexfecPacketGenerator::BuildFlexfecPacket( |
| 159 | const ForwardErrorCorrection::Packet& packet) { |
| 160 | RTC_DCHECK_LE(packet.length, |
| 161 | static_cast<size_t>(IP_PACKET_SIZE - kRtpHeaderSize)); |
| 162 | |
| 163 | RTPHeader header; |
| 164 | header.sequenceNumber = flexfec_seq_num_; |
| 165 | ++flexfec_seq_num_; |
| 166 | header.timestamp = flexfec_timestamp_; |
| 167 | flexfec_timestamp_ += kPacketTimestampIncrement; |
| 168 | header.ssrc = flexfec_ssrc_; |
| 169 | |
| 170 | std::unique_ptr<AugmentedPacket> packet_with_rtp_header( |
| 171 | new AugmentedPacket()); |
| 172 | WriteRtpHeader(header, packet_with_rtp_header->data); |
| 173 | memcpy(packet_with_rtp_header->data + kRtpHeaderSize, packet.data, |
| 174 | packet.length); |
| 175 | packet_with_rtp_header->length = kRtpHeaderSize + packet.length; |
| 176 | |
| 177 | return packet_with_rtp_header; |
| 178 | } |
| 179 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 180 | UlpfecPacketGenerator::UlpfecPacketGenerator(uint32_t ssrc) |
| 181 | : AugmentedPacketGenerator(ssrc) {} |
| 182 | |
| 183 | std::unique_ptr<AugmentedPacket> UlpfecPacketGenerator::BuildMediaRedPacket( |
| 184 | const AugmentedPacket& packet) { |
| 185 | std::unique_ptr<AugmentedPacket> red_packet(new AugmentedPacket()); |
| 186 | |
| 187 | const size_t kHeaderLength = packet.header.header.headerLength; |
| 188 | red_packet->header = packet.header; |
| 189 | red_packet->length = packet.length + 1; // 1 byte RED header. |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 190 | // Copy RTP header. |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 191 | memcpy(red_packet->data, packet.data, kHeaderLength); |
| 192 | SetRedHeader(red_packet->data[1] & 0x7f, kHeaderLength, red_packet.get()); |
| 193 | memcpy(red_packet->data + kHeaderLength + 1, packet.data + kHeaderLength, |
| 194 | packet.length - kHeaderLength); |
| 195 | |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 196 | return red_packet; |
| 197 | } |
| 198 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 199 | std::unique_ptr<AugmentedPacket> UlpfecPacketGenerator::BuildUlpfecRedPacket( |
| 200 | const ForwardErrorCorrection::Packet& packet) { |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 201 | // Create a fake media packet to get a correct header. 1 byte RED header. |
| 202 | ++num_packets_; |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 203 | std::unique_ptr<AugmentedPacket> red_packet = |
| 204 | NextPacket(0, packet.length + 1); |
| 205 | |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 206 | red_packet->data[1] &= ~0x80; // Clear marker bit. |
| 207 | const size_t kHeaderLength = red_packet->header.header.headerLength; |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 208 | SetRedHeader(kFecPayloadType, kHeaderLength, red_packet.get()); |
| 209 | memcpy(red_packet->data + kHeaderLength + 1, packet.data, packet.length); |
| 210 | red_packet->length = kHeaderLength + 1 + packet.length; |
| 211 | |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 212 | return red_packet; |
| 213 | } |
| 214 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 215 | void UlpfecPacketGenerator::SetRedHeader(uint8_t payload_type, |
| 216 | size_t header_length, |
| 217 | AugmentedPacket* red_packet) { |
| 218 | // Replace payload type. |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 219 | red_packet->data[1] &= 0x80; // Reset. |
| 220 | red_packet->data[1] += kRedPayloadType; // Replace. |
| 221 | |
| 222 | // Add RED header, f-bit always 0. |
| 223 | red_packet->data[header_length] = payload_type; |
| 224 | } |
| 225 | |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 226 | } // namespace fec |
| 227 | } // namespace test |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 228 | } // namespace webrtc |