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',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'neteq_test_tools',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/test/test.gyp:rtp_test_utils',
|
||||
],
|
||||
'sources': [
|
||||
'test/RTPcat.cc',
|
||||
|
@ -10,13 +10,14 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "webrtc/base/checks.h"
|
||||
#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"
|
||||
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
|
||||
|
||||
#define FIRSTLINELEN 40
|
||||
using webrtc::scoped_ptr;
|
||||
using webrtc::test::RtpFileReader;
|
||||
using webrtc::test::RtpFileWriter;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
@ -24,52 +25,20 @@ int main(int argc, char* argv[]) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE* in_file = fopen(argv[1], "rb");
|
||||
if (!in_file) {
|
||||
printf("Cannot open input file %s\n", argv[1]);
|
||||
return -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);
|
||||
scoped_ptr<RtpFileWriter> output(
|
||||
RtpFileWriter::Create(RtpFileWriter::kRtpDump, argv[argc - 1]));
|
||||
CHECK(output.get() != NULL) << "Cannot open output file.";
|
||||
printf("Output RTP file: %s\n", argv[argc - 1]);
|
||||
|
||||
for (int i = 1; i < argc - 1; i++) {
|
||||
in_file = fopen(argv[i], "rb");
|
||||
if (!in_file) {
|
||||
printf("Cannot open input file %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
scoped_ptr<RtpFileReader> input(
|
||||
RtpFileReader::Create(RtpFileReader::kRtpDump, argv[i]));
|
||||
CHECK(input.get() != NULL) << "Cannot open input file " << argv[i];
|
||||
printf("Input RTP file: %s\n", argv[i]);
|
||||
|
||||
NETEQTEST_RTPpacket::skipFileHeader(in_file);
|
||||
NETEQTEST_RTPpacket packet;
|
||||
int pack_len = packet.readFromFile(in_file);
|
||||
if (pack_len < 0) {
|
||||
exit(1);
|
||||
}
|
||||
while (pack_len >= 0) {
|
||||
packet.writeToFile(out_file);
|
||||
pack_len = packet.readFromFile(in_file);
|
||||
}
|
||||
fclose(in_file);
|
||||
webrtc::test::RtpPacket packet;
|
||||
while (input->NextPacket(&packet))
|
||||
CHECK(output->WritePacket(&packet));
|
||||
}
|
||||
fclose(out_file);
|
||||
return 0;
|
||||
}
|
||||
|
@ -91,11 +91,11 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
||||
uint32_t source;
|
||||
uint16_t port;
|
||||
uint16_t padding;
|
||||
TRY(Read(&start_sec));
|
||||
TRY(Read(&start_usec));
|
||||
TRY(Read(&source));
|
||||
TRY(Read(&port));
|
||||
TRY(Read(&padding));
|
||||
TRY(ReadUint32(&start_sec));
|
||||
TRY(ReadUint32(&start_usec));
|
||||
TRY(ReadUint32(&source));
|
||||
TRY(ReadUint16(&port));
|
||||
TRY(ReadUint16(&padding));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -107,9 +107,9 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
||||
uint16_t len;
|
||||
uint16_t plen;
|
||||
uint32_t offset;
|
||||
TRY(Read(&len));
|
||||
TRY(Read(&plen));
|
||||
TRY(Read(&offset));
|
||||
TRY(ReadUint16(&len));
|
||||
TRY(ReadUint16(&plen));
|
||||
TRY(ReadUint32(&offset));
|
||||
|
||||
// Use 'len' here because a 'plen' of 0 specifies rtcp.
|
||||
len -= kPacketHeaderSize;
|
||||
@ -130,7 +130,7 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
||||
}
|
||||
|
||||
private:
|
||||
bool Read(uint32_t* out) {
|
||||
bool ReadUint32(uint32_t* out) {
|
||||
*out = 0;
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
*out <<= 8;
|
||||
@ -142,7 +142,7 @@ class RtpDumpReader : public RtpFileReaderImpl {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(uint16_t* out) {
|
||||
bool ReadUint16(uint16_t* out) {
|
||||
*out = 0;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
*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',
|
||||
'rtp_file_reader.cc',
|
||||
'rtp_file_reader.h',
|
||||
'rtp_file_writer.cc',
|
||||
'rtp_file_writer.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
|
||||
|
@ -157,6 +157,7 @@
|
||||
'sources': [
|
||||
'fake_network_pipe_unittest.cc',
|
||||
'rtp_file_reader_unittest.cc',
|
||||
'rtp_file_writer_unittest.cc',
|
||||
],
|
||||
},
|
||||
], #targets
|
||||
|
Loading…
Reference in New Issue
Block a user