blob: 93cd4652cc7df1bf3fc4d42fa6c40b9f842c1c21 [file] [log] [blame]
Ivo Creusene1aa5b52015-09-18 13:41:071/*
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
Yves Gerey3e707812018-11-28 15:47:4911#include <stdint.h>
oprypin6e09d872017-08-31 10:21:3912#include <string.h>
Jonas Olssona4d87372019-07-05 17:08:3313
Ivo Creusene1aa5b52015-09-18 13:41:0714#include <iostream>
kwibergb25345e2016-03-12 14:10:4415#include <memory>
Ivo Creusene1aa5b52015-09-18 13:41:0716#include <string>
Yves Gerey3e707812018-11-28 15:47:4917#include <utility>
18#include <vector>
Ivo Creusene1aa5b52015-09-18 13:41:0719
Mirko Bonadeiab0b9d42019-07-08 10:31:5920#include "absl/flags/flag.h"
21#include "absl/flags/parse.h"
Mirko Bonadeif24729b2019-07-19 10:05:0922#include "absl/flags/usage.h"
Bjorn Terelius60d629f2018-09-24 15:10:2723#include "absl/memory/memory.h"
24#include "absl/types/optional.h"
Yves Gerey3e707812018-11-28 15:47:4925#include "api/array_view.h"
Danil Chapovalov83bbe912019-08-07 10:24:5326#include "api/rtc_event_log/rtc_event_log.h"
Yves Gerey3e707812018-11-28 15:47:4927#include "api/rtp_headers.h"
Sebastian Janssonb290a6d2019-01-03 13:46:2328#include "logging/rtc_event_log/rtc_event_log_parser.h"
Bjorn Terelius60d629f2018-09-24 15:10:2729#include "logging/rtc_event_log/rtc_event_processor.h"
Yves Gerey3e707812018-11-28 15:47:4930#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
Bjorn Terelius60d629f2018-09-24 15:10:2731#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
32#include "modules/rtp_rtcp/source/rtp_packet.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3133#include "rtc_base/checks.h"
Yves Gerey3e707812018-11-28 15:47:4934#include "test/rtp_file_reader.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3135#include "test/rtp_file_writer.h"
Ivo Creusene1aa5b52015-09-18 13:41:0736
Mirko Bonadeiab0b9d42019-07-08 10:31:5937ABSL_FLAG(
38 bool,
39 audio,
40 true,
41 "Use --noaudio to exclude audio packets from the converted RTPdump file.");
42ABSL_FLAG(
43 bool,
44 video,
45 true,
46 "Use --novideo to exclude video packets from the converted RTPdump file.");
47ABSL_FLAG(
48 bool,
49 data,
50 true,
51 "Use --nodata to exclude data packets from the converted RTPdump file.");
52ABSL_FLAG(
53 bool,
54 rtp,
55 true,
56 "Use --nortp to exclude RTP packets from the converted RTPdump file.");
57ABSL_FLAG(
58 bool,
59 rtcp,
60 true,
61 "Use --nortcp to exclude RTCP packets from the converted RTPdump file.");
62ABSL_FLAG(std::string,
63 ssrc,
64 "",
65 "Store only packets with this SSRC (decimal or hex, the latter "
66 "starting with 0x).");
67
Ivo Creusene1aa5b52015-09-18 13:41:0768namespace {
69
Sebastian Janssonb290a6d2019-01-03 13:46:2370using MediaType = webrtc::ParsedRtcEventLog::MediaType;
perkj77cd58e2017-05-30 10:52:1071
Ivo Creusene1aa5b52015-09-18 13:41:0772// Parses the input string for a valid SSRC. If a valid SSRC is found, it is
Artem Titovaf9a3c62021-07-30 12:22:5573// written to the output variable `ssrc`, and true is returned. Otherwise,
Ivo Creusene1aa5b52015-09-18 13:41:0774// false is returned.
75// The empty string must be validated as true, because it is the default value
76// of the command-line flag. In this case, no value is written to the output
77// variable.
Bjorn Terelius60d629f2018-09-24 15:10:2778absl::optional<uint32_t> ParseSsrc(std::string str) {
Ivo Creusene1aa5b52015-09-18 13:41:0779 // If the input string starts with 0x or 0X it indicates a hexadecimal number.
Bjorn Terelius60d629f2018-09-24 15:10:2780 uint32_t ssrc;
Ivo Creusene1aa5b52015-09-18 13:41:0781 auto read_mode = std::dec;
82 if (str.size() > 2 &&
83 (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) {
84 read_mode = std::hex;
85 str = str.substr(2);
86 }
87 std::stringstream ss(str);
Bjorn Terelius60d629f2018-09-24 15:10:2788 ss >> read_mode >> ssrc;
89 if (str.empty() || (!ss.fail() && ss.eof()))
90 return ssrc;
91 return absl::nullopt;
92}
93
94bool ShouldSkipStream(MediaType media_type,
95 uint32_t ssrc,
96 absl::optional<uint32_t> ssrc_filter) {
Mirko Bonadeiab0b9d42019-07-08 10:31:5997 if (!absl::GetFlag(FLAGS_audio) && media_type == MediaType::AUDIO)
Bjorn Terelius60d629f2018-09-24 15:10:2798 return true;
Mirko Bonadeiab0b9d42019-07-08 10:31:5999 if (!absl::GetFlag(FLAGS_video) && media_type == MediaType::VIDEO)
Bjorn Terelius60d629f2018-09-24 15:10:27100 return true;
Mirko Bonadeiab0b9d42019-07-08 10:31:59101 if (!absl::GetFlag(FLAGS_data) && media_type == MediaType::DATA)
Bjorn Terelius60d629f2018-09-24 15:10:27102 return true;
103 if (ssrc_filter.has_value() && ssrc != *ssrc_filter)
104 return true;
105 return false;
106}
107
108// Convert a LoggedRtpPacketIncoming to a test::RtpPacket. Header extension IDs
109// are allocated according to the provided extension map. This might not match
110// the extension map used in the actual call.
Bjorn Terelius788c51c2018-09-28 12:51:22111void ConvertRtpPacket(
112 const webrtc::LoggedRtpPacketIncoming& incoming,
113 const webrtc::RtpHeaderExtensionMap& default_extension_map,
114 webrtc::test::RtpPacket* packet) {
Bjorn Terelius60d629f2018-09-24 15:10:27115 webrtc::RtpPacket reconstructed_packet(&default_extension_map);
116
117 reconstructed_packet.SetMarker(incoming.rtp.header.markerBit);
118 reconstructed_packet.SetPayloadType(incoming.rtp.header.payloadType);
119 reconstructed_packet.SetSequenceNumber(incoming.rtp.header.sequenceNumber);
120 reconstructed_packet.SetTimestamp(incoming.rtp.header.timestamp);
121 reconstructed_packet.SetSsrc(incoming.rtp.header.ssrc);
122 if (incoming.rtp.header.numCSRCs > 0) {
123 reconstructed_packet.SetCsrcs(rtc::ArrayView<const uint32_t>(
124 incoming.rtp.header.arrOfCSRCs, incoming.rtp.header.numCSRCs));
125 }
126
127 // Set extensions.
128 if (incoming.rtp.header.extension.hasTransmissionTimeOffset)
129 reconstructed_packet.SetExtension<webrtc::TransmissionOffset>(
130 incoming.rtp.header.extension.transmissionTimeOffset);
131 if (incoming.rtp.header.extension.hasAbsoluteSendTime)
132 reconstructed_packet.SetExtension<webrtc::AbsoluteSendTime>(
133 incoming.rtp.header.extension.absoluteSendTime);
134 if (incoming.rtp.header.extension.hasTransportSequenceNumber)
135 reconstructed_packet.SetExtension<webrtc::TransportSequenceNumber>(
136 incoming.rtp.header.extension.transportSequenceNumber);
137 if (incoming.rtp.header.extension.hasAudioLevel)
138 reconstructed_packet.SetExtension<webrtc::AudioLevel>(
139 incoming.rtp.header.extension.voiceActivity,
140 incoming.rtp.header.extension.audioLevel);
141 if (incoming.rtp.header.extension.hasVideoRotation)
142 reconstructed_packet.SetExtension<webrtc::VideoOrientation>(
143 incoming.rtp.header.extension.videoRotation);
144 if (incoming.rtp.header.extension.hasVideoContentType)
145 reconstructed_packet.SetExtension<webrtc::VideoContentTypeExtension>(
146 incoming.rtp.header.extension.videoContentType);
147 if (incoming.rtp.header.extension.has_video_timing)
148 reconstructed_packet.SetExtension<webrtc::VideoTimingExtension>(
149 incoming.rtp.header.extension.video_timing);
150
151 RTC_DCHECK_EQ(reconstructed_packet.size(), incoming.rtp.header_length);
152 RTC_DCHECK_EQ(reconstructed_packet.headers_size(),
153 incoming.rtp.header_length);
154 memcpy(packet->data, reconstructed_packet.data(),
155 reconstructed_packet.headers_size());
156 packet->length = reconstructed_packet.headers_size();
157 packet->original_length = incoming.rtp.total_length;
158 packet->time_ms = incoming.log_time_ms();
159 // Set padding bit.
160 if (incoming.rtp.header.paddingLength > 0)
161 packet->data[0] = packet->data[0] | 0x20;
Ivo Creusene1aa5b52015-09-18 13:41:07162}
163
164} // namespace
165
166// This utility will convert a stored event log to the rtpdump format.
167int main(int argc, char* argv[]) {
Mirko Bonadeif24729b2019-07-19 10:05:09168 absl::SetProgramUsageMessage(
169 "Tool for converting an RtcEventLog file to an "
170 "RTP dump file.\n"
171 "Example usage:\n"
172 "./rtc_event_log2rtp_dump input.rel output.rtp\n");
Mirko Bonadeiab0b9d42019-07-08 10:31:59173 std::vector<char*> args = absl::ParseCommandLine(argc, argv);
Mirko Bonadeiab0b9d42019-07-08 10:31:59174 if (args.size() != 3) {
Mirko Bonadeif24729b2019-07-19 10:05:09175 std::cout << absl::ProgramUsageMessage();
oprypin6e09d872017-08-31 10:21:39176 return 1;
Ivo Creusene1aa5b52015-09-18 13:41:07177 }
oprypin6e09d872017-08-31 10:21:39178
Mirko Bonadeiab0b9d42019-07-08 10:31:59179 std::string input_file = args[1];
180 std::string output_file = args[2];
Ivo Creusene1aa5b52015-09-18 13:41:07181
Bjorn Terelius60d629f2018-09-24 15:10:27182 absl::optional<uint32_t> ssrc_filter;
Mirko Bonadeiab0b9d42019-07-08 10:31:59183 if (!absl::GetFlag(FLAGS_ssrc).empty()) {
184 ssrc_filter = ParseSsrc(absl::GetFlag(FLAGS_ssrc));
Bjorn Terelius60d629f2018-09-24 15:10:27185 RTC_CHECK(ssrc_filter.has_value()) << "Failed to read SSRC filter flag.";
186 }
Ivo Creusene1aa5b52015-09-18 13:41:07187
Sebastian Janssonb290a6d2019-01-03 13:46:23188 webrtc::ParsedRtcEventLog parsed_stream;
Björn Tereliusa06048a2019-11-01 13:31:46189 auto status = parsed_stream.ParseFile(input_file);
190 if (!status.ok()) {
191 std::cerr << "Failed to parse event log " << input_file << ": "
192 << status.message() << std::endl;
Ivo Creusene1aa5b52015-09-18 13:41:07193 return -1;
194 }
195
kwibergb25345e2016-03-12 14:10:44196 std::unique_ptr<webrtc::test::RtpFileWriter> rtp_writer(
Ivo Creusene1aa5b52015-09-18 13:41:07197 webrtc::test::RtpFileWriter::Create(
198 webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file));
199
Benjamin Wrightf1c9e212019-03-14 00:51:59200 if (!rtp_writer) {
Ivo Creusene1aa5b52015-09-18 13:41:07201 std::cerr << "Error while opening output file: " << output_file
202 << std::endl;
203 return -1;
204 }
205
Ivo Creusene1aa5b52015-09-18 13:41:07206 int rtp_counter = 0, rtcp_counter = 0;
207 bool header_only = false;
Ivo Creusene1aa5b52015-09-18 13:41:07208
Bjorn Terelius60d629f2018-09-24 15:10:27209 webrtc::RtpHeaderExtensionMap default_extension_map =
Sebastian Janssonb290a6d2019-01-03 13:46:23210 webrtc::ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
Bjorn Terelius60d629f2018-09-24 15:10:27211 auto handle_rtp = [&default_extension_map, &rtp_writer, &rtp_counter](
212 const webrtc::LoggedRtpPacketIncoming& incoming) {
213 webrtc::test::RtpPacket packet;
214 ConvertRtpPacket(incoming, default_extension_map, &packet);
perkj77cd58e2017-05-30 10:52:10215
Bjorn Terelius60d629f2018-09-24 15:10:27216 rtp_writer->WritePacket(&packet);
217 rtp_counter++;
218 };
perkj77cd58e2017-05-30 10:52:10219
Bjorn Terelius60d629f2018-09-24 15:10:27220 auto handle_rtcp = [&rtp_writer, &rtcp_counter](
221 const webrtc::LoggedRtcpPacketIncoming& incoming) {
222 webrtc::test::RtpPacket packet;
223 memcpy(packet.data, incoming.rtcp.raw_data.data(),
224 incoming.rtcp.raw_data.size());
225 packet.length = incoming.rtcp.raw_data.size();
226 // For RTCP packets the original_length should be set to 0 in the
227 // RTPdump format.
228 packet.original_length = 0;
229 packet.time_ms = incoming.log_time_ms();
tereliusd5c1a0b2016-05-13 07:42:59230
Bjorn Terelius60d629f2018-09-24 15:10:27231 rtp_writer->WritePacket(&packet);
232 rtcp_counter++;
233 };
Ivo Creusene1aa5b52015-09-18 13:41:07234
Bjorn Terelius60d629f2018-09-24 15:10:27235 webrtc::RtcEventProcessor event_processor;
236 for (const auto& stream : parsed_stream.incoming_rtp_packets_by_ssrc()) {
237 MediaType media_type =
238 parsed_stream.GetMediaType(stream.ssrc, webrtc::kIncomingPacket);
239 if (ShouldSkipStream(media_type, stream.ssrc, ssrc_filter))
240 continue;
Sebastian Jansson03fbf1e2019-01-08 14:31:06241 event_processor.AddEvents(stream.incoming_packets, handle_rtp);
Ivo Creusene1aa5b52015-09-18 13:41:07242 }
Artem Titovaf9a3c62021-07-30 12:22:55243 // Note that `packet_ssrc` is the sender SSRC. An RTCP message may contain
Bjorn Terelius60d629f2018-09-24 15:10:27244 // report blocks for many streams, thus several SSRCs and they don't
245 // necessarily have to be of the same media type. We therefore don't
246 // support filtering of RTCP based on SSRC and media type.
Sebastian Jansson03fbf1e2019-01-08 14:31:06247 event_processor.AddEvents(parsed_stream.incoming_rtcp_packets(), handle_rtcp);
Bjorn Terelius60d629f2018-09-24 15:10:27248
249 event_processor.ProcessEventsInOrder();
250
Ivo Creusene1aa5b52015-09-18 13:41:07251 std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "")
Jonas Olssonb2b20312020-01-14 11:11:31252 << " RTP packets and " << rtcp_counter
253 << " RTCP packets to the "
254 "output file."
255 << std::endl;
Ivo Creusene1aa5b52015-09-18 13:41:07256 return 0;
257}