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