OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 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 <string.h> |
| 12 |
11 #include <iostream> | 13 #include <iostream> |
12 #include <memory> | 14 #include <memory> |
13 #include <sstream> | 15 #include <sstream> |
14 #include <string> | 16 #include <string> |
15 | 17 |
16 #include "gflags/gflags.h" | |
17 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" | 18 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" |
18 #include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h" | 19 #include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h" |
19 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 20 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
20 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | 21 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" |
21 #include "webrtc/rtc_base/checks.h" | 22 #include "webrtc/rtc_base/checks.h" |
| 23 #include "webrtc/rtc_base/flags.h" |
22 #include "webrtc/test/rtp_file_writer.h" | 24 #include "webrtc/test/rtp_file_writer.h" |
23 | 25 |
24 namespace { | 26 namespace { |
25 | 27 |
26 using MediaType = webrtc::ParsedRtcEventLog::MediaType; | 28 using MediaType = webrtc::ParsedRtcEventLog::MediaType; |
27 | 29 |
28 DEFINE_bool(noaudio, | 30 DEFINE_bool(noaudio, |
29 false, | 31 false, |
30 "Excludes audio packets from the converted RTPdump file."); | 32 "Excludes audio packets from the converted RTPdump file."); |
31 DEFINE_bool(novideo, | 33 DEFINE_bool(novideo, |
32 false, | 34 false, |
33 "Excludes video packets from the converted RTPdump file."); | 35 "Excludes video packets from the converted RTPdump file."); |
34 DEFINE_bool(nodata, | 36 DEFINE_bool(nodata, |
35 false, | 37 false, |
36 "Excludes data packets from the converted RTPdump file."); | 38 "Excludes data packets from the converted RTPdump file."); |
37 DEFINE_bool(nortp, | 39 DEFINE_bool(nortp, |
38 false, | 40 false, |
39 "Excludes RTP packets from the converted RTPdump file."); | 41 "Excludes RTP packets from the converted RTPdump file."); |
40 DEFINE_bool(nortcp, | 42 DEFINE_bool(nortcp, |
41 false, | 43 false, |
42 "Excludes RTCP packets from the converted RTPdump file."); | 44 "Excludes RTCP packets from the converted RTPdump file."); |
43 DEFINE_string(ssrc, | 45 DEFINE_string(ssrc, |
44 "", | 46 "", |
45 "Store only packets with this SSRC (decimal or hex, the latter " | 47 "Store only packets with this SSRC (decimal or hex, the latter " |
46 "starting with 0x)."); | 48 "starting with 0x)."); |
| 49 DEFINE_bool(help, false, "Prints this message."); |
47 | 50 |
48 // Parses the input string for a valid SSRC. If a valid SSRC is found, it is | 51 // Parses the input string for a valid SSRC. If a valid SSRC is found, it is |
49 // written to the output variable |ssrc|, and true is returned. Otherwise, | 52 // written to the output variable |ssrc|, and true is returned. Otherwise, |
50 // false is returned. | 53 // false is returned. |
51 // The empty string must be validated as true, because it is the default value | 54 // The empty string must be validated as true, because it is the default value |
52 // of the command-line flag. In this case, no value is written to the output | 55 // of the command-line flag. In this case, no value is written to the output |
53 // variable. | 56 // variable. |
54 bool ParseSsrc(std::string str, uint32_t* ssrc) { | 57 bool ParseSsrc(std::string str, uint32_t* ssrc) { |
55 // If the input string starts with 0x or 0X it indicates a hexadecimal number. | 58 // If the input string starts with 0x or 0X it indicates a hexadecimal number. |
56 auto read_mode = std::dec; | 59 auto read_mode = std::dec; |
57 if (str.size() > 2 && | 60 if (str.size() > 2 && |
58 (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) { | 61 (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) { |
59 read_mode = std::hex; | 62 read_mode = std::hex; |
60 str = str.substr(2); | 63 str = str.substr(2); |
61 } | 64 } |
62 std::stringstream ss(str); | 65 std::stringstream ss(str); |
63 ss >> read_mode >> *ssrc; | 66 ss >> read_mode >> *ssrc; |
64 return str.empty() || (!ss.fail() && ss.eof()); | 67 return str.empty() || (!ss.fail() && ss.eof()); |
65 } | 68 } |
66 | 69 |
67 } // namespace | 70 } // namespace |
68 | 71 |
69 // This utility will convert a stored event log to the rtpdump format. | 72 // This utility will convert a stored event log to the rtpdump format. |
70 int main(int argc, char* argv[]) { | 73 int main(int argc, char* argv[]) { |
71 std::string program_name = argv[0]; | 74 std::string program_name = argv[0]; |
72 std::string usage = | 75 std::string usage = |
73 "Tool for converting an RtcEventLog file to an RTP dump file.\n" | 76 "Tool for converting an RtcEventLog file to an RTP dump file.\n" |
74 "Run " + | 77 "Run " + |
75 program_name + | 78 program_name + |
76 " --helpshort for usage.\n" | 79 " --help for usage.\n" |
77 "Example usage:\n" + | 80 "Example usage:\n" + |
78 program_name + " input.rel output.rtp\n"; | 81 program_name + " input.rel output.rtp\n"; |
79 google::SetUsageMessage(usage); | 82 if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || |
80 google::ParseCommandLineFlags(&argc, &argv, true); | 83 FLAG_help || argc != 3) { |
| 84 std::cout << usage; |
| 85 if (FLAG_help) { |
| 86 rtc::FlagList::Print(nullptr, false); |
| 87 return 0; |
| 88 } |
| 89 return 1; |
| 90 } |
81 | 91 |
82 if (argc != 3) { | |
83 std::cout << google::ProgramUsage(); | |
84 return 0; | |
85 } | |
86 std::string input_file = argv[1]; | 92 std::string input_file = argv[1]; |
87 std::string output_file = argv[2]; | 93 std::string output_file = argv[2]; |
88 | 94 |
89 uint32_t ssrc_filter = 0; | 95 uint32_t ssrc_filter = 0; |
90 if (!FLAGS_ssrc.empty()) | 96 if (strlen(FLAG_ssrc) > 0) |
91 RTC_CHECK(ParseSsrc(FLAGS_ssrc, &ssrc_filter)) | 97 RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc_filter)) |
92 << "Flag verification has failed."; | 98 << "Flag verification has failed."; |
93 | 99 |
94 webrtc::ParsedRtcEventLog parsed_stream; | 100 webrtc::ParsedRtcEventLog parsed_stream; |
95 if (!parsed_stream.ParseFile(input_file)) { | 101 if (!parsed_stream.ParseFile(input_file)) { |
96 std::cerr << "Error while parsing input file: " << input_file << std::endl; | 102 std::cerr << "Error while parsing input file: " << input_file << std::endl; |
97 return -1; | 103 return -1; |
98 } | 104 } |
99 | 105 |
100 std::unique_ptr<webrtc::test::RtpFileWriter> rtp_writer( | 106 std::unique_ptr<webrtc::test::RtpFileWriter> rtp_writer( |
101 webrtc::test::RtpFileWriter::Create( | 107 webrtc::test::RtpFileWriter::Create( |
102 webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file)); | 108 webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file)); |
103 | 109 |
104 if (!rtp_writer.get()) { | 110 if (!rtp_writer.get()) { |
105 std::cerr << "Error while opening output file: " << output_file | 111 std::cerr << "Error while opening output file: " << output_file |
106 << std::endl; | 112 << std::endl; |
107 return -1; | 113 return -1; |
108 } | 114 } |
109 | 115 |
110 std::cout << "Found " << parsed_stream.GetNumberOfEvents() | 116 std::cout << "Found " << parsed_stream.GetNumberOfEvents() |
111 << " events in the input file." << std::endl; | 117 << " events in the input file." << std::endl; |
112 int rtp_counter = 0, rtcp_counter = 0; | 118 int rtp_counter = 0, rtcp_counter = 0; |
113 bool header_only = false; | 119 bool header_only = false; |
114 for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) { | 120 for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) { |
115 // The parsed_stream will assert if the protobuf event is missing | 121 // The parsed_stream will assert if the protobuf event is missing |
116 // some required fields and we attempt to access them. We could consider | 122 // some required fields and we attempt to access them. We could consider |
117 // a softer failure option, but it does not seem useful to generate | 123 // a softer failure option, but it does not seem useful to generate |
118 // RTP dumps based on broken event logs. | 124 // RTP dumps based on broken event logs. |
119 if (!FLAGS_nortp && | 125 if (!FLAG_nortp && |
120 parsed_stream.GetEventType(i) == webrtc::ParsedRtcEventLog::RTP_EVENT) { | 126 parsed_stream.GetEventType(i) == webrtc::ParsedRtcEventLog::RTP_EVENT) { |
121 webrtc::test::RtpPacket packet; | 127 webrtc::test::RtpPacket packet; |
122 webrtc::PacketDirection direction; | 128 webrtc::PacketDirection direction; |
123 parsed_stream.GetRtpHeader(i, &direction, packet.data, &packet.length, | 129 parsed_stream.GetRtpHeader(i, &direction, packet.data, &packet.length, |
124 &packet.original_length); | 130 &packet.original_length); |
125 if (packet.original_length > packet.length) | 131 if (packet.original_length > packet.length) |
126 header_only = true; | 132 header_only = true; |
127 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; | 133 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; |
128 | 134 |
129 webrtc::RtpUtility::RtpHeaderParser rtp_parser(packet.data, | 135 webrtc::RtpUtility::RtpHeaderParser rtp_parser(packet.data, |
130 packet.length); | 136 packet.length); |
131 | 137 |
132 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? | 138 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? |
133 if (direction == webrtc::kOutgoingPacket) | 139 if (direction == webrtc::kOutgoingPacket) |
134 continue; | 140 continue; |
135 | 141 |
136 webrtc::RTPHeader parsed_header; | 142 webrtc::RTPHeader parsed_header; |
137 rtp_parser.Parse(&parsed_header); | 143 rtp_parser.Parse(&parsed_header); |
138 MediaType media_type = | 144 MediaType media_type = |
139 parsed_stream.GetMediaType(parsed_header.ssrc, direction); | 145 parsed_stream.GetMediaType(parsed_header.ssrc, direction); |
140 if (FLAGS_noaudio && media_type == MediaType::AUDIO) | 146 if (FLAG_noaudio && media_type == MediaType::AUDIO) |
141 continue; | 147 continue; |
142 if (FLAGS_novideo && media_type == MediaType::VIDEO) | 148 if (FLAG_novideo && media_type == MediaType::VIDEO) |
143 continue; | 149 continue; |
144 if (FLAGS_nodata && media_type == MediaType::DATA) | 150 if (FLAG_nodata && media_type == MediaType::DATA) |
145 continue; | 151 continue; |
146 if (!FLAGS_ssrc.empty()) { | 152 if (strlen(FLAG_ssrc) > 0) { |
147 const uint32_t packet_ssrc = | 153 const uint32_t packet_ssrc = |
148 webrtc::ByteReader<uint32_t>::ReadBigEndian( | 154 webrtc::ByteReader<uint32_t>::ReadBigEndian( |
149 reinterpret_cast<const uint8_t*>(packet.data + 8)); | 155 reinterpret_cast<const uint8_t*>(packet.data + 8)); |
150 if (packet_ssrc != ssrc_filter) | 156 if (packet_ssrc != ssrc_filter) |
151 continue; | 157 continue; |
152 } | 158 } |
153 | 159 |
154 rtp_writer->WritePacket(&packet); | 160 rtp_writer->WritePacket(&packet); |
155 rtp_counter++; | 161 rtp_counter++; |
156 } | 162 } |
157 if (!FLAGS_nortcp && | 163 if (!FLAG_nortcp && |
158 parsed_stream.GetEventType(i) == | 164 parsed_stream.GetEventType(i) == |
159 webrtc::ParsedRtcEventLog::RTCP_EVENT) { | 165 webrtc::ParsedRtcEventLog::RTCP_EVENT) { |
160 webrtc::test::RtpPacket packet; | 166 webrtc::test::RtpPacket packet; |
161 webrtc::PacketDirection direction; | 167 webrtc::PacketDirection direction; |
162 parsed_stream.GetRtcpPacket(i, &direction, packet.data, &packet.length); | 168 parsed_stream.GetRtcpPacket(i, &direction, packet.data, &packet.length); |
163 // For RTCP packets the original_length should be set to 0 in the | 169 // For RTCP packets the original_length should be set to 0 in the |
164 // RTPdump format. | 170 // RTPdump format. |
165 packet.original_length = 0; | 171 packet.original_length = 0; |
166 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; | 172 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; |
167 | 173 |
168 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? | 174 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? |
169 if (direction == webrtc::kOutgoingPacket) | 175 if (direction == webrtc::kOutgoingPacket) |
170 continue; | 176 continue; |
171 | 177 |
172 // Note that |packet_ssrc| is the sender SSRC. An RTCP message may contain | 178 // Note that |packet_ssrc| is the sender SSRC. An RTCP message may contain |
173 // report blocks for many streams, thus several SSRCs and they doen't | 179 // report blocks for many streams, thus several SSRCs and they doen't |
174 // necessarily have to be of the same media type. | 180 // necessarily have to be of the same media type. |
175 const uint32_t packet_ssrc = webrtc::ByteReader<uint32_t>::ReadBigEndian( | 181 const uint32_t packet_ssrc = webrtc::ByteReader<uint32_t>::ReadBigEndian( |
176 reinterpret_cast<const uint8_t*>(packet.data + 4)); | 182 reinterpret_cast<const uint8_t*>(packet.data + 4)); |
177 MediaType media_type = parsed_stream.GetMediaType(packet_ssrc, direction); | 183 MediaType media_type = parsed_stream.GetMediaType(packet_ssrc, direction); |
178 if (FLAGS_noaudio && media_type == MediaType::AUDIO) | 184 if (FLAG_noaudio && media_type == MediaType::AUDIO) |
179 continue; | 185 continue; |
180 if (FLAGS_novideo && media_type == MediaType::VIDEO) | 186 if (FLAG_novideo && media_type == MediaType::VIDEO) |
181 continue; | 187 continue; |
182 if (FLAGS_nodata && media_type == MediaType::DATA) | 188 if (FLAG_nodata && media_type == MediaType::DATA) |
183 continue; | 189 continue; |
184 if (!FLAGS_ssrc.empty()) { | 190 if (strlen(FLAG_ssrc) > 0) { |
185 if (packet_ssrc != ssrc_filter) | 191 if (packet_ssrc != ssrc_filter) |
186 continue; | 192 continue; |
187 } | 193 } |
188 | 194 |
189 rtp_writer->WritePacket(&packet); | 195 rtp_writer->WritePacket(&packet); |
190 rtcp_counter++; | 196 rtcp_counter++; |
191 } | 197 } |
192 } | 198 } |
193 std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "") | 199 std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "") |
194 << " RTP packets and " << rtcp_counter << " RTCP packets to the " | 200 << " RTP packets and " << rtcp_counter << " RTCP packets to the " |
195 << "output file." << std::endl; | 201 << "output file." << std::endl; |
196 return 0; | 202 return 0; |
197 } | 203 } |
OLD | NEW |