rtp_jitter.cc (4762B)
1 /* 2 * Copyright (c) 2017 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 <algorithm> 12 #include <cstdint> 13 #include <cstdio> 14 #include <fstream> 15 #include <iostream> 16 #include <string> 17 #include <utility> 18 #include <vector> 19 20 #include "api/array_view.h" 21 #include "modules/rtp_rtcp/source/byte_io.h" 22 #include "rtc_base/buffer.h" 23 #include "rtc_base/checks.h" 24 25 namespace webrtc { 26 namespace test { 27 namespace { 28 29 constexpr size_t kRtpDumpHeaderLength = 8; 30 31 // Returns the next packet or an empty buffer if end of file was encountered. 32 Buffer ReadNextPacket(FILE* file) { 33 // Read the rtpdump header for the next packet. 34 Buffer buffer; 35 buffer.SetData(kRtpDumpHeaderLength, [&](ArrayView<uint8_t> x) { 36 return fread(x.data(), 1, x.size(), file); 37 }); 38 if (buffer.size() != kRtpDumpHeaderLength) { 39 return Buffer(); 40 } 41 42 // Get length field. This is the total length for this packet written to file, 43 // including the kRtpDumpHeaderLength bytes already read. 44 const uint16_t len = ByteReader<uint16_t>::ReadBigEndian(buffer.data()); 45 RTC_CHECK_GE(len, kRtpDumpHeaderLength); 46 47 // Read remaining data from file directly into buffer. 48 buffer.AppendData(len - kRtpDumpHeaderLength, [&](ArrayView<uint8_t> x) { 49 return fread(x.data(), 1, x.size(), file); 50 }); 51 if (buffer.size() != len) { 52 buffer.Clear(); 53 } 54 return buffer; 55 } 56 57 struct PacketAndTime { 58 Buffer packet; 59 int time; 60 }; 61 62 void WritePacket(const PacketAndTime& packet, FILE* file) { 63 // Write the first 4 bytes from the original packet. 64 const auto* payload_ptr = packet.packet.data(); 65 RTC_CHECK_EQ(fwrite(payload_ptr, 4, 1, file), 1); 66 payload_ptr += 4; 67 68 // Convert the new time offset to network endian, and write to file. 69 uint8_t time[sizeof(uint32_t)]; 70 ByteWriter<uint32_t, sizeof(uint32_t)>::WriteBigEndian(time, packet.time); 71 RTC_CHECK_EQ(fwrite(time, sizeof(uint32_t), 1, file), 1); 72 payload_ptr += 4; // Skip the old time in the original payload. 73 74 // Write the remaining part of the payload. 75 RTC_DCHECK_EQ(payload_ptr - packet.packet.data(), kRtpDumpHeaderLength); 76 RTC_CHECK_EQ( 77 fwrite(payload_ptr, packet.packet.size() - kRtpDumpHeaderLength, 1, file), 78 1); 79 } 80 81 int RunRtpJitter(int argc, char* argv[]) { 82 const std::string program_name = argv[0]; 83 const std::string usage = 84 "Tool for alternating the arrival times in an RTP dump file.\n" 85 "Example usage:\n" + 86 program_name + " input.rtp arrival_times_ms.txt output.rtp\n\n"; 87 if (argc != 4) { 88 printf("%s", usage.c_str()); 89 return 1; 90 } 91 92 printf("Input RTP file: %s\n", argv[1]); 93 FILE* in_file = fopen(argv[1], "rb"); 94 RTC_CHECK(in_file) << "Could not open file " << argv[1] << " for reading"; 95 printf("Timing file: %s\n", argv[2]); 96 std::ifstream timing_file(argv[2]); 97 printf("Output file: %s\n", argv[3]); 98 FILE* out_file = fopen(argv[3], "wb"); 99 RTC_CHECK(out_file) << "Could not open file " << argv[2] << " for writing"; 100 101 // Copy the RTP file header to the output file. 102 char header_string[30]; 103 RTC_CHECK(fgets(header_string, 30, in_file)); 104 fprintf(out_file, "%s", header_string); 105 uint8_t file_header[16]; 106 RTC_CHECK_EQ(fread(file_header, sizeof(file_header), 1, in_file), 1); 107 RTC_CHECK_EQ(fwrite(file_header, sizeof(file_header), 1, out_file), 1); 108 109 // Read all time values from the timing file. Store in a vector. 110 std::vector<int> new_arrival_times; 111 int new_time; 112 while (timing_file >> new_time) { 113 new_arrival_times.push_back(new_time); 114 } 115 116 // Read all packets from the input RTP file, but no more than the number of 117 // new time values. Store RTP packets together with new time values. 118 auto time_it = new_arrival_times.begin(); 119 std::vector<PacketAndTime> packets; 120 while (1) { 121 auto packet = ReadNextPacket(in_file); 122 if (packet.empty() || time_it == new_arrival_times.end()) { 123 break; 124 } 125 packets.push_back({std::move(packet), *time_it}); 126 ++time_it; 127 } 128 129 // Sort on new time values. 130 std::sort(packets.begin(), packets.end(), 131 [](const PacketAndTime& a, const PacketAndTime& b) { 132 return a.time < b.time; 133 }); 134 135 // Write packets to output file. 136 for (const auto& p : packets) { 137 WritePacket(p, out_file); 138 } 139 140 fclose(in_file); 141 fclose(out_file); 142 return 0; 143 } 144 145 } // namespace 146 } // namespace test 147 } // namespace webrtc 148 149 int main(int argc, char* argv[]) { 150 return webrtc::test::RunRtpJitter(argc, argv); 151 }