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:
parent
fabe2c961f
commit
b947f287a6
@ -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',
|
||||
],
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user