| 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 | 
|---|