RTPFile.cc (7799B)
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 11 #include "RTPFile.h" 12 13 #include <sys/types.h> 14 15 #include <cstdint> 16 #include <cstdio> 17 #include <cstdlib> 18 #include <cstring> 19 #include <limits> 20 #include <string> 21 22 #include "absl/strings/string_view.h" 23 #include "api/rtp_headers.h" 24 #include "rtc_base/ip_address.h" 25 #include "rtc_base/synchronization/mutex.h" 26 27 #ifdef WIN32 28 #include <Winsock2.h> 29 #else 30 #endif 31 32 // TODO(tlegrand): Consider removing usage of gtest. 33 #include "test/gtest.h" 34 35 namespace webrtc { 36 37 void RTPStream::ParseRTPHeader(RTPHeader* rtp_header, 38 const uint8_t* rtpHeader) { 39 rtp_header->payloadType = rtpHeader[1]; 40 rtp_header->sequenceNumber = 41 (static_cast<uint16_t>(rtpHeader[2]) << 8) | rtpHeader[3]; 42 rtp_header->timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) | 43 (static_cast<uint32_t>(rtpHeader[5]) << 16) | 44 (static_cast<uint32_t>(rtpHeader[6]) << 8) | 45 rtpHeader[7]; 46 rtp_header->ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) | 47 (static_cast<uint32_t>(rtpHeader[9]) << 16) | 48 (static_cast<uint32_t>(rtpHeader[10]) << 8) | 49 rtpHeader[11]; 50 } 51 52 void RTPStream::MakeRTPheader(uint8_t* rtpHeader, 53 uint8_t payloadType, 54 int16_t seqNo, 55 uint32_t timeStamp, 56 uint32_t ssrc) { 57 rtpHeader[0] = 0x80; 58 rtpHeader[1] = payloadType; 59 rtpHeader[2] = (seqNo >> 8) & 0xFF; 60 rtpHeader[3] = seqNo & 0xFF; 61 rtpHeader[4] = timeStamp >> 24; 62 rtpHeader[5] = (timeStamp >> 16) & 0xFF; 63 rtpHeader[6] = (timeStamp >> 8) & 0xFF; 64 rtpHeader[7] = timeStamp & 0xFF; 65 rtpHeader[8] = ssrc >> 24; 66 rtpHeader[9] = (ssrc >> 16) & 0xFF; 67 rtpHeader[10] = (ssrc >> 8) & 0xFF; 68 rtpHeader[11] = ssrc & 0xFF; 69 } 70 71 RTPPacket::RTPPacket(uint8_t payloadType, 72 uint32_t timeStamp, 73 int16_t seqNo, 74 const uint8_t* payloadData, 75 size_t payloadSize, 76 uint32_t frequency) 77 : payloadType(payloadType), 78 timeStamp(timeStamp), 79 seqNo(seqNo), 80 payloadSize(payloadSize), 81 frequency(frequency) { 82 if (payloadSize > 0) { 83 this->payloadData = new uint8_t[payloadSize]; 84 memcpy(this->payloadData, payloadData, payloadSize); 85 } 86 } 87 88 RTPPacket::~RTPPacket() { 89 delete[] payloadData; 90 } 91 92 void RTPBuffer::Write(const uint8_t payloadType, 93 const uint32_t timeStamp, 94 const int16_t seqNo, 95 const uint8_t* payloadData, 96 const size_t payloadSize, 97 uint32_t frequency) { 98 RTPPacket* packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData, 99 payloadSize, frequency); 100 MutexLock lock(&mutex_); 101 _rtpQueue.push(packet); 102 } 103 104 size_t RTPBuffer::Read(RTPHeader* rtp_header, 105 uint8_t* payloadData, 106 size_t payloadSize, 107 uint32_t* offset) { 108 RTPPacket* packet; 109 { 110 MutexLock lock(&mutex_); 111 packet = _rtpQueue.front(); 112 _rtpQueue.pop(); 113 } 114 rtp_header->markerBit = 1; 115 rtp_header->payloadType = packet->payloadType; 116 rtp_header->sequenceNumber = packet->seqNo; 117 rtp_header->ssrc = 0; 118 rtp_header->timestamp = packet->timeStamp; 119 if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) { 120 memcpy(payloadData, packet->payloadData, packet->payloadSize); 121 } else { 122 return 0; 123 } 124 *offset = (packet->timeStamp / (packet->frequency / 1000)); 125 126 return packet->payloadSize; 127 } 128 129 bool RTPBuffer::EndOfFile() const { 130 MutexLock lock(&mutex_); 131 return _rtpQueue.empty(); 132 } 133 134 void RTPFile::Open(absl::string_view filename, absl::string_view mode) { 135 std::string filename_str = std::string(filename); 136 if ((_rtpFile = fopen(filename_str.c_str(), std::string(mode).c_str())) == 137 nullptr) { 138 printf("Cannot write file %s.\n", filename_str.c_str()); 139 ADD_FAILURE() << "Unable to write file"; 140 exit(1); 141 } 142 } 143 144 void RTPFile::Close() { 145 if (_rtpFile != nullptr) { 146 fclose(_rtpFile); 147 _rtpFile = nullptr; 148 } 149 } 150 151 void RTPFile::WriteHeader() { 152 // Write data in a format that NetEQ and RTP Play can parse 153 fprintf(_rtpFile, "#!RTPencode%s\n", "1.0"); 154 uint32_t dummy_variable = 0; 155 // should be converted to network endian format, but does not matter when 0 156 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile)); 157 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile)); 158 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile)); 159 EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile)); 160 EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile)); 161 fflush(_rtpFile); 162 } 163 164 void RTPFile::ReadHeader() { 165 uint32_t start_sec, start_usec, source; 166 uint16_t port, padding; 167 char fileHeader[40]; 168 EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != nullptr); 169 EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile)); 170 start_sec = ntohl(start_sec); 171 EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile)); 172 start_usec = ntohl(start_usec); 173 EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile)); 174 source = ntohl(source); 175 EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile)); 176 port = ntohs(port); 177 EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile)); 178 padding = ntohs(padding); 179 } 180 181 void RTPFile::Write(const uint8_t payloadType, 182 const uint32_t timeStamp, 183 const int16_t seqNo, 184 const uint8_t* payloadData, 185 const size_t payloadSize, 186 uint32_t frequency) { 187 /* write RTP packet to file */ 188 uint8_t rtpHeader[12]; 189 MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0); 190 ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max()); 191 uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8)); 192 uint16_t plen = htons(static_cast<u_short>(12 + payloadSize)); 193 uint32_t offsetMs; 194 195 offsetMs = (timeStamp / (frequency / 1000)); 196 offsetMs = htonl(offsetMs); 197 EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile)); 198 EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile)); 199 EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile)); 200 EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile)); 201 EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile)); 202 } 203 204 size_t RTPFile::Read(RTPHeader* rtp_header, 205 uint8_t* payloadData, 206 size_t payloadSize, 207 uint32_t* offset) { 208 uint16_t lengthBytes; 209 uint16_t plen; 210 uint8_t rtpHeader[12]; 211 size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile); 212 /* Check if we have reached end of file. */ 213 if ((read_len == 0) && feof(_rtpFile)) { 214 _rtpEOF = true; 215 return 0; 216 } 217 EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile)); 218 EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile)); 219 lengthBytes = ntohs(lengthBytes); 220 plen = ntohs(plen); 221 *offset = ntohl(*offset); 222 EXPECT_GT(plen, 11); 223 224 EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile)); 225 ParseRTPHeader(rtp_header, rtpHeader); 226 EXPECT_EQ(lengthBytes, plen + 8); 227 228 if (plen == 0) { 229 return 0; 230 } 231 if (lengthBytes < 20) { 232 return 0; 233 } 234 if (payloadSize < static_cast<size_t>((lengthBytes - 20))) { 235 return 0; 236 } 237 lengthBytes -= 20; 238 EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile)); 239 return lengthBytes; 240 } 241 242 } // namespace webrtc