Files
platform-external-webrtc/webrtc/call/rtc_event_log2rtp_dump.cc
terelius d5c1a0bd5d New parser for event log. Manually parse the outermost EventStream to more easily deal with corrupt or partially written logs.
Changed rtpdump converter and neteq tool to use new parser, but still aborting if the file is corrupt.

Review-Url: https://codereview.webrtc.org/1768773002
Cr-Commit-Position: refs/heads/master@{#12714}
2016-05-13 07:43:04 +00:00

187 lines
6.6 KiB
C++

/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include "gflags/gflags.h"
#include "webrtc/base/checks.h"
#include "webrtc/call.h"
#include "webrtc/call/rtc_event_log.h"
#include "webrtc/call/rtc_event_log_parser.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/test/rtp_file_writer.h"
namespace {
DEFINE_bool(noaudio,
false,
"Excludes audio packets from the converted RTPdump file.");
DEFINE_bool(novideo,
false,
"Excludes video packets from the converted RTPdump file.");
DEFINE_bool(nodata,
false,
"Excludes data packets from the converted RTPdump file.");
DEFINE_bool(nortp,
false,
"Excludes RTP packets from the converted RTPdump file.");
DEFINE_bool(nortcp,
false,
"Excludes RTCP packets from the converted RTPdump file.");
DEFINE_string(ssrc,
"",
"Store only packets with this SSRC (decimal or hex, the latter "
"starting with 0x).");
// Parses the input string for a valid SSRC. If a valid SSRC is found, it is
// written to the output variable |ssrc|, and true is returned. Otherwise,
// false is returned.
// The empty string must be validated as true, because it is the default value
// of the command-line flag. In this case, no value is written to the output
// variable.
bool ParseSsrc(std::string str, uint32_t* ssrc) {
// If the input string starts with 0x or 0X it indicates a hexadecimal number.
auto read_mode = std::dec;
if (str.size() > 2 &&
(str.substr(0, 2) == "0x" || str.substr(0, 2) == "0X")) {
read_mode = std::hex;
str = str.substr(2);
}
std::stringstream ss(str);
ss >> read_mode >> *ssrc;
return str.empty() || (!ss.fail() && ss.eof());
}
} // namespace
// This utility will convert a stored event log to the rtpdump format.
int main(int argc, char* argv[]) {
std::string program_name = argv[0];
std::string usage =
"Tool for converting an RtcEventLog file to an RTP dump file.\n"
"Run " +
program_name +
" --helpshort for usage.\n"
"Example usage:\n" +
program_name + " input.rel output.rtp\n";
google::SetUsageMessage(usage);
google::ParseCommandLineFlags(&argc, &argv, true);
if (argc != 3) {
std::cout << google::ProgramUsage();
return 0;
}
std::string input_file = argv[1];
std::string output_file = argv[2];
uint32_t ssrc_filter = 0;
if (!FLAGS_ssrc.empty())
RTC_CHECK(ParseSsrc(FLAGS_ssrc, &ssrc_filter))
<< "Flag verification has failed.";
webrtc::ParsedRtcEventLog parsed_stream;
if (!parsed_stream.ParseFile(input_file)) {
std::cerr << "Error while parsing input file: " << input_file << std::endl;
return -1;
}
std::unique_ptr<webrtc::test::RtpFileWriter> rtp_writer(
webrtc::test::RtpFileWriter::Create(
webrtc::test::RtpFileWriter::FileFormat::kRtpDump, output_file));
if (!rtp_writer.get()) {
std::cerr << "Error while opening output file: " << output_file
<< std::endl;
return -1;
}
std::cout << "Found " << parsed_stream.GetNumberOfEvents()
<< " events in the input file." << std::endl;
int rtp_counter = 0, rtcp_counter = 0;
bool header_only = false;
for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) {
// The parsed_stream will assert if the protobuf event is missing
// some required fields and we attempt to access them. We could consider
// a softer failure option, but it does not seem useful to generate
// RTP dumps based on broken event logs.
if (!FLAGS_nortp &&
parsed_stream.GetEventType(i) == webrtc::ParsedRtcEventLog::RTP_EVENT) {
webrtc::test::RtpPacket packet;
webrtc::PacketDirection direction;
webrtc::MediaType media_type;
parsed_stream.GetRtpHeader(i, &direction, &media_type, packet.data,
&packet.length, &packet.original_length);
if (packet.original_length > packet.length)
header_only = true;
packet.time_ms = parsed_stream.GetTimestamp(i) / 1000;
// TODO(terelius): Maybe add a flag to dump outgoing traffic instead?
if (direction == webrtc::kOutgoingPacket)
continue;
if (FLAGS_noaudio && media_type == webrtc::MediaType::AUDIO)
continue;
if (FLAGS_novideo && media_type == webrtc::MediaType::VIDEO)
continue;
if (FLAGS_nodata && media_type == webrtc::MediaType::DATA)
continue;
if (!FLAGS_ssrc.empty()) {
const uint32_t packet_ssrc =
webrtc::ByteReader<uint32_t>::ReadBigEndian(
reinterpret_cast<const uint8_t*>(packet.data + 8));
if (packet_ssrc != ssrc_filter)
continue;
}
rtp_writer->WritePacket(&packet);
rtp_counter++;
}
if (!FLAGS_nortcp &&
parsed_stream.GetEventType(i) ==
webrtc::ParsedRtcEventLog::RTCP_EVENT) {
webrtc::test::RtpPacket packet;
webrtc::PacketDirection direction;
webrtc::MediaType media_type;
parsed_stream.GetRtcpPacket(i, &direction, &media_type, packet.data,
&packet.length);
// For RTCP packets the original_length should be set to 0 in the
// RTPdump format.
packet.original_length = 0;
packet.time_ms = parsed_stream.GetTimestamp(i) / 1000;
// TODO(terelius): Maybe add a flag to dump outgoing traffic instead?
if (direction == webrtc::kOutgoingPacket)
continue;
if (FLAGS_noaudio && media_type == webrtc::MediaType::AUDIO)
continue;
if (FLAGS_novideo && media_type == webrtc::MediaType::VIDEO)
continue;
if (FLAGS_nodata && media_type == webrtc::MediaType::DATA)
continue;
if (!FLAGS_ssrc.empty()) {
const uint32_t packet_ssrc =
webrtc::ByteReader<uint32_t>::ReadBigEndian(
reinterpret_cast<const uint8_t*>(packet.data + 4));
if (packet_ssrc != ssrc_filter)
continue;
}
rtp_writer->WritePacket(&packet);
rtcp_counter++;
}
}
std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "")
<< " RTP packets and " << rtcp_counter << " RTCP packets to the "
<< "output file." << std::endl;
return 0;
}