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:
henrik.lundin@webrtc.org 2014-12-01 11:25:04 +00:00
parent 4796301c0e
commit 83317146ba
8 changed files with 248 additions and 59 deletions

View File

@ -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',

View File

@ -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);
webrtc::test::RtpPacket packet;
while (input->NextPacket(&packet))
CHECK(output->WritePacket(&packet));
}
while (pack_len >= 0) {
packet.writeToFile(out_file);
pack_len = packet.readFromFile(in_file);
}
fclose(in_file);
}
fclose(out_file);
return 0;
}

View File

@ -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;

View 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

View 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_

View 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

View File

@ -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',

View File

@ -157,6 +157,7 @@
'sources': [
'fake_network_pipe_unittest.cc',
'rtp_file_reader_unittest.cc',
'rtp_file_writer_unittest.cc',
],
},
], #targets