Add pcap support to bwe tools. Allow filtering on SSRCs.

Also switches the command line interface to gflags.

Review URL: https://codereview.webrtc.org/1235433005

Cr-Commit-Position: refs/heads/master@{#9599}
This commit is contained in:
stefan 2015-07-17 05:27:21 -07:00 committed by Commit bot
parent fabe2c961f
commit b947f287a6
6 changed files with 129 additions and 60 deletions

View File

@ -105,6 +105,7 @@
'target_name': 'bwe_tools_util',
'type': 'static_library',
'dependencies': [
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
'rtp_rtcp',
],

View File

@ -10,9 +10,11 @@
#include "webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h"
#include <sstream>
#include <stdio.h>
#include <string>
#include "gflags/gflags.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
@ -21,6 +23,49 @@
const int kMinBitrateBps = 30000;
namespace flags {
DEFINE_string(extension_type,
"abs",
"Extension type, either abs for absolute send time or tsoffset "
"for timestamp offset.");
std::string ExtensionType() {
return static_cast<std::string>(FLAGS_extension_type);
}
DEFINE_int32(extension_id, 3, "Extension id.");
int ExtensionId() {
return static_cast<int>(FLAGS_extension_id);
}
DEFINE_string(input_file, "", "Input file.");
std::string InputFile() {
return static_cast<std::string>(FLAGS_input_file);
}
DEFINE_string(ssrc_filter,
"",
"Comma-separated list of SSRCs in hexadecimal which are to be "
"used as input to the BWE (only applicable to pcap files).");
std::set<uint32_t> SsrcFilter() {
std::string ssrc_filter_string = static_cast<std::string>(FLAGS_ssrc_filter);
if (ssrc_filter_string.empty())
return std::set<uint32_t>();
std::stringstream ss;
std::string ssrc_filter = ssrc_filter_string;
std::set<uint32_t> ssrcs;
// Parse the ssrcs in hexadecimal format.
ss << std::hex << ssrc_filter;
uint32_t ssrc;
while (ss >> ssrc) {
ssrcs.insert(ssrc);
ss.ignore(1, ',');
}
return ssrcs;
}
} // namespace flags
bool ParseArgsAndSetupEstimator(int argc,
char** argv,
webrtc::Clock* clock,
@ -29,26 +74,45 @@ bool ParseArgsAndSetupEstimator(int argc,
webrtc::RtpHeaderParser** parser,
webrtc::RemoteBitrateEstimator** estimator,
std::string* estimator_used) {
*rtp_reader = webrtc::test::RtpFileReader::Create(
webrtc::test::RtpFileReader::kRtpDump, argv[3]);
google::ParseCommandLineFlags(&argc, &argv, true);
std::string filename = flags::InputFile();
std::set<uint32_t> ssrc_filter = flags::SsrcFilter();
fprintf(stderr, "Filter on SSRC: ");
for (auto& s : ssrc_filter) {
fprintf(stderr, "0x%08x, ", s);
}
fprintf(stderr, "\n");
if (filename.substr(filename.find_last_of(".")) == ".pcap") {
fprintf(stderr, "Opening as pcap\n");
*rtp_reader = webrtc::test::RtpFileReader::Create(
webrtc::test::RtpFileReader::kPcap, filename.c_str(),
flags::SsrcFilter());
} else {
fprintf(stderr, "Opening as rtp\n");
*rtp_reader = webrtc::test::RtpFileReader::Create(
webrtc::test::RtpFileReader::kRtpDump, filename.c_str());
}
if (!*rtp_reader) {
fprintf(stderr, "Cannot open input file %s\n", argv[3]);
fprintf(stderr, "Cannot open input file %s\n", filename.c_str());
return false;
}
fprintf(stderr, "Input file: %s\n\n", argv[3]);
webrtc::RTPExtensionType extension = webrtc::kRtpExtensionAbsoluteSendTime;
fprintf(stderr, "Input file: %s\n\n", filename.c_str());
if (strncmp("tsoffset", argv[1], 8) == 0) {
webrtc::RTPExtensionType extension = webrtc::kRtpExtensionAbsoluteSendTime;
if (flags::ExtensionType() == "tsoffset") {
extension = webrtc::kRtpExtensionTransmissionTimeOffset;
fprintf(stderr, "Extension: toffset\n");
} else {
} else if (flags::ExtensionType() == "abs") {
fprintf(stderr, "Extension: abs\n");
} else {
fprintf(stderr, "Unknown extension type\n");
return false;
}
int id = atoi(argv[2]);
// Setup the RTP header parser and the bitrate estimator.
*parser = webrtc::RtpHeaderParser::Create();
(*parser)->RegisterRtpHeaderExtension(extension, id);
(*parser)->RegisterRtpHeaderExtension(extension, flags::ExtensionId());
if (estimator) {
switch (extension) {
case webrtc::kRtpExtensionAbsoluteSendTime: {

View File

@ -38,15 +38,6 @@ class Observer : public webrtc::RemoteBitrateObserver {
};
int main(int argc, char** argv) {
if (argc < 4) {
printf("Usage: bwe_rtp_play <extension type> <extension id> "
"<input_file.rtp>\n");
printf("<extension type> can either be:\n"
" abs for absolute send time or\n"
" tsoffset for timestamp offset.\n"
"<extension id> is the id associated with the extension.\n");
return -1;
}
webrtc::test::RtpFileReader* reader;
webrtc::RemoteBitrateEstimator* estimator;
webrtc::RtpHeaderParser* parser;
@ -76,22 +67,24 @@ int main(int argc, char** argv) {
packet.time_ms = packet.time_ms - first_rtp_time_ms;
while (true) {
if (next_rtp_time_ms <= clock.TimeInMilliseconds()) {
webrtc::RTPHeader header;
parser->Parse(packet.data, packet.length, &header);
if (header.extension.hasAbsoluteSendTime)
++abs_send_time_count;
if (header.extension.hasTransmissionTimeOffset)
++ts_offset_count;
size_t packet_length = packet.length;
// Some RTP dumps only include the header, in which case packet.length
// is equal to the header length. In those cases packet.original_length
// usually contains the original packet length.
if (packet.original_length > 0) {
packet_length = packet.original_length;
if (!parser->IsRtcp(packet.data, packet.length)) {
webrtc::RTPHeader header;
parser->Parse(packet.data, packet.length, &header);
if (header.extension.hasAbsoluteSendTime)
++abs_send_time_count;
if (header.extension.hasTransmissionTimeOffset)
++ts_offset_count;
size_t packet_length = packet.length;
// Some RTP dumps only include the header, in which case packet.length
// is equal to the header length. In those cases packet.original_length
// usually contains the original packet length.
if (packet.original_length > 0) {
packet_length = packet.original_length;
}
rbe->IncomingPacket(clock.TimeInMilliseconds(),
packet_length - header.headerLength, header, true);
++packet_counter;
}
rbe->IncomingPacket(clock.TimeInMilliseconds(),
packet_length - header.headerLength, header, true);
++packet_counter;
if (!rtp_reader->NextPacket(&packet)) {
break;
}

View File

@ -19,17 +19,6 @@
#include "webrtc/test/rtp_file_reader.h"
int main(int argc, char** argv) {
if (argc < 4) {
fprintf(stderr, "Usage: rtp_to_text <extension type> <extension id>"
" <input_file.rtp> [-t]\n");
fprintf(stderr, "<extension type> can either be:\n"
" abs for absolute send time or\n"
" tsoffset for timestamp offset.\n"
"<extension id> is the id associated with the extension.\n"
" -t is an optional flag, if set only packet arrival time will be"
" output.\n");
return -1;
}
webrtc::test::RtpFileReader* reader;
webrtc::RtpHeaderParser* parser;
if (!ParseArgsAndSetupEstimator(argc, argv, NULL, NULL, &reader, &parser,

View File

@ -69,7 +69,8 @@ bool ReadUint16(uint16_t* out, FILE* file) {
class RtpFileReaderImpl : public RtpFileReader {
public:
virtual bool Init(const std::string& filename) = 0;
virtual bool Init(const std::string& filename,
const std::set<uint32_t>& ssrc_filter) = 0;
};
class InterleavedRtpFileReader : public RtpFileReaderImpl {
@ -81,7 +82,8 @@ class InterleavedRtpFileReader : public RtpFileReaderImpl {
}
}
virtual bool Init(const std::string& filename) {
virtual bool Init(const std::string& filename,
const std::set<uint32_t>& ssrc_filter) {
file_ = fopen(filename.c_str(), "rb");
if (file_ == NULL) {
printf("ERROR: Can't open file: %s\n", filename.c_str());
@ -127,7 +129,8 @@ class RtpDumpReader : public RtpFileReaderImpl {
}
}
bool Init(const std::string& filename) {
bool Init(const std::string& filename,
const std::set<uint32_t>& ssrc_filter) {
file_ = fopen(filename.c_str(), "rb");
if (file_ == NULL) {
printf("ERROR: Can't open file: %s\n", filename.c_str());
@ -265,11 +268,13 @@ class PcapReader : public RtpFileReaderImpl {
}
}
bool Init(const std::string& filename) override {
return Initialize(filename) == kResultSuccess;
bool Init(const std::string& filename,
const std::set<uint32_t>& ssrc_filter) override {
return Initialize(filename, ssrc_filter) == kResultSuccess;
}
int Initialize(const std::string& filename) {
int Initialize(const std::string& filename,
const std::set<uint32_t>& ssrc_filter) {
file_ = fopen(filename.c_str(), "rb");
if (file_ == NULL) {
printf("ERROR: Can't open file: %s\n", filename.c_str());
@ -286,7 +291,7 @@ class PcapReader : public RtpFileReaderImpl {
for (;;) {
TRY_PCAP(fseek(file_, next_packet_pos, SEEK_SET));
int result = ReadPacket(&next_packet_pos, stream_start_ms,
++total_packet_count);
++total_packet_count, ssrc_filter);
if (result == kResultFail) {
break;
} else if (result == kResultSuccess && packets_.size() == 1) {
@ -308,10 +313,10 @@ class PcapReader : public RtpFileReaderImpl {
for (SsrcMapIterator mit = packets_by_ssrc_.begin();
mit != packets_by_ssrc_.end(); ++mit) {
uint32_t ssrc = mit->first;
const std::vector<uint32_t>& packet_numbers = mit->second;
uint8_t pt = packets_[packet_numbers[0]].rtp_header.payloadType;
const std::vector<uint32_t>& packet_indices = mit->second;
uint8_t pt = packets_[packet_indices[0]].rtp_header.payloadType;
printf("SSRC: %08x, %" PRIuS " packets, pt=%d\n", ssrc,
packet_numbers.size(), pt);
packet_indices.size(), pt);
}
// TODO(solenberg): Better validation of identified SSRC streams.
@ -419,8 +424,10 @@ class PcapReader : public RtpFileReaderImpl {
return kResultSuccess;
}
int ReadPacket(int32_t* next_packet_pos, uint32_t stream_start_ms,
uint32_t number) {
int ReadPacket(int32_t* next_packet_pos,
uint32_t stream_start_ms,
uint32_t number,
const std::set<uint32_t>& ssrc_filter) {
assert(next_packet_pos);
uint32_t ts_sec; // Timestamp seconds.
@ -457,8 +464,13 @@ class PcapReader : public RtpFileReaderImpl {
}
uint32_t ssrc = marker.rtp_header.ssrc;
packets_by_ssrc_[ssrc].push_back(marker.packet_number);
packets_.push_back(marker);
if (ssrc_filter.empty() || ssrc_filter.find(ssrc) != ssrc_filter.end()) {
packets_by_ssrc_[ssrc].push_back(
static_cast<uint32_t>(packets_.size()));
packets_.push_back(marker);
} else {
return kResultSkip;
}
}
return kResultSuccess;
@ -632,7 +644,8 @@ class PcapReader : public RtpFileReaderImpl {
};
RtpFileReader* RtpFileReader::Create(FileFormat format,
const std::string& filename) {
const std::string& filename,
const std::set<uint32_t>& ssrc_filter) {
RtpFileReaderImpl* reader = NULL;
switch (format) {
case kPcap:
@ -645,12 +658,17 @@ RtpFileReader* RtpFileReader::Create(FileFormat format,
reader = new InterleavedRtpFileReader();
break;
}
if (!reader->Init(filename)) {
if (!reader->Init(filename, ssrc_filter)) {
delete reader;
return NULL;
}
return reader;
}
RtpFileReader* RtpFileReader::Create(FileFormat format,
const std::string& filename) {
return RtpFileReader::Create(format, filename, std::set<uint32_t>());
}
} // namespace test
} // namespace webrtc

View File

@ -10,6 +10,7 @@
#ifndef WEBRTC_TEST_RTP_FILE_READER_H_
#define WEBRTC_TEST_RTP_FILE_READER_H_
#include <set>
#include <string>
#include "webrtc/common_types.h"
@ -37,6 +38,9 @@ class RtpFileReader {
virtual ~RtpFileReader() {}
static RtpFileReader* Create(FileFormat format,
const std::string& filename);
static RtpFileReader* Create(FileFormat format,
const std::string& filename,
const std::set<uint32_t>& ssrc_filter);
virtual bool NextPacket(RtpPacket* packet) = 0;
};