1 /*
2  *  Copyright (c) 2015 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 <iostream>
12 #include <sstream>
13 #include <string>
14 
15 #include "gflags/gflags.h"
16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/scoped_ptr.h"
18 #include "webrtc/call/rtc_event_log.h"
19 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
20 #include "webrtc/test/rtp_file_writer.h"
21 
22 // Files generated at build-time by the protobuf compiler.
23 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD
24 #include "external/webrtc/webrtc/call/rtc_event_log.pb.h"
25 #else
26 #include "webrtc/call/rtc_event_log.pb.h"
27 #endif
28 
29 namespace {
30 
31 DEFINE_bool(noaudio,
32             false,
33             "Excludes audio packets from the converted RTPdump file.");
34 DEFINE_bool(novideo,
35             false,
36             "Excludes video packets from the converted RTPdump file.");
37 DEFINE_bool(nodata,
38             false,
39             "Excludes data packets from the converted RTPdump file.");
40 DEFINE_bool(nortp,
41             false,
42             "Excludes RTP packets from the converted RTPdump file.");
43 DEFINE_bool(nortcp,
44             false,
45             "Excludes RTCP packets from the converted RTPdump file.");
46 DEFINE_string(ssrc,
47               "",
48               "Store only packets with this SSRC (decimal or hex, the latter "
49               "starting with 0x).");
50 
51 // Parses the input string for a valid SSRC. If a valid SSRC is found, it is
52 // written to the output variable |ssrc|, and true is returned. Otherwise,
53 // false is returned.
54 // The empty string must be validated as true, because it is the default value
55 // of the command-line flag. In this case, no value is written to the output
56 // variable.
ParseSsrc(std::string str,uint32_t * ssrc)57 bool ParseSsrc(std::string str, uint32_t* ssrc) {
58   // If the input string starts with 0x or 0X it indicates a hexadecimal number.
59   auto read_mode = std::dec;
60   if (str.size() > 2 &&
61       (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) {
62     read_mode = std::hex;
63     str = str.substr(2);
64   }
65   std::stringstream ss(str);
66   ss >> read_mode >> *ssrc;
67   return str.empty() || (!ss.fail() && ss.eof());
68 }
69 
70 }  // namespace
71 
72 // This utility will convert a stored event log to the rtpdump format.
main(int argc,char * argv[])73 int main(int argc, char* argv[]) {
74   std::string program_name = argv[0];
75   std::string usage =
76       "Tool for converting an RtcEventLog file to an RTP dump file.\n"
77       "Run " +
78       program_name +
79       " --helpshort for usage.\n"
80       "Example usage:\n" +
81       program_name + " input.rel output.rtp\n";
82   google::SetUsageMessage(usage);
83   google::ParseCommandLineFlags(&argc, &argv, true);
84 
85   if (argc != 3) {
86     std::cout << google::ProgramUsage();
87     return 0;
88   }
89   std::string input_file = argv[1];
90   std::string output_file = argv[2];
91 
92   uint32_t ssrc_filter = 0;
93   if (!FLAGS_ssrc.empty())
94     RTC_CHECK(ParseSsrc(FLAGS_ssrc, &ssrc_filter))
95         << "Flag verification has failed.";
96 
97   webrtc::rtclog::EventStream event_stream;
98   if (!webrtc::RtcEventLog::ParseRtcEventLog(input_file, &event_stream)) {
99     std::cerr << "Error while parsing input file: " << input_file << std::endl;
100     return -1;
101   }
102 
103   rtc::scoped_ptr<webrtc::test::RtpFileWriter> rtp_writer(
104       webrtc::test::RtpFileWriter::Create(
105           webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file));
106 
107   if (!rtp_writer.get()) {
108     std::cerr << "Error while opening output file: " << output_file
109               << std::endl;
110     return -1;
111   }
112 
113   std::cout << "Found " << event_stream.stream_size()
114             << " events in the input file." << std::endl;
115   int rtp_counter = 0, rtcp_counter = 0;
116   bool header_only = false;
117   // TODO(ivoc): This can be refactored once the packet interpretation
118   //             functions are finished.
119   for (int i = 0; i < event_stream.stream_size(); i++) {
120     const webrtc::rtclog::Event& event = event_stream.stream(i);
121     if (!FLAGS_nortp && event.has_type() && event.type() == event.RTP_EVENT) {
122       if (event.has_timestamp_us() && event.has_rtp_packet() &&
123           event.rtp_packet().has_header() &&
124           event.rtp_packet().header().size() >= 12 &&
125           event.rtp_packet().has_packet_length() &&
126           event.rtp_packet().has_type()) {
127         const webrtc::rtclog::RtpPacket& rtp_packet = event.rtp_packet();
128         if (FLAGS_noaudio && rtp_packet.type() == webrtc::rtclog::AUDIO)
129           continue;
130         if (FLAGS_novideo && rtp_packet.type() == webrtc::rtclog::VIDEO)
131           continue;
132         if (FLAGS_nodata && rtp_packet.type() == webrtc::rtclog::DATA)
133           continue;
134         if (!FLAGS_ssrc.empty()) {
135           const uint32_t packet_ssrc =
136               webrtc::ByteReader<uint32_t>::ReadBigEndian(
137                   reinterpret_cast<const uint8_t*>(rtp_packet.header().data() +
138                                                    8));
139           if (packet_ssrc != ssrc_filter)
140             continue;
141         }
142 
143         webrtc::test::RtpPacket packet;
144         packet.length = rtp_packet.header().size();
145         if (packet.length > packet.kMaxPacketBufferSize) {
146           std::cout << "Skipping packet with size " << packet.length
147                     << ", the maximum supported size is "
148                     << packet.kMaxPacketBufferSize << std::endl;
149           continue;
150         }
151         packet.original_length = rtp_packet.packet_length();
152         if (packet.original_length > packet.length)
153           header_only = true;
154         packet.time_ms = event.timestamp_us() / 1000;
155         memcpy(packet.data, rtp_packet.header().data(), packet.length);
156         rtp_writer->WritePacket(&packet);
157         rtp_counter++;
158       } else {
159         std::cout << "Skipping malformed event." << std::endl;
160       }
161     }
162     if (!FLAGS_nortcp && event.has_type() && event.type() == event.RTCP_EVENT) {
163       if (event.has_timestamp_us() && event.has_rtcp_packet() &&
164           event.rtcp_packet().has_type() &&
165           event.rtcp_packet().has_packet_data() &&
166           event.rtcp_packet().packet_data().size() > 0) {
167         const webrtc::rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet();
168         if (FLAGS_noaudio && rtcp_packet.type() == webrtc::rtclog::AUDIO)
169           continue;
170         if (FLAGS_novideo && rtcp_packet.type() == webrtc::rtclog::VIDEO)
171           continue;
172         if (FLAGS_nodata && rtcp_packet.type() == webrtc::rtclog::DATA)
173           continue;
174         if (!FLAGS_ssrc.empty()) {
175           const uint32_t packet_ssrc =
176               webrtc::ByteReader<uint32_t>::ReadBigEndian(
177                   reinterpret_cast<const uint8_t*>(
178                       rtcp_packet.packet_data().data() + 4));
179           if (packet_ssrc != ssrc_filter)
180             continue;
181         }
182 
183         webrtc::test::RtpPacket packet;
184         packet.length = rtcp_packet.packet_data().size();
185         if (packet.length > packet.kMaxPacketBufferSize) {
186           std::cout << "Skipping packet with size " << packet.length
187                     << ", the maximum supported size is "
188                     << packet.kMaxPacketBufferSize << std::endl;
189           continue;
190         }
191         // For RTCP packets the original_length should be set to 0 in the
192         // RTPdump format.
193         packet.original_length = 0;
194         packet.time_ms = event.timestamp_us() / 1000;
195         memcpy(packet.data, rtcp_packet.packet_data().data(), packet.length);
196         rtp_writer->WritePacket(&packet);
197         rtcp_counter++;
198       } else {
199         std::cout << "Skipping malformed event." << std::endl;
200       }
201     }
202   }
203   std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "")
204             << " RTP packets and " << rtcp_counter << " RTCP packets to the "
205             << "output file." << std::endl;
206   return 0;
207 }
208