blob: 250aaf59d7f9c869ff2598f9982c8c8e36a08188 [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"
Ali Tofigh277766f2022-07-14 22:44:0224#include "absl/strings/string_view.h"
Bjorn Terelius60d629f2018-09-24 15:10:2725#include "absl/types/optional.h"
Yves Gerey3e707812018-11-28 15:47:4926#include "api/array_view.h"
Danil Chapovalov83bbe912019-08-07 10:24:5327#include "api/rtc_event_log/rtc_event_log.h"
Yves Gerey3e707812018-11-28 15:47:4928#include "api/rtp_headers.h"
Sebastian Janssonb290a6d2019-01-03 13:46:2329#include "logging/rtc_event_log/rtc_event_log_parser.h"
Bjorn Terelius60d629f2018-09-24 15:10:2730#include "logging/rtc_event_log/rtc_event_processor.h"
Yves Gerey3e707812018-11-28 15:47:4931#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
Bjorn Terelius60d629f2018-09-24 15:10:2732#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
33#include "modules/rtp_rtcp/source/rtp_packet.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3134#include "rtc_base/checks.h"
Yves Gerey3e707812018-11-28 15:47:4935#include "test/rtp_file_reader.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3136#include "test/rtp_file_writer.h"
Ivo Creusene1aa5b52015-09-18 13:41:0737
Mirko Bonadeiab0b9d42019-07-08 10:31:5938ABSL_FLAG(
39 bool,
40 audio,
41 true,
42 "Use --noaudio to exclude audio packets from the converted RTPdump file.");
43ABSL_FLAG(
44 bool,
45 video,
46 true,
47 "Use --novideo to exclude video packets from the converted RTPdump file.");
48ABSL_FLAG(
49 bool,
50 data,
51 true,
52 "Use --nodata to exclude data packets from the converted RTPdump file.");
53ABSL_FLAG(
54 bool,
55 rtp,
56 true,
57 "Use --nortp to exclude RTP packets from the converted RTPdump file.");
58ABSL_FLAG(
59 bool,
60 rtcp,
61 true,
62 "Use --nortcp to exclude RTCP packets from the converted RTPdump file.");
63ABSL_FLAG(std::string,
64 ssrc,
65 "",
66 "Store only packets with this SSRC (decimal or hex, the latter "
67 "starting with 0x).");
68
Ivo Creusene1aa5b52015-09-18 13:41:0769namespace {
70
Sebastian Janssonb290a6d2019-01-03 13:46:2371using MediaType = webrtc::ParsedRtcEventLog::MediaType;
perkj77cd58e2017-05-30 10:52:1072
Ivo Creusene1aa5b52015-09-18 13:41:0773// Parses the input string for a valid SSRC. If a valid SSRC is found, it is
Artem Titovaf9a3c62021-07-30 12:22:5574// written to the output variable `ssrc`, and true is returned. Otherwise,
Ivo Creusene1aa5b52015-09-18 13:41:0775// false is returned.
76// The empty string must be validated as true, because it is the default value
77// of the command-line flag. In this case, no value is written to the output
78// variable.
Ali Tofigh277766f2022-07-14 22:44:0279absl::optional<uint32_t> ParseSsrc(absl::string_view str) {
Ivo Creusene1aa5b52015-09-18 13:41:0780 // If the input string starts with 0x or 0X it indicates a hexadecimal number.
Bjorn Terelius60d629f2018-09-24 15:10:2781 uint32_t ssrc;
Ivo Creusene1aa5b52015-09-18 13:41:0782 auto read_mode = std::dec;
83 if (str.size() > 2 &&
84 (str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) {
85 read_mode = std::hex;
86 str = str.substr(2);
87 }
Ali Tofigh277766f2022-07-14 22:44:0288 std::stringstream ss(std::string{str});
Bjorn Terelius60d629f2018-09-24 15:10:2789 ss >> read_mode >> ssrc;
90 if (str.empty() || (!ss.fail() && ss.eof()))
91 return ssrc;
92 return absl::nullopt;
93}
94
95bool ShouldSkipStream(MediaType media_type,
96 uint32_t ssrc,
97 absl::optional<uint32_t> ssrc_filter) {
Mirko Bonadeiab0b9d42019-07-08 10:31:5998 if (!absl::GetFlag(FLAGS_audio) && media_type == MediaType::AUDIO)
Bjorn Terelius60d629f2018-09-24 15:10:2799 return true;
Mirko Bonadeiab0b9d42019-07-08 10:31:59100 if (!absl::GetFlag(FLAGS_video) && media_type == MediaType::VIDEO)
Bjorn Terelius60d629f2018-09-24 15:10:27101 return true;
Mirko Bonadeiab0b9d42019-07-08 10:31:59102 if (!absl::GetFlag(FLAGS_data) && media_type == MediaType::DATA)
Bjorn Terelius60d629f2018-09-24 15:10:27103 return true;
104 if (ssrc_filter.has_value() && ssrc != *ssrc_filter)
105 return true;
106 return false;
107}
108
109// Convert a LoggedRtpPacketIncoming to a test::RtpPacket. Header extension IDs
110// are allocated according to the provided extension map. This might not match
111// the extension map used in the actual call.
Bjorn Terelius788c51c2018-09-28 12:51:22112void ConvertRtpPacket(
113 const webrtc::LoggedRtpPacketIncoming& incoming,
114 const webrtc::RtpHeaderExtensionMap& default_extension_map,
115 webrtc::test::RtpPacket* packet) {
Bjorn Terelius60d629f2018-09-24 15:10:27116 webrtc::RtpPacket reconstructed_packet(&default_extension_map);
117
118 reconstructed_packet.SetMarker(incoming.rtp.header.markerBit);
119 reconstructed_packet.SetPayloadType(incoming.rtp.header.payloadType);
120 reconstructed_packet.SetSequenceNumber(incoming.rtp.header.sequenceNumber);
121 reconstructed_packet.SetTimestamp(incoming.rtp.header.timestamp);
122 reconstructed_packet.SetSsrc(incoming.rtp.header.ssrc);
123 if (incoming.rtp.header.numCSRCs > 0) {
124 reconstructed_packet.SetCsrcs(rtc::ArrayView<const uint32_t>(
125 incoming.rtp.header.arrOfCSRCs, incoming.rtp.header.numCSRCs));
126 }
127
128 // Set extensions.
129 if (incoming.rtp.header.extension.hasTransmissionTimeOffset)
130 reconstructed_packet.SetExtension<webrtc::TransmissionOffset>(
131 incoming.rtp.header.extension.transmissionTimeOffset);
132 if (incoming.rtp.header.extension.hasAbsoluteSendTime)
133 reconstructed_packet.SetExtension<webrtc::AbsoluteSendTime>(
134 incoming.rtp.header.extension.absoluteSendTime);
135 if (incoming.rtp.header.extension.hasTransportSequenceNumber)
136 reconstructed_packet.SetExtension<webrtc::TransportSequenceNumber>(
137 incoming.rtp.header.extension.transportSequenceNumber);
138 if (incoming.rtp.header.extension.hasAudioLevel)
Joachim Reiersen4a974882024-02-22 19:26:04139 reconstructed_packet.SetExtension<webrtc::AudioLevelExtension>(
Bjorn Terelius60d629f2018-09-24 15:10:27140 incoming.rtp.header.extension.voiceActivity,
141 incoming.rtp.header.extension.audioLevel);
142 if (incoming.rtp.header.extension.hasVideoRotation)
143 reconstructed_packet.SetExtension<webrtc::VideoOrientation>(
144 incoming.rtp.header.extension.videoRotation);
145 if (incoming.rtp.header.extension.hasVideoContentType)
146 reconstructed_packet.SetExtension<webrtc::VideoContentTypeExtension>(
147 incoming.rtp.header.extension.videoContentType);
148 if (incoming.rtp.header.extension.has_video_timing)
149 reconstructed_packet.SetExtension<webrtc::VideoTimingExtension>(
150 incoming.rtp.header.extension.video_timing);
151
152 RTC_DCHECK_EQ(reconstructed_packet.size(), incoming.rtp.header_length);
153 RTC_DCHECK_EQ(reconstructed_packet.headers_size(),
154 incoming.rtp.header_length);
155 memcpy(packet->data, reconstructed_packet.data(),
156 reconstructed_packet.headers_size());
157 packet->length = reconstructed_packet.headers_size();
158 packet->original_length = incoming.rtp.total_length;
159 packet->time_ms = incoming.log_time_ms();
160 // Set padding bit.
161 if (incoming.rtp.header.paddingLength > 0)
162 packet->data[0] = packet->data[0] | 0x20;
Ivo Creusene1aa5b52015-09-18 13:41:07163}
164
165} // namespace
166
167// This utility will convert a stored event log to the rtpdump format.
168int main(int argc, char* argv[]) {
Mirko Bonadeif24729b2019-07-19 10:05:09169 absl::SetProgramUsageMessage(
170 "Tool for converting an RtcEventLog file to an "
171 "RTP dump file.\n"
172 "Example usage:\n"
173 "./rtc_event_log2rtp_dump input.rel output.rtp\n");
Mirko Bonadeiab0b9d42019-07-08 10:31:59174 std::vector<char*> args = absl::ParseCommandLine(argc, argv);
Mirko Bonadeiab0b9d42019-07-08 10:31:59175 if (args.size() != 3) {
Mirko Bonadeif24729b2019-07-19 10:05:09176 std::cout << absl::ProgramUsageMessage();
oprypin6e09d872017-08-31 10:21:39177 return 1;
Ivo Creusene1aa5b52015-09-18 13:41:07178 }
oprypin6e09d872017-08-31 10:21:39179
Mirko Bonadeiab0b9d42019-07-08 10:31:59180 std::string input_file = args[1];
181 std::string output_file = args[2];
Ivo Creusene1aa5b52015-09-18 13:41:07182
Bjorn Terelius60d629f2018-09-24 15:10:27183 absl::optional<uint32_t> ssrc_filter;
Mirko Bonadeiab0b9d42019-07-08 10:31:59184 if (!absl::GetFlag(FLAGS_ssrc).empty()) {
185 ssrc_filter = ParseSsrc(absl::GetFlag(FLAGS_ssrc));
Bjorn Terelius60d629f2018-09-24 15:10:27186 RTC_CHECK(ssrc_filter.has_value()) << "Failed to read SSRC filter flag.";
187 }
Ivo Creusene1aa5b52015-09-18 13:41:07188
Sebastian Janssonb290a6d2019-01-03 13:46:23189 webrtc::ParsedRtcEventLog parsed_stream;
Björn Tereliusa06048a2019-11-01 13:31:46190 auto status = parsed_stream.ParseFile(input_file);
191 if (!status.ok()) {
192 std::cerr << "Failed to parse event log " << input_file << ": "
193 << status.message() << std::endl;
Ivo Creusene1aa5b52015-09-18 13:41:07194 return -1;
195 }
196
kwibergb25345e2016-03-12 14:10:44197 std::unique_ptr<webrtc::test::RtpFileWriter> rtp_writer(
Ivo Creusene1aa5b52015-09-18 13:41:07198 webrtc::test::RtpFileWriter::Create(
199 webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file));
200
Benjamin Wrightf1c9e212019-03-14 00:51:59201 if (!rtp_writer) {
Ivo Creusene1aa5b52015-09-18 13:41:07202 std::cerr << "Error while opening output file: " << output_file
203 << std::endl;
204 return -1;
205 }
206
Ivo Creusene1aa5b52015-09-18 13:41:07207 int rtp_counter = 0, rtcp_counter = 0;
208 bool header_only = false;
Ivo Creusene1aa5b52015-09-18 13:41:07209
Bjorn Terelius60d629f2018-09-24 15:10:27210 webrtc::RtpHeaderExtensionMap default_extension_map =
Sebastian Janssonb290a6d2019-01-03 13:46:23211 webrtc::ParsedRtcEventLog::GetDefaultHeaderExtensionMap();
Bjorn Terelius60d629f2018-09-24 15:10:27212 auto handle_rtp = [&default_extension_map, &rtp_writer, &rtp_counter](
213 const webrtc::LoggedRtpPacketIncoming& incoming) {
214 webrtc::test::RtpPacket packet;
215 ConvertRtpPacket(incoming, default_extension_map, &packet);
perkj77cd58e2017-05-30 10:52:10216
Bjorn Terelius60d629f2018-09-24 15:10:27217 rtp_writer->WritePacket(&packet);
218 rtp_counter++;
219 };
perkj77cd58e2017-05-30 10:52:10220
Bjorn Terelius60d629f2018-09-24 15:10:27221 auto handle_rtcp = [&rtp_writer, &rtcp_counter](
222 const webrtc::LoggedRtcpPacketIncoming& incoming) {
223 webrtc::test::RtpPacket packet;
224 memcpy(packet.data, incoming.rtcp.raw_data.data(),
225 incoming.rtcp.raw_data.size());
226 packet.length = incoming.rtcp.raw_data.size();
227 // For RTCP packets the original_length should be set to 0 in the
228 // RTPdump format.
229 packet.original_length = 0;
230 packet.time_ms = incoming.log_time_ms();
tereliusd5c1a0b2016-05-13 07:42:59231
Bjorn Terelius60d629f2018-09-24 15:10:27232 rtp_writer->WritePacket(&packet);
233 rtcp_counter++;
234 };
Ivo Creusene1aa5b52015-09-18 13:41:07235
Bjorn Terelius60d629f2018-09-24 15:10:27236 webrtc::RtcEventProcessor event_processor;
237 for (const auto& stream : parsed_stream.incoming_rtp_packets_by_ssrc()) {
238 MediaType media_type =
239 parsed_stream.GetMediaType(stream.ssrc, webrtc::kIncomingPacket);
240 if (ShouldSkipStream(media_type, stream.ssrc, ssrc_filter))
241 continue;
Sebastian Jansson03fbf1e2019-01-08 14:31:06242 event_processor.AddEvents(stream.incoming_packets, handle_rtp);
Ivo Creusene1aa5b52015-09-18 13:41:07243 }
Artem Titovaf9a3c62021-07-30 12:22:55244 // Note that `packet_ssrc` is the sender SSRC. An RTCP message may contain
Bjorn Terelius60d629f2018-09-24 15:10:27245 // report blocks for many streams, thus several SSRCs and they don't
246 // necessarily have to be of the same media type. We therefore don't
247 // support filtering of RTCP based on SSRC and media type.
Sebastian Jansson03fbf1e2019-01-08 14:31:06248 event_processor.AddEvents(parsed_stream.incoming_rtcp_packets(), handle_rtcp);
Bjorn Terelius60d629f2018-09-24 15:10:27249
250 event_processor.ProcessEventsInOrder();
251
Ivo Creusene1aa5b52015-09-18 13:41:07252 std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "")
Jonas Olssonb2b20312020-01-14 11:11:31253 << " RTP packets and " << rtcp_counter
254 << " RTCP packets to the "
255 "output file."
256 << std::endl;
Ivo Creusene1aa5b52015-09-18 13:41:07257 return 0;
258}