Adding a new test helper RtpFileWriter and use it in RTPcat
This new helper class writes RTP packets to file in rtpdump format. A unit test is also included. The new test class is used while re-writing the test tool RTPcat. BUG=2692 R=pbos@webrtc.org Review URL: https://webrtc-codereview.appspot.com/28099004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7768 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
4796301c0e
commit
83317146ba
@ -122,8 +122,8 @@
|
|||||||
'target_name': 'RTPcat',
|
'target_name': 'RTPcat',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'neteq_test_tools',
|
|
||||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||||
|
'<(webrtc_root)/test/test.gyp:rtp_test_utils',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'test/RTPcat.cc',
|
'test/RTPcat.cc',
|
||||||
|
@ -10,13 +10,14 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include "webrtc/base/checks.h"
|
||||||
#include <vector>
|
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||||
|
#include "webrtc/test/rtp_file_reader.h"
|
||||||
|
#include "webrtc/test/rtp_file_writer.h"
|
||||||
|
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
using webrtc::scoped_ptr;
|
||||||
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
|
using webrtc::test::RtpFileReader;
|
||||||
|
using webrtc::test::RtpFileWriter;
|
||||||
#define FIRSTLINELEN 40
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
@ -24,52 +25,20 @@ int main(int argc, char* argv[]) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* in_file = fopen(argv[1], "rb");
|
scoped_ptr<RtpFileWriter> output(
|
||||||
if (!in_file) {
|
RtpFileWriter::Create(RtpFileWriter::kRtpDump, argv[argc - 1]));
|
||||||
printf("Cannot open input file %s\n", argv[1]);
|
CHECK(output.get() != NULL) << "Cannot open output file.";
|
||||||
return -1;
|
printf("Output RTP file: %s\n", argv[argc - 1]);
|
||||||
}
|
|
||||||
|
|
||||||
FILE* out_file = fopen(argv[argc - 1], "wb"); // Last parameter is out file.
|
|
||||||
if (!out_file) {
|
|
||||||
printf("Cannot open output file %s\n", argv[argc - 1]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Output RTP file: %s\n\n", argv[argc - 1]);
|
|
||||||
|
|
||||||
// Read file header and write directly to output file.
|
|
||||||
char firstline[FIRSTLINELEN];
|
|
||||||
const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
|
||||||
EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, in_file) != NULL);
|
|
||||||
EXPECT_GT(fputs(firstline, out_file), 0);
|
|
||||||
EXPECT_EQ(kRtpDumpHeaderSize, fread(firstline, 1, kRtpDumpHeaderSize,
|
|
||||||
in_file));
|
|
||||||
EXPECT_EQ(kRtpDumpHeaderSize, fwrite(firstline, 1, kRtpDumpHeaderSize,
|
|
||||||
out_file));
|
|
||||||
|
|
||||||
// Close input file and re-open it later (easier to write the loop below).
|
|
||||||
fclose(in_file);
|
|
||||||
|
|
||||||
for (int i = 1; i < argc - 1; i++) {
|
for (int i = 1; i < argc - 1; i++) {
|
||||||
in_file = fopen(argv[i], "rb");
|
scoped_ptr<RtpFileReader> input(
|
||||||
if (!in_file) {
|
RtpFileReader::Create(RtpFileReader::kRtpDump, argv[i]));
|
||||||
printf("Cannot open input file %s\n", argv[i]);
|
CHECK(input.get() != NULL) << "Cannot open input file " << argv[i];
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Input RTP file: %s\n", argv[i]);
|
printf("Input RTP file: %s\n", argv[i]);
|
||||||
|
|
||||||
NETEQTEST_RTPpacket::skipFileHeader(in_file);
|
webrtc::test::RtpPacket packet;
|
||||||
NETEQTEST_RTPpacket packet;
|
while (input->NextPacket(&packet))
|
||||||
int pack_len = packet.readFromFile(in_file);
|
CHECK(output->WritePacket(&packet));
|
||||||
if (pack_len < 0) {
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
while (pack_len >= 0) {
|
|
||||||
packet.writeToFile(out_file);
|
|
||||||
pack_len = packet.readFromFile(in_file);
|
|
||||||
}
|
|
||||||
fclose(in_file);
|
|
||||||
}
|
|
||||||
fclose(out_file);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -91,11 +91,11 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
|||||||
uint32_t source;
|
uint32_t source;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
uint16_t padding;
|
uint16_t padding;
|
||||||
TRY(Read(&start_sec));
|
TRY(ReadUint32(&start_sec));
|
||||||
TRY(Read(&start_usec));
|
TRY(ReadUint32(&start_usec));
|
||||||
TRY(Read(&source));
|
TRY(ReadUint32(&source));
|
||||||
TRY(Read(&port));
|
TRY(ReadUint16(&port));
|
||||||
TRY(Read(&padding));
|
TRY(ReadUint16(&padding));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -107,9 +107,9 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
|||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint16_t plen;
|
uint16_t plen;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
TRY(Read(&len));
|
TRY(ReadUint16(&len));
|
||||||
TRY(Read(&plen));
|
TRY(ReadUint16(&plen));
|
||||||
TRY(Read(&offset));
|
TRY(ReadUint32(&offset));
|
||||||
|
|
||||||
// Use 'len' here because a 'plen' of 0 specifies rtcp.
|
// Use 'len' here because a 'plen' of 0 specifies rtcp.
|
||||||
len -= kPacketHeaderSize;
|
len -= kPacketHeaderSize;
|
||||||
@ -130,7 +130,7 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Read(uint32_t* out) {
|
bool ReadUint32(uint32_t* out) {
|
||||||
*out = 0;
|
*out = 0;
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
*out <<= 8;
|
*out <<= 8;
|
||||||
@ -142,7 +142,7 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Read(uint16_t* out) {
|
bool ReadUint16(uint16_t* out) {
|
||||||
*out = 0;
|
*out = 0;
|
||||||
for (size_t i = 0; i < 2; ++i) {
|
for (size_t i = 0; i < 2; ++i) {
|
||||||
*out <<= 8;
|
*out <<= 8;
|
||||||
|
109
webrtc/test/rtp_file_writer.cc
Normal file
109
webrtc/test/rtp_file_writer.cc
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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 "webrtc/test/rtp_file_writer.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "webrtc/base/checks.h"
|
||||||
|
#include "webrtc/base/constructormagic.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
static const uint16_t kPacketHeaderSize = 8;
|
||||||
|
static const char kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n";
|
||||||
|
|
||||||
|
// Write RTP packets to file in rtpdump format, as documented at:
|
||||||
|
// http://www.cs.columbia.edu/irt/software/rtptools/
|
||||||
|
class RtpDumpWriter : public RtpFileWriter {
|
||||||
|
public:
|
||||||
|
explicit RtpDumpWriter(FILE* file) : file_(file) {
|
||||||
|
CHECK(file_ != NULL);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
virtual ~RtpDumpWriter() {
|
||||||
|
if (file_ != NULL) {
|
||||||
|
fclose(file_);
|
||||||
|
file_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool WritePacket(const RtpPacket* packet) OVERRIDE {
|
||||||
|
uint16_t len = static_cast<uint16_t>(packet->length + kPacketHeaderSize);
|
||||||
|
CHECK_GE(packet->original_length, packet->length);
|
||||||
|
uint16_t plen = static_cast<uint16_t>(packet->original_length);
|
||||||
|
uint32_t offset = packet->time_ms;
|
||||||
|
CHECK(WriteUint16(len));
|
||||||
|
CHECK(WriteUint16(plen));
|
||||||
|
CHECK(WriteUint32(offset));
|
||||||
|
return fwrite(packet->data, sizeof(uint8_t), packet->length, file_) ==
|
||||||
|
packet->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool Init() {
|
||||||
|
fprintf(file_, "%s", kFirstLine);
|
||||||
|
|
||||||
|
CHECK(WriteUint32(0));
|
||||||
|
CHECK(WriteUint32(0));
|
||||||
|
CHECK(WriteUint32(0));
|
||||||
|
CHECK(WriteUint16(0));
|
||||||
|
CHECK(WriteUint16(0));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteUint32(uint32_t in) {
|
||||||
|
// Loop through shifts = {24, 16, 8, 0}.
|
||||||
|
for (int shifts = 24; shifts >= 0; shifts -= 8) {
|
||||||
|
uint8_t tmp = static_cast<uint8_t>((in >> shifts) & 0xFF);
|
||||||
|
if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteUint16(uint16_t in) {
|
||||||
|
// Write 8 MSBs.
|
||||||
|
uint8_t tmp = static_cast<uint8_t>((in >> 8) & 0xFF);
|
||||||
|
if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1)
|
||||||
|
return false;
|
||||||
|
// Write 8 LSBs.
|
||||||
|
tmp = static_cast<uint8_t>(in & 0xFF);
|
||||||
|
if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* file_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter);
|
||||||
|
};
|
||||||
|
|
||||||
|
RtpFileWriter* RtpFileWriter::Create(FileFormat format,
|
||||||
|
const std::string& filename) {
|
||||||
|
FILE* file = fopen(filename.c_str(), "wb");
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("ERROR: Can't open file: %s\n", filename.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
switch (format) {
|
||||||
|
case kRtpDump:
|
||||||
|
return new RtpDumpWriter(file);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace webrtc
|
33
webrtc/test/rtp_file_writer.h
Normal file
33
webrtc/test/rtp_file_writer.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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.
|
||||||
|
*/
|
||||||
|
#ifndef WEBRTC_TEST_RTP_FILE_WRITER_H_
|
||||||
|
#define WEBRTC_TEST_RTP_FILE_WRITER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "webrtc/common_types.h"
|
||||||
|
#include "webrtc/test/rtp_file_reader.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace test {
|
||||||
|
class RtpFileWriter {
|
||||||
|
public:
|
||||||
|
enum FileFormat {
|
||||||
|
kRtpDump,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~RtpFileWriter() {}
|
||||||
|
static RtpFileWriter* Create(FileFormat format, const std::string& filename);
|
||||||
|
|
||||||
|
virtual bool WritePacket(const RtpPacket* packet) = 0;
|
||||||
|
};
|
||||||
|
} // namespace test
|
||||||
|
} // namespace webrtc
|
||||||
|
#endif // WEBRTC_TEST_RTP_FILE_WRITER_H_
|
75
webrtc/test/rtp_file_writer_unittest.cc
Normal file
75
webrtc/test/rtp_file_writer_unittest.cc
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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 <string.h>
|
||||||
|
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||||
|
#include "webrtc/test/rtp_file_reader.h"
|
||||||
|
#include "webrtc/test/rtp_file_writer.h"
|
||||||
|
#include "webrtc/test/testsupport/fileutils.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class RtpFileWriterTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
void Init(const std::string& filename) {
|
||||||
|
filename_ = test::OutputPath() + filename;
|
||||||
|
rtp_writer_.reset(
|
||||||
|
test::RtpFileWriter::Create(test::RtpFileWriter::kRtpDump, filename_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteRtpPackets(int num_packets) {
|
||||||
|
ASSERT_TRUE(rtp_writer_.get() != NULL);
|
||||||
|
test::RtpPacket packet;
|
||||||
|
for (int i = 1; i <= num_packets; ++i) {
|
||||||
|
packet.length = i;
|
||||||
|
packet.original_length = i;
|
||||||
|
packet.time_ms = i;
|
||||||
|
memset(packet.data, i, packet.length);
|
||||||
|
EXPECT_TRUE(rtp_writer_->WritePacket(&packet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseOutputFile() { rtp_writer_.reset(); }
|
||||||
|
|
||||||
|
void VerifyFileContents(int expected_packets) {
|
||||||
|
ASSERT_TRUE(rtp_writer_.get() == NULL)
|
||||||
|
<< "Must call CloseOutputFile before VerifyFileContents";
|
||||||
|
scoped_ptr<test::RtpFileReader> rtp_reader(
|
||||||
|
test::RtpFileReader::Create(test::RtpFileReader::kRtpDump, filename_));
|
||||||
|
ASSERT_TRUE(rtp_reader.get() != NULL);
|
||||||
|
test::RtpPacket packet;
|
||||||
|
int i = 0;
|
||||||
|
while (rtp_reader->NextPacket(&packet)) {
|
||||||
|
++i;
|
||||||
|
EXPECT_EQ(static_cast<size_t>(i), packet.length);
|
||||||
|
EXPECT_EQ(static_cast<size_t>(i), packet.original_length);
|
||||||
|
EXPECT_EQ(static_cast<uint32_t>(i), packet.time_ms);
|
||||||
|
for (int j = 0; j < i; ++j) {
|
||||||
|
EXPECT_EQ(i, packet.data[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(expected_packets, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
scoped_ptr<test::RtpFileWriter> rtp_writer_;
|
||||||
|
std::string filename_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(RtpFileWriterTest, WriteToRtpDump) {
|
||||||
|
Init("test_rtp_file_writer.rtp");
|
||||||
|
WriteRtpPackets(10);
|
||||||
|
CloseOutputFile();
|
||||||
|
VerifyFileContents(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
@ -60,6 +60,8 @@
|
|||||||
'rtcp_packet_parser.h',
|
'rtcp_packet_parser.h',
|
||||||
'rtp_file_reader.cc',
|
'rtp_file_reader.cc',
|
||||||
'rtp_file_reader.h',
|
'rtp_file_reader.h',
|
||||||
|
'rtp_file_writer.cc',
|
||||||
|
'rtp_file_writer.h',
|
||||||
],
|
],
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
|
'<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
|
||||||
|
@ -157,6 +157,7 @@
|
|||||||
'sources': [
|
'sources': [
|
||||||
'fake_network_pipe_unittest.cc',
|
'fake_network_pipe_unittest.cc',
|
||||||
'rtp_file_reader_unittest.cc',
|
'rtp_file_reader_unittest.cc',
|
||||||
|
'rtp_file_writer_unittest.cc',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
], #targets
|
], #targets
|
||||||
|
Loading…
Reference in New Issue
Block a user