diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 10a1860021..b8aa55b18b 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -242,10 +242,6 @@ 'video_coding/main/source/qm_select_unittest.cc', 'video_coding/main/source/test/stream_generator.cc', 'video_coding/main/source/test/stream_generator.h', - 'video_coding/main/test/pcap_file_reader.cc', - 'video_coding/main/test/pcap_file_reader_unittest.cc', - 'video_coding/main/test/rtp_file_reader.cc', - 'video_coding/main/test/rtp_file_reader_unittest.cc', 'video_processing/main/test/unit_test/brightness_detection_test.cc', 'video_processing/main/test/unit_test/color_enhancement_test.cc', 'video_processing/main/test/unit_test/content_metrics_test.cc', diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi index c2f1b3da47..f290a34c53 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi @@ -56,8 +56,8 @@ }, 'sources': [ 'tools/rtp_to_text.cc', - '<(webrtc_root)/modules/video_coding/main/test/rtp_file_reader.cc', - '<(webrtc_root)/modules/video_coding/main/test/rtp_file_reader.h', + '<(webrtc_root)/test/rtp_file_reader.cc', + '<(webrtc_root)/test/rtp_file_reader.h', ], # source }, { @@ -79,8 +79,8 @@ }, 'sources': [ 'tools/bwe_rtp_play.cc', - '<(webrtc_root)/modules/video_coding/main/test/rtp_file_reader.cc', - '<(webrtc_root)/modules/video_coding/main/test/rtp_file_reader.h', + '<(webrtc_root)/test/rtp_file_reader.cc', + '<(webrtc_root)/test/rtp_file_reader.h', ], # source }, ], # targets diff --git a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc index 40fa6df8ff..e71c75ce39 100644 --- a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc +++ b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc @@ -16,10 +16,7 @@ #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" -#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h" -#include "webrtc/modules/video_coding/main/test/rtp_player.h" - -using webrtc::rtpplayer::RtpPacketSourceInterface; +#include "webrtc/test/rtp_file_reader.h" const int kMinBitrateBps = 30000; @@ -27,11 +24,12 @@ bool ParseArgsAndSetupEstimator(int argc, char** argv, webrtc::Clock* clock, webrtc::RemoteBitrateObserver* observer, - RtpPacketSourceInterface** rtp_reader, + webrtc::test::RtpFileReader** rtp_reader, webrtc::RtpHeaderParser** parser, webrtc::RemoteBitrateEstimator** estimator, std::string* estimator_used) { - *rtp_reader = webrtc::rtpplayer::CreateRtpFileReader(argv[3]); + *rtp_reader = webrtc::test::RtpFileReader::Create( + webrtc::test::RtpFileReader::kRtpDump, argv[3]); if (!*rtp_reader) { fprintf(stderr, "Cannot open input file %s\n", argv[3]); return false; diff --git a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h index 714457d566..2d12a8083f 100644 --- a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h +++ b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h @@ -18,8 +18,8 @@ class Clock; class RemoteBitrateEstimator; class RemoteBitrateObserver; class RtpHeaderParser; -namespace rtpplayer { -class RtpPacketSourceInterface; +namespace test { +class RtpFileReader; } } @@ -28,7 +28,7 @@ bool ParseArgsAndSetupEstimator( char** argv, webrtc::Clock* clock, webrtc::RemoteBitrateObserver* observer, - webrtc::rtpplayer::RtpPacketSourceInterface** rtp_reader, + webrtc::test::RtpFileReader** rtp_reader, webrtc::RtpHeaderParser** parser, webrtc::RemoteBitrateEstimator** estimator, std::string* estimator_used); diff --git a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp_play.cc b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp_play.cc index 9ea3f08eab..eb224f2e4a 100644 --- a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp_play.cc +++ b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp_play.cc @@ -14,11 +14,8 @@ #include "webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" -#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h" -#include "webrtc/modules/video_coding/main/test/rtp_player.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" - -using webrtc::rtpplayer::RtpPacketSourceInterface; +#include "webrtc/test/rtp_file_reader.h" class Observer : public webrtc::RemoteBitrateObserver { public: @@ -49,7 +46,7 @@ int main(int argc, char** argv) { " is the id associated with the extension.\n"); return -1; } - RtpPacketSourceInterface* reader; + webrtc::test::RtpFileReader* reader; webrtc::RemoteBitrateEstimator* estimator; webrtc::RtpHeaderParser* parser; std::string estimator_used; @@ -59,7 +56,7 @@ int main(int argc, char** argv) { &parser, &estimator, &estimator_used)) { return -1; } - webrtc::scoped_ptr rtp_reader(reader); + webrtc::scoped_ptr rtp_reader(reader); webrtc::scoped_ptr rtp_parser(parser); webrtc::scoped_ptr rbe(estimator); @@ -68,30 +65,25 @@ int main(int argc, char** argv) { int64_t next_process_time_ms = 0; int64_t next_rtp_time_ms = 0; int64_t first_rtp_time_ms = -1; - const uint32_t kMaxPacketSize = 1500; - uint8_t packet_buffer[kMaxPacketSize]; - uint8_t* packet = packet_buffer; int non_zero_abs_send_time = 0; int non_zero_ts_offsets = 0; while (true) { - uint32_t next_rtp_time; if (next_rtp_time_ms <= clock.TimeInMilliseconds()) { - uint32_t packet_length = kMaxPacketSize; - if (rtp_reader->NextPacket(packet, &packet_length, - &next_rtp_time) == -1) { + webrtc::test::RtpFileReader::Packet packet; + if (!rtp_reader->NextPacket(&packet)) { break; } if (first_rtp_time_ms == -1) - first_rtp_time_ms = next_rtp_time; - next_rtp_time_ms = next_rtp_time - first_rtp_time_ms; + first_rtp_time_ms = packet.time_ms; + packet.time_ms = packet.time_ms - first_rtp_time_ms; webrtc::RTPHeader header; - parser->Parse(packet, packet_length, &header); + parser->Parse(packet.data, packet.length, &header); if (header.extension.absoluteSendTime != 0) ++non_zero_abs_send_time; if (header.extension.transmissionTimeOffset != 0) ++non_zero_ts_offsets; rbe->IncomingPacket(clock.TimeInMilliseconds(), - packet_length - header.headerLength, + static_cast(packet.length - header.headerLength), header); ++packet_counter; } diff --git a/webrtc/modules/remote_bitrate_estimator/tools/rtp_to_text.cc b/webrtc/modules/remote_bitrate_estimator/tools/rtp_to_text.cc index af4a4d4ee7..a85bca4f64 100644 --- a/webrtc/modules/remote_bitrate_estimator/tools/rtp_to_text.cc +++ b/webrtc/modules/remote_bitrate_estimator/tools/rtp_to_text.cc @@ -14,11 +14,8 @@ #include "webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" -#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h" -#include "webrtc/modules/video_coding/main/test/rtp_player.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" - -using webrtc::rtpplayer::RtpPacketSourceInterface; +#include "webrtc/test/rtp_file_reader.h" int main(int argc, char** argv) { if (argc < 4) { @@ -32,43 +29,44 @@ int main(int argc, char** argv) { " output.\n"); return -1; } - RtpPacketSourceInterface* reader; + webrtc::test::RtpFileReader* reader; webrtc::RtpHeaderParser* parser; if (!ParseArgsAndSetupEstimator(argc, argv, NULL, NULL, &reader, &parser, NULL, NULL)) { return -1; } bool arrival_time_only = (argc >= 5 && strncmp(argv[4], "-t", 2) == 0); - webrtc::scoped_ptr rtp_reader(reader); + webrtc::scoped_ptr rtp_reader(reader); webrtc::scoped_ptr rtp_parser(parser); fprintf(stdout, "seqnum timestamp ts_offset abs_sendtime recvtime " "markerbit ssrc size\n"); int packet_counter = 0; - static const uint32_t kMaxPacketSize = 1500; - uint8_t packet_buffer[kMaxPacketSize]; - uint8_t* packet = packet_buffer; - uint32_t packet_length = kMaxPacketSize; - uint32_t time_ms = 0; int non_zero_abs_send_time = 0; int non_zero_ts_offsets = 0; - while (rtp_reader->NextPacket(packet, &packet_length, &time_ms) == 0) { + webrtc::test::RtpFileReader::Packet packet; + while (rtp_reader->NextPacket(&packet)) { webrtc::RTPHeader header; - parser->Parse(packet, packet_length, &header); + parser->Parse(packet.data, packet.length, &header); if (header.extension.absoluteSendTime != 0) ++non_zero_abs_send_time; if (header.extension.transmissionTimeOffset != 0) ++non_zero_ts_offsets; if (arrival_time_only) { std::stringstream ss; - ss << static_cast(time_ms) * 1000000; + ss << static_cast(packet.time_ms) * 1000000; fprintf(stdout, "%s\n", ss.str().c_str()); } else { - fprintf(stdout, "%u %u %d %u %u %d %u %u\n", header.sequenceNumber, - header.timestamp, header.extension.transmissionTimeOffset, - header.extension.absoluteSendTime, time_ms, header.markerBit, - header.ssrc, packet_length); + fprintf(stdout, + "%u %u %d %u %u %d %u %d\n", + header.sequenceNumber, + header.timestamp, + header.extension.transmissionTimeOffset, + header.extension.absoluteSendTime, + packet.time_ms, + header.markerBit, + header.ssrc, + static_cast(packet.length)); } - packet_length = kMaxPacketSize; ++packet_counter; } fprintf(stderr, "Parsed %d packets\n", packet_counter); diff --git a/webrtc/modules/video_coding/main/source/video_coding_test.gypi b/webrtc/modules/video_coding/main/source/video_coding_test.gypi index b0fe510cf9..576524d13e 100644 --- a/webrtc/modules/video_coding/main/source/video_coding_test.gypi +++ b/webrtc/modules/video_coding/main/source/video_coding_test.gypi @@ -21,6 +21,7 @@ '<(webrtc_root)/test/metrics.gyp:metrics', '<(webrtc_root)/common_video/common_video.gyp:common_video', '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default', + '<(webrtc_root)/test/webrtc_test_common.gyp:webrtc_test_common', ], 'sources': [ # headers @@ -30,11 +31,9 @@ '../test/media_opt_test.h', '../test/mt_test_common.h', '../test/normal_test.h', - '../test/pcap_file_reader.h', '../test/quality_modes_test.h', '../test/receiver_tests.h', '../test/release_test.h', - '../test/rtp_file_reader.h', '../test/rtp_player.h', '../test/test_callbacks.h', '../test/test_util.h', @@ -48,9 +47,7 @@ '../test/mt_test_common.cc', '../test/mt_rx_tx_test.cc', '../test/normal_test.cc', - '../test/pcap_file_reader.cc', '../test/quality_modes_test.cc', - '../test/rtp_file_reader.cc', '../test/rtp_player.cc', '../test/test_callbacks.cc', '../test/test_util.cc', diff --git a/webrtc/modules/video_coding/main/test/pcap_file_reader.h b/webrtc/modules/video_coding/main/test/pcap_file_reader.h deleted file mode 100644 index 6450e2d64a..0000000000 --- a/webrtc/modules/video_coding/main/test/pcap_file_reader.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013 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_MODULES_VIDEO_CODING_TEST_PCAP_FILE_READER_H_ -#define WEBRTC_MODULES_VIDEO_CODING_TEST_PCAP_FILE_READER_H_ - -#include - -namespace webrtc { -namespace rtpplayer { - -class RtpPacketSourceInterface; - -RtpPacketSourceInterface* CreatePcapFileReader(const std::string& filename); - -} // namespace rtpplayer -} // namespace webrtc - -#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_PCAP_FILE_READER_H_ diff --git a/webrtc/modules/video_coding/main/test/rtp_file_reader.cc b/webrtc/modules/video_coding/main/test/rtp_file_reader.cc deleted file mode 100644 index 447eb9bea9..0000000000 --- a/webrtc/modules/video_coding/main/test/rtp_file_reader.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2013 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/modules/video_coding/main/test/rtp_file_reader.h" - -#ifdef WIN32 -#include -#include -#else -#include -#endif -#include -#include - -#include "webrtc/modules/video_coding/main/test/rtp_player.h" -#include "webrtc/system_wrappers/interface/scoped_ptr.h" - -namespace webrtc { -namespace rtpplayer { - -enum { - kResultFail = -1, - kResultSuccess = 0, - - kFirstLineLength = 40, // More than needed to read the ID line. - kPacketHeaderSize = 8 // Rtpplay packet header size in bytes. -}; - -#if 1 -# define DEBUG_LOG(text) -# define DEBUG_LOG1(text, arg) -#else -# define DEBUG_LOG(text) (printf(text "\n")) -# define DEBUG_LOG1(text, arg) (printf(text "\n", arg)) -#endif - -#define TRY(expr) \ - do { \ - if ((expr) < 0) { \ - DEBUG_LOG1("FAIL at " __FILE__ ":%d", __LINE__); \ - return kResultFail; \ - } \ - } while (0) - -// Read RTP packets from file in rtpdump format, as documented at: -// http://www.cs.columbia.edu/irt/software/rtptools/ -class RtpFileReaderImpl : public RtpPacketSourceInterface { - public: - RtpFileReaderImpl() : file_(NULL) {} - virtual ~RtpFileReaderImpl() { - if (file_ != NULL) { - fclose(file_); - file_ = NULL; - } - } - - int Initialize(const std::string& filename) { - file_ = fopen(filename.c_str(), "rb"); - if (file_ == NULL) { - printf("ERROR: Can't open file: %s\n", filename.c_str()); - return kResultFail; - } - - char firstline[kFirstLineLength + 1] = {0}; - if (fgets(firstline, kFirstLineLength, file_) == NULL) { - DEBUG_LOG("ERROR: Can't read from file\n"); - return kResultFail; - } - if (strncmp(firstline, "#!rtpplay", 9) == 0) { - if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) { - DEBUG_LOG("ERROR: wrong rtpplay version, must be 1.0\n"); - return kResultFail; - } - } else if (strncmp(firstline, "#!RTPencode", 11) == 0) { - if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) { - DEBUG_LOG("ERROR: wrong RTPencode version, must be 1.0\n"); - return kResultFail; - } - } else { - DEBUG_LOG("ERROR: wrong file format of input file\n"); - return kResultFail; - } - - uint32_t start_sec; - uint32_t start_usec; - 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)); - - return kResultSuccess; - } - - virtual int NextPacket(uint8_t* rtp_data, uint32_t* length, - uint32_t* time_ms) { - assert(rtp_data); - assert(length); - assert(time_ms); - - uint16_t len; - uint16_t plen; - uint32_t offset; - TRY(Read(&len)); - TRY(Read(&plen)); - TRY(Read(&offset)); - - // Use 'len' here because a 'plen' of 0 specifies rtcp. - len -= kPacketHeaderSize; - if (*length < len) { - return kResultFail; - } - if (fread(rtp_data, 1, len, file_) != len) { - return kResultFail; - } - - *length = len; - *time_ms = offset; - return kResultSuccess; - } - - private: - int Read(uint32_t* out) { - assert(out); - uint32_t tmp = 0; - if (fread(&tmp, 1, sizeof(uint32_t), file_) != sizeof(uint32_t)) { - return kResultFail; - } - *out = ntohl(tmp); - return kResultSuccess; - } - - int Read(uint16_t* out) { - assert(out); - uint16_t tmp = 0; - if (fread(&tmp, 1, sizeof(uint16_t), file_) != sizeof(uint16_t)) { - return kResultFail; - } - *out = ntohs(tmp); - return kResultSuccess; - } - - FILE* file_; - - DISALLOW_COPY_AND_ASSIGN(RtpFileReaderImpl); -}; - -RtpPacketSourceInterface* CreateRtpFileReader(const std::string& filename) { - scoped_ptr impl(new RtpFileReaderImpl()); - if (impl->Initialize(filename) != 0) { - return NULL; - } - return impl.release(); -} -} // namespace rtpplayer -} // namespace webrtc diff --git a/webrtc/modules/video_coding/main/test/rtp_file_reader.h b/webrtc/modules/video_coding/main/test/rtp_file_reader.h deleted file mode 100644 index b763ee7513..0000000000 --- a/webrtc/modules/video_coding/main/test/rtp_file_reader.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013 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_MODULES_VIDEO_CODING_MAIN_TEST_RTP_FILE_READER_H_ -#define WEBRTC_MODULES_VIDEO_CODING_MAIN_TEST_RTP_FILE_READER_H_ - -#include - -namespace webrtc { -namespace rtpplayer { - -class RtpPacketSourceInterface; - -RtpPacketSourceInterface* CreateRtpFileReader(const std::string& filename); - -} // namespace rtpplayer -} // namespace webrtc - -#endif // WEBRTC_MODULES_VIDEO_CODING_MAIN_TEST_RTP_FILE_READER_H_ diff --git a/webrtc/modules/video_coding/main/test/rtp_file_reader_unittest.cc b/webrtc/modules/video_coding/main/test/rtp_file_reader_unittest.cc deleted file mode 100644 index 7e0e607cae..0000000000 --- a/webrtc/modules/video_coding/main/test/rtp_file_reader_unittest.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2013 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 "testing/gtest/include/gtest/gtest.h" -#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" -#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h" -#include "webrtc/modules/video_coding/main/test/rtp_player.h" -#include "webrtc/system_wrappers/interface/scoped_ptr.h" -#include "webrtc/test/testsupport/fileutils.h" - -namespace webrtc { -namespace rtpplayer { - -class TestRtpFileReader : public ::testing::Test { - public: - void Init(const std::string& filename) { - std::string filepath = - test::ResourcePath("video_coding/" + filename, "rtp"); - rtp_packet_source_.reset(CreateRtpFileReader(filepath)); - ASSERT_TRUE(rtp_packet_source_.get() != NULL); - } - - int CountRtpPackets() { - const uint32_t kBufferSize = 4096; - uint8_t data[kBufferSize]; - uint32_t length = kBufferSize; - uint32_t dummy_time_ms = 0; - int c = 0; - while (rtp_packet_source_->NextPacket(data, &length, &dummy_time_ms) == 0) { - EXPECT_GE(kBufferSize, length); - length = kBufferSize; - c++; - } - return c; - } - - private: - scoped_ptr rtp_packet_source_; -}; - -TEST_F(TestRtpFileReader, Test60Packets) { - Init("pltype103"); - EXPECT_EQ(60, CountRtpPackets()); -} - -} // namespace rtpplayer -} // namespace webrtc diff --git a/webrtc/modules/video_coding/main/test/rtp_player.cc b/webrtc/modules/video_coding/main/test/rtp_player.cc index f02aebba5e..8c8c56ebe3 100644 --- a/webrtc/modules/video_coding/main/test/rtp_player.cc +++ b/webrtc/modules/video_coding/main/test/rtp_player.cc @@ -19,12 +19,11 @@ #include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" #include "webrtc/modules/video_coding/main/source/internal_defines.h" -#include "webrtc/modules/video_coding/main/test/pcap_file_reader.h" -#include "webrtc/modules/video_coding/main/test/rtp_file_reader.h" #include "webrtc/modules/video_coding/main/test/test_util.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/test/rtp_file_reader.h" #if 1 # define DEBUG_LOG1(text, arg) @@ -323,7 +322,7 @@ class RtpPlayerImpl : public RtpPlayerInterface { public: RtpPlayerImpl(PayloadSinkFactoryInterface* payload_sink_factory, const PayloadTypes& payload_types, Clock* clock, - scoped_ptr* packet_source, + scoped_ptr* packet_source, float loss_rate, uint32_t rtt_ms, bool reordering) : ssrc_handlers_(payload_sink_factory, payload_types), clock_(clock), @@ -337,9 +336,7 @@ class RtpPlayerImpl : public RtpPlayerInterface { no_loss_startup_(100), end_of_file_(false), reordering_(false), - reorder_buffer_(), - next_packet_(), - next_packet_length_(0) { + reorder_buffer_() { assert(clock); assert(packet_source); assert(packet_source->get()); @@ -368,22 +365,23 @@ class RtpPlayerImpl : public RtpPlayerInterface { // Send any packets from packet source. if (!end_of_file_ && (TimeUntilNextPacket() == 0 || first_packet_)) { if (first_packet_) { - next_packet_length_ = sizeof(next_packet_); - if (packet_source_->NextPacket(next_packet_, &next_packet_length_, - &next_rtp_time_) != 0) { + if (!packet_source_->NextPacket(&next_packet_)) return 0; - } - first_packet_rtp_time_ = next_rtp_time_; + first_packet_rtp_time_ = next_packet_.time_ms; first_packet_time_ms_ = clock_->TimeInMilliseconds(); first_packet_ = false; } if (reordering_ && reorder_buffer_.get() == NULL) { - reorder_buffer_.reset(new RawRtpPacket(next_packet_, - next_packet_length_, 0, 0)); + reorder_buffer_.reset( + new RawRtpPacket(next_packet_.data, + static_cast(next_packet_.length), + 0, + 0)); return 0; } - int ret = SendPacket(next_packet_, next_packet_length_); + int ret = SendPacket(next_packet_.data, + static_cast(next_packet_.length)); if (reorder_buffer_.get()) { SendPacket(reorder_buffer_->data(), reorder_buffer_->length()); reorder_buffer_.reset(NULL); @@ -392,13 +390,11 @@ class RtpPlayerImpl : public RtpPlayerInterface { return ret; } - next_packet_length_ = sizeof(next_packet_); - if (packet_source_->NextPacket(next_packet_, &next_packet_length_, - &next_rtp_time_) != 0) { + if (!packet_source_->NextPacket(&next_packet_)) { end_of_file_ = true; return 0; } - else if (next_packet_length_ == 0) { + else if (next_packet_.length == 0) { return 0; } } @@ -456,7 +452,8 @@ class RtpPlayerImpl : public RtpPlayerInterface { SsrcHandlers ssrc_handlers_; Clock* clock_; - scoped_ptr packet_source_; + scoped_ptr packet_source_; + test::RtpFileReader::Packet next_packet_; uint32_t next_rtp_time_; bool first_packet_; int64_t first_packet_rtp_time_; @@ -468,8 +465,6 @@ class RtpPlayerImpl : public RtpPlayerInterface { bool end_of_file_; bool reordering_; scoped_ptr reorder_buffer_; - uint8_t next_packet_[kMaxPacketBufferSize]; - uint32_t next_packet_length_; DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPlayerImpl); }; @@ -478,10 +473,11 @@ RtpPlayerInterface* Create(const std::string& input_filename, PayloadSinkFactoryInterface* payload_sink_factory, Clock* clock, const PayloadTypes& payload_types, float loss_rate, uint32_t rtt_ms, bool reordering) { - scoped_ptr packet_source( - CreateRtpFileReader(input_filename)); + scoped_ptr packet_source(test::RtpFileReader::Create( + test::RtpFileReader::kRtpDump, input_filename)); if (packet_source.get() == NULL) { - packet_source.reset(CreatePcapFileReader(input_filename)); + packet_source.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap, + input_filename)); if (packet_source.get() == NULL) { return NULL; } diff --git a/webrtc/modules/video_coding/main/test/rtp_player.h b/webrtc/modules/video_coding/main/test/rtp_player.h index 24e62b63c5..1703618a24 100644 --- a/webrtc/modules/video_coding/main/test/rtp_player.h +++ b/webrtc/modules/video_coding/main/test/rtp_player.h @@ -44,20 +44,6 @@ class PayloadCodecTuple { typedef std::vector PayloadTypes; typedef std::vector::const_iterator PayloadTypesIterator; -// Implemented by something that can provide RTP packets, for instance a file -// format parser such as the rtp_file_reader or the pcap_file_reader. -class RtpPacketSourceInterface { - public: - virtual ~RtpPacketSourceInterface() {} - - // Read next RTP packet into buffer pointed to by rtp_data. On call, 'length' - // field must be filled in with the size of the buffer. The actual size of - // the packet is available in 'length' upon returning. Time in milliseconds - // from start of stream is returned in 'time_ms'. - virtual int NextPacket(uint8_t* rtp_data, uint32_t* length, - uint32_t* time_ms) = 0; -}; - // Implemented by RtpPlayer and given to client as a means to retrieve // information about a specific RTP stream. class RtpStreamInterface { diff --git a/webrtc/modules/video_coding/main/test/pcap_file_reader.cc b/webrtc/test/rtp_file_reader.cc similarity index 64% rename from webrtc/modules/video_coding/main/test/pcap_file_reader.cc rename to webrtc/test/rtp_file_reader.cc index 68c856652d..be8dc2bc8f 100644 --- a/webrtc/modules/video_coding/main/test/pcap_file_reader.cc +++ b/webrtc/test/rtp_file_reader.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * 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 @@ -8,15 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/modules/video_coding/main/test/pcap_file_reader.h" +#include "webrtc/test/rtp_file_reader.h" -#ifdef WIN32 -#include -#include -#else -#include -#endif -#include #include #include @@ -24,11 +17,142 @@ #include #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" -#include "webrtc/modules/video_coding/main/test/rtp_player.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" namespace webrtc { -namespace rtpplayer { +namespace test { + +static const size_t kFirstLineLength = 40; +static uint16_t kPacketHeaderSize = 8; + +#if 1 +# define DEBUG_LOG(text) +# define DEBUG_LOG1(text, arg) +#else +# define DEBUG_LOG(text) (printf(text "\n")) +# define DEBUG_LOG1(text, arg) (printf(text "\n", arg)) +#endif + +#define TRY(expr) \ + do { \ + if (!(expr)) { \ + DEBUG_LOG1("FAIL at " __FILE__ ":%d", __LINE__); \ + return false; \ + } \ + } while (0) + +class RtpFileReaderImpl : public RtpFileReader { + public: + virtual bool Init(const std::string& filename) = 0; +}; + +// Read RTP packets from file in rtpdump format, as documented at: +// http://www.cs.columbia.edu/irt/software/rtptools/ +class RtpDumpReader : public RtpFileReaderImpl { + public: + RtpDumpReader() : file_(NULL) {} + virtual ~RtpDumpReader() { + if (file_ != NULL) { + fclose(file_); + file_ = NULL; + } + } + + bool Init(const std::string& filename) { + file_ = fopen(filename.c_str(), "rb"); + if (file_ == NULL) { + printf("ERROR: Can't open file: %s\n", filename.c_str()); + return false; + } + + char firstline[kFirstLineLength + 1] = {0}; + if (fgets(firstline, kFirstLineLength, file_) == NULL) { + DEBUG_LOG("ERROR: Can't read from file\n"); + return false; + } + if (strncmp(firstline, "#!rtpplay", 9) == 0) { + if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) { + DEBUG_LOG("ERROR: wrong rtpplay version, must be 1.0\n"); + return false; + } + } else if (strncmp(firstline, "#!RTPencode", 11) == 0) { + if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) { + DEBUG_LOG("ERROR: wrong RTPencode version, must be 1.0\n"); + return false; + } + } else { + DEBUG_LOG("ERROR: wrong file format of input file\n"); + return false; + } + + uint32_t start_sec; + uint32_t start_usec; + 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)); + + return true; + } + + virtual bool NextPacket(Packet* packet) OVERRIDE { + uint8_t* rtp_data = packet->data; + packet->length = Packet::kMaxPacketBufferSize; + + uint16_t len; + uint16_t plen; + uint32_t offset; + TRY(Read(&len)); + TRY(Read(&plen)); + TRY(Read(&offset)); + + // Use 'len' here because a 'plen' of 0 specifies rtcp. + len -= kPacketHeaderSize; + if (packet->length < len) { + return false; + } + if (fread(rtp_data, 1, len, file_) != len) { + return false; + } + + packet->length = len; + packet->time_ms = offset; + return true; + } + + private: + bool Read(uint32_t* out) { + *out = 0; + for (size_t i = 0; i < 4; ++i) { + *out <<= 8; + uint8_t tmp; + if (fread(&tmp, 1, sizeof(uint8_t), file_) != sizeof(uint8_t)) + return false; + *out |= tmp; + } + return true; + } + + bool Read(uint16_t* out) { + *out = 0; + for (size_t i = 0; i < 2; ++i) { + *out <<= 8; + uint8_t tmp; + if (fread(&tmp, 1, sizeof(uint8_t), file_) != sizeof(uint8_t)) + return false; + *out |= tmp; + } + return true; + } + + FILE* file_; + + DISALLOW_COPY_AND_ASSIGN(RtpDumpReader); +}; enum { kResultFail = -1, @@ -56,50 +180,46 @@ enum { const uint32_t kPcapBOMSwapOrder = 0xd4c3b2a1UL; const uint32_t kPcapBOMNoSwapOrder = 0xa1b2c3d4UL; -#if 1 -# define DEBUG_LOG(text) -# define DEBUG_LOG1(text, arg) -#else -# define DEBUG_LOG(text) (printf(text "\n")) -# define DEBUG_LOG1(text, arg) (printf(text "\n", arg)) -#endif - -#define TRY(expr) \ - do { \ - int r = (expr); \ - if (r == kResultFail) { \ - DEBUG_LOG1("FAIL at " __FILE__ ":%d", __LINE__); \ - return kResultFail; \ - } else if (r == kResultSkip) { \ - return kResultSkip; \ - } \ +#define TRY_PCAP(expr) \ + do { \ + int r = (expr); \ + if (r == kResultFail) { \ + DEBUG_LOG1("FAIL at " __FILE__ ":%d", __LINE__); \ + return kResultFail; \ + } else if (r == kResultSkip) { \ + return kResultSkip; \ + } \ } while (0) // Read RTP packets from file in tcpdump/libpcap format, as documented at: // http://wiki.wireshark.org/Development/LibpcapFileFormat -class PcapFileReaderImpl : public RtpPacketSourceInterface { +class PcapReader : public RtpFileReaderImpl { public: - PcapFileReaderImpl() + PcapReader() : file_(NULL), swap_pcap_byte_order_(false), +#ifdef WEBRTC_ARCH_BIG_ENDIAN swap_network_byte_order_(false), +#else + swap_network_byte_order_(true), +#endif read_buffer_(), packets_by_ssrc_(), packets_(), next_packet_it_() { - int16_t test = 0x7f00; - if (test != htons(test)) { - swap_network_byte_order_ = true; - } } - virtual ~PcapFileReaderImpl() { + virtual ~PcapReader() { if (file_ != NULL) { fclose(file_); file_ = NULL; } } + bool Init(const std::string& filename) OVERRIDE { + return Initialize(filename) == kResultSuccess; + } + int Initialize(const std::string& filename) { file_ = fopen(filename.c_str(), "rb"); if (file_ == NULL) { @@ -115,7 +235,7 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { uint32_t stream_start_ms = 0; int32_t next_packet_pos = ftell(file_); for (;;) { - TRY(fseek(file_, next_packet_pos, SEEK_SET)); + TRY_PCAP(fseek(file_, next_packet_pos, SEEK_SET)); int result = ReadPacket(&next_packet_pos, stream_start_ms, ++total_packet_count); if (result == kResultFail) { @@ -165,7 +285,15 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { return kResultSuccess; } - virtual int NextPacket(uint8_t* data, uint32_t* length, uint32_t* time_ms) { + virtual bool NextPacket(Packet* packet) OVERRIDE { + uint32_t length = Packet::kMaxPacketBufferSize; + if (NextPcap(packet->data, &length, &packet->time_ms) != kResultSuccess) + return false; + packet->length = static_cast(length); + return true; + } + + virtual int NextPcap(uint8_t* data, uint32_t* length, uint32_t* time_ms) { assert(data); assert(length); assert(time_ms); @@ -176,8 +304,8 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { if (*length < next_packet_it_->payload_length) { return -1; } - TRY(fseek(file_, next_packet_it_->pos_in_file, SEEK_SET)); - TRY(Read(data, next_packet_it_->payload_length)); + TRY_PCAP(fseek(file_, next_packet_it_->pos_in_file, SEEK_SET)); + TRY_PCAP(Read(data, next_packet_it_->payload_length)); *length = next_packet_it_->payload_length; *time_ms = next_packet_it_->time_offset_ms; next_packet_it_++; @@ -205,7 +333,7 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { int ReadGlobalHeader() { uint32_t magic; - TRY(Read(&magic, false)); + TRY_PCAP(Read(&magic, false)); if (magic == kPcapBOMSwapOrder) { swap_pcap_byte_order_ = true; } else if (magic == kPcapBOMNoSwapOrder) { @@ -216,8 +344,8 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { uint16_t version_major; uint16_t version_minor; - TRY(Read(&version_major, false)); - TRY(Read(&version_minor, false)); + TRY_PCAP(Read(&version_major, false)); + TRY_PCAP(Read(&version_minor, false)); if (version_major != kPcapVersionMajor || version_minor != kPcapVersionMinor) { return kResultFail; @@ -227,10 +355,10 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { uint32_t sigfigs; // Accuracy of timestamps. uint32_t snaplen; // Max length of captured packets, in octets. uint32_t network; // Data link type. - TRY(Read(&this_zone, false)); - TRY(Read(&sigfigs, false)); - TRY(Read(&snaplen, false)); - TRY(Read(&network, false)); + TRY_PCAP(Read(&this_zone, false)); + TRY_PCAP(Read(&sigfigs, false)); + TRY_PCAP(Read(&snaplen, false)); + TRY_PCAP(Read(&network, false)); // Accept only LINKTYPE_NULL and LINKTYPE_ETHERNET. // See: http://www.tcpdump.org/linktypes.html @@ -249,24 +377,24 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { uint32_t ts_usec; // Timestamp microseconds. uint32_t incl_len; // Number of octets of packet saved in file. uint32_t orig_len; // Actual length of packet. - TRY(Read(&ts_sec, false)); - TRY(Read(&ts_usec, false)); - TRY(Read(&incl_len, false)); - TRY(Read(&orig_len, false)); + TRY_PCAP(Read(&ts_sec, false)); + TRY_PCAP(Read(&ts_usec, false)); + TRY_PCAP(Read(&incl_len, false)); + TRY_PCAP(Read(&orig_len, false)); *next_packet_pos = ftell(file_) + incl_len; RtpPacketMarker marker = {0}; marker.packet_number = number; marker.time_offset_ms = CalcTimeDelta(ts_sec, ts_usec, stream_start_ms); - TRY(ReadPacketHeader(&marker)); + TRY_PCAP(ReadPacketHeader(&marker)); marker.pos_in_file = ftell(file_); if (marker.payload_length > sizeof(read_buffer_)) { printf("Packet too large!\n"); return kResultFail; } - TRY(Read(read_buffer_, marker.payload_length)); + TRY_PCAP(Read(read_buffer_, marker.payload_length)); RtpUtility::RtpHeaderParser rtp_parser(read_buffer_, marker.payload_length); if (rtp_parser.RTCP()) { @@ -294,7 +422,7 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { // the header as such and will likely fail reading the IP header if this is // something else than null/loopback. uint32_t protocol; - TRY(Read(&protocol, true)); + TRY_PCAP(Read(&protocol, true)); if (protocol == kBsdNullLoopback1 || protocol == kBsdNullLoopback2) { int result = ReadXxpIpHeader(marker); DEBUG_LOG("Recognized loopback frame"); @@ -303,12 +431,12 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { } } - TRY(fseek(file_, file_pos, SEEK_SET)); + TRY_PCAP(fseek(file_, file_pos, SEEK_SET)); // Check for Ethernet II, IP frame header. uint16_t type; - TRY(Skip(kEthernetIIHeaderMacSkip)); // Source+destination MAC. - TRY(Read(&type, true)); + TRY_PCAP(Skip(kEthernetIIHeaderMacSkip)); // Source+destination MAC. + TRY_PCAP(Read(&type, true)); if (type == kEthertypeIp) { int result = ReadXxpIpHeader(marker); DEBUG_LOG("Recognized ethernet 2 frame"); @@ -341,14 +469,14 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { uint16_t fragment; uint16_t protocol; uint16_t checksum; - TRY(Read(&version, true)); - TRY(Read(&length, true)); - TRY(Read(&id, true)); - TRY(Read(&fragment, true)); - TRY(Read(&protocol, true)); - TRY(Read(&checksum, true)); - TRY(Read(&marker->source_ip, true)); - TRY(Read(&marker->dest_ip, true)); + TRY_PCAP(Read(&version, true)); + TRY_PCAP(Read(&length, true)); + TRY_PCAP(Read(&id, true)); + TRY_PCAP(Read(&fragment, true)); + TRY_PCAP(Read(&protocol, true)); + TRY_PCAP(Read(&checksum, true)); + TRY_PCAP(Read(&marker->source_ip, true)); + TRY_PCAP(Read(&marker->dest_ip, true)); if (((version >> 12) & 0x000f) != kIpVersion4) { DEBUG_LOG("IP header is not IPv4"); @@ -364,7 +492,7 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { // Skip remaining fields of IP header. uint16_t header_length = (version & 0x0f00) >> (8 - 2); assert(header_length >= kMinIpHeaderLength); - TRY(Skip(header_length - kMinIpHeaderLength)); + TRY_PCAP(Skip(header_length - kMinIpHeaderLength)); protocol = protocol & 0x00ff; if (protocol == kProtocolTcp) { @@ -373,10 +501,10 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { } else if (protocol == kProtocolUdp) { uint16_t length; uint16_t checksum; - TRY(Read(&marker->source_port, true)); - TRY(Read(&marker->dest_port, true)); - TRY(Read(&length, true)); - TRY(Read(&checksum, true)); + TRY_PCAP(Read(&marker->source_port, true)); + TRY_PCAP(Read(&marker->dest_port, true)); + TRY_PCAP(Read(&length, true)); + TRY_PCAP(Read(&checksum, true)); marker->payload_length = length - kUdpHeaderLength; } else { DEBUG_LOG("Unknown transport (expected UDP or TCP)"); @@ -443,22 +571,33 @@ class PcapFileReaderImpl : public RtpPacketSourceInterface { FILE* file_; bool swap_pcap_byte_order_; - bool swap_network_byte_order_; + const bool swap_network_byte_order_; uint8_t read_buffer_[kMaxReadBufferSize]; SsrcMap packets_by_ssrc_; std::vector packets_; PacketIterator next_packet_it_; - DISALLOW_COPY_AND_ASSIGN(PcapFileReaderImpl); + DISALLOW_COPY_AND_ASSIGN(PcapReader); }; -RtpPacketSourceInterface* CreatePcapFileReader(const std::string& filename) { - scoped_ptr impl(new PcapFileReaderImpl()); - if (impl->Initialize(filename) != 0) { +RtpFileReader* RtpFileReader::Create(FileFormat format, + const std::string& filename) { + RtpFileReaderImpl* reader = NULL; + switch (format) { + case kPcap: + reader = new PcapReader(); + break; + case kRtpDump: + reader = new RtpDumpReader(); + break; + } + if (!reader->Init(filename)) { + delete reader; return NULL; } - return impl.release(); + return reader; } -} // namespace rtpplayer + +} // namespace test } // namespace webrtc diff --git a/webrtc/test/rtp_file_reader.h b/webrtc/test/rtp_file_reader.h new file mode 100644 index 0000000000..379bf2d7a5 --- /dev/null +++ b/webrtc/test/rtp_file_reader.h @@ -0,0 +1,42 @@ +/* + * 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_READER_H_ +#define WEBRTC_TEST_RTP_FILE_READER_H_ + +#include + +#include "webrtc/common_types.h" + +namespace webrtc { +namespace test { +class RtpFileReader { + public: + enum FileFormat { + kPcap, + kRtpDump, + }; + + struct Packet { + static const size_t kMaxPacketBufferSize = 1500; + uint8_t data[kMaxPacketBufferSize]; + size_t length; + + uint32_t time_ms; + }; + + virtual ~RtpFileReader() {} + static RtpFileReader* Create(FileFormat format, + const std::string& filename); + + virtual bool NextPacket(Packet* packet) = 0; +}; +} // namespace test +} // namespace webrtc +#endif // WEBRTC_TEST_RTP_FILE_READER_H_ diff --git a/webrtc/modules/video_coding/main/test/pcap_file_reader_unittest.cc b/webrtc/test/rtp_file_reader_unittest.cc similarity index 63% rename from webrtc/modules/video_coding/main/test/pcap_file_reader_unittest.cc rename to webrtc/test/rtp_file_reader_unittest.cc index c6f1d511c1..b5fa260c7d 100644 --- a/webrtc/modules/video_coding/main/test/pcap_file_reader_unittest.cc +++ b/webrtc/test/rtp_file_reader_unittest.cc @@ -12,13 +12,38 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" -#include "webrtc/modules/video_coding/main/test/pcap_file_reader.h" -#include "webrtc/modules/video_coding/main/test/rtp_player.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/test/rtp_file_reader.h" #include "webrtc/test/testsupport/fileutils.h" namespace webrtc { -namespace rtpplayer { + +class TestRtpFileReader : public ::testing::Test { + public: + void Init(const std::string& filename) { + std::string filepath = + test::ResourcePath("video_coding/" + filename, "rtp"); + rtp_packet_source_.reset( + test::RtpFileReader::Create(test::RtpFileReader::kRtpDump, filepath)); + ASSERT_TRUE(rtp_packet_source_.get() != NULL); + } + + int CountRtpPackets() { + test::RtpFileReader::Packet packet; + int c = 0; + while (rtp_packet_source_->NextPacket(&packet)) + c++; + return c; + } + + private: + scoped_ptr rtp_packet_source_; +}; + +TEST_F(TestRtpFileReader, Test60Packets) { + Init("pltype103"); + EXPECT_EQ(60, CountRtpPackets()); +} typedef std::map PacketsPerSsrc; @@ -27,35 +52,24 @@ class TestPcapFileReader : public ::testing::Test { void Init(const std::string& filename) { std::string filepath = test::ResourcePath("video_coding/" + filename, "pcap"); - rtp_packet_source_.reset(CreatePcapFileReader(filepath)); + rtp_packet_source_.reset( + test::RtpFileReader::Create(test::RtpFileReader::kPcap, filepath)); ASSERT_TRUE(rtp_packet_source_.get() != NULL); } int CountRtpPackets() { - const uint32_t kBufferSize = 4096; - uint8_t data[kBufferSize]; - uint32_t length = kBufferSize; - uint32_t dummy_time_ms = 0; int c = 0; - while (rtp_packet_source_->NextPacket(data, &length, &dummy_time_ms) == 0) { - EXPECT_GE(kBufferSize, length); - length = kBufferSize; + test::RtpFileReader::Packet packet; + while (rtp_packet_source_->NextPacket(&packet)) c++; - } return c; } PacketsPerSsrc CountRtpPacketsPerSsrc() { - const uint32_t kBufferSize = 4096; - uint8_t data[kBufferSize]; - uint32_t length = kBufferSize; - uint32_t dummy_time_ms = 0; PacketsPerSsrc pps; - while (rtp_packet_source_->NextPacket(data, &length, &dummy_time_ms) == 0) { - EXPECT_GE(kBufferSize, length); - length = kBufferSize; - - RtpUtility::RtpHeaderParser rtp_header_parser(data, length); + test::RtpFileReader::Packet packet; + while (rtp_packet_source_->NextPacket(&packet)) { + RtpUtility::RtpHeaderParser rtp_header_parser(packet.data, packet.length); webrtc::RTPHeader header; if (!rtp_header_parser.RTCP() && rtp_header_parser.Parse(header, NULL)) { pps[header.ssrc]++; @@ -65,7 +79,7 @@ class TestPcapFileReader : public ::testing::Test { } private: - scoped_ptr rtp_packet_source_; + scoped_ptr rtp_packet_source_; }; TEST_F(TestPcapFileReader, TestEthernetIIFrame) { @@ -94,6 +108,4 @@ TEST_F(TestPcapFileReader, TestThreeSsrc) { EXPECT_EQ(113, pps[0x59fe6ef0]); EXPECT_EQ(61, pps[0xed2bd2ac]); } - -} // namespace rtpplayer } // namespace webrtc diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp index 8c8774fba2..be6b303f87 100644 --- a/webrtc/test/webrtc_test_common.gyp +++ b/webrtc/test/webrtc_test_common.gyp @@ -35,6 +35,8 @@ 'mock_transport.h', 'null_transport.cc', 'null_transport.h', + 'rtp_file_reader.cc', + 'rtp_file_reader.h', 'rtp_rtcp_observer.h', 'run_loop.cc', 'run_loop.h', @@ -184,6 +186,7 @@ ], 'sources': [ 'fake_network_pipe_unittest.cc', + 'rtp_file_reader_unittest.cc', ], }, ], #targets diff --git a/webrtc/video/replay.cc b/webrtc/video/replay.cc new file mode 100644 index 0000000000..75390259a5 --- /dev/null +++ b/webrtc/video/replay.cc @@ -0,0 +1,266 @@ +/* + * 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 + +#include +#include + +#include "gflags/gflags.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "webrtc/call.h" +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" +#include "webrtc/system_wrappers/interface/clock.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/system_wrappers/interface/sleep.h" +#include "webrtc/test/encoder_settings.h" +#include "webrtc/test/null_transport.h" +#include "webrtc/test/rtp_file_reader.h" +#include "webrtc/test/run_loop.h" +#include "webrtc/test/run_test.h" +#include "webrtc/test/video_capturer.h" +#include "webrtc/test/video_renderer.h" +#include "webrtc/typedefs.h" + +namespace webrtc { +namespace flags { + +// TODO(pbos): Multiple receivers. + +// Flag for payload type. +static bool ValidatePayloadType(const char* flagname, int32_t payload_type) { + return payload_type > 0 && payload_type <= 127; +} +DEFINE_int32(payload_type, 0, "Payload type."); +static int PayloadType() { return static_cast(FLAGS_payload_type); } +static const bool payload_dummy = + google::RegisterFlagValidator(&FLAGS_payload_type, &ValidatePayloadType); + +// Flag for SSRC. +static bool ValidateSsrc(const char* flagname, uint64_t ssrc) { + return ssrc > 0 && ssrc <= 0xFFFFFFFFu; +} + +DEFINE_uint64(ssrc, 0, "Incoming SSRC."); +static uint32_t Ssrc() { return static_cast(FLAGS_ssrc); } +static const bool ssrc_dummy = + google::RegisterFlagValidator(&FLAGS_ssrc, &ValidateSsrc); + +static bool ValidateOptionalPayloadType(const char* flagname, + int32_t payload_type) { + return payload_type == -1 || ValidatePayloadType(flagname, payload_type); +} + +// Flag for RED payload type. +DEFINE_int32(red_payload_type, -1, "RED payload type."); +static int RedPayloadType() { + return static_cast(FLAGS_red_payload_type); +} +static const bool red_dummy = + google::RegisterFlagValidator(&FLAGS_red_payload_type, + &ValidateOptionalPayloadType); + +// Flag for ULPFEC payload type. +DEFINE_int32(fec_payload_type, -1, "ULPFEC payload type."); +static int FecPayloadType() { + return static_cast(FLAGS_fec_payload_type); +} +static const bool fec_dummy = + google::RegisterFlagValidator(&FLAGS_fec_payload_type, + &ValidateOptionalPayloadType); + +// Flag for abs-send-time id. +static bool ValidateRtpHeaderExtensionId(const char* flagname, + int32_t extension_id) { + return extension_id >= -1 || extension_id < 15; +} +DEFINE_int32(abs_send_time_id, -1, "RTP extension ID for abs-send-time."); +static int AbsSendTimeId() { return static_cast(FLAGS_abs_send_time_id); } +static const bool abs_send_time_dummy = + google::RegisterFlagValidator(&FLAGS_abs_send_time_id, + &ValidateRtpHeaderExtensionId); + +// Flag for transmission-offset id. +DEFINE_int32(transmission_offset_id, + -1, + "RTP extension ID for transmission-offset."); +static int TransmissionOffsetId() { + return static_cast(FLAGS_transmission_offset_id); +} +static const bool timestamp_offset_dummy = + google::RegisterFlagValidator(&FLAGS_transmission_offset_id, + &ValidateRtpHeaderExtensionId); + +// Flag for rtpdump input file. +DEFINE_string(input_file, "", "rtpdump input file."); +static std::string InputFile() { + return static_cast(FLAGS_input_file); +} + +// Flag for raw output files. +DEFINE_string(out_base, "", "Basename (excluding .yuv) for raw output."); +static std::string OutBase() { + return static_cast(FLAGS_out_base); +} + +// Flag for video codec. +DEFINE_string(codec, "VP8", "Video codec."); +static std::string Codec() { return static_cast(FLAGS_codec); } + +} // namespace flags + +static const uint32_t kReceiverLocalSsrc = 0x123456; + +class FileRenderPassthrough : public VideoRenderer { + public: + FileRenderPassthrough(const std::string& basename, VideoRenderer* renderer) + : basename_(basename), + renderer_(renderer), + file_(NULL), + count_(0), + last_width_(0), + last_height_(0) {} + + ~FileRenderPassthrough() { + if (file_ != NULL) + fclose(file_); + } + + private: + virtual void RenderFrame(const I420VideoFrame& video_frame, + int time_to_render_ms) OVERRIDE { + if (renderer_ != NULL) + renderer_->RenderFrame(video_frame, time_to_render_ms); + if (basename_ == "") + return; + if (last_width_ != video_frame.width() || + last_height_ != video_frame.height()) { + if (file_ != NULL) + fclose(file_); + std::stringstream filename; + filename << basename_; + if (++count_ > 1) + filename << '-' << count_; + filename << '_' << video_frame.width() << 'x' << video_frame.height() + << ".yuv"; + file_ = fopen(filename.str().c_str(), "wb"); + if (file_ == NULL) { + fprintf(stderr, + "Couldn't open file for writing: %s\n", + filename.str().c_str()); + } + } + last_width_ = video_frame.width(); + last_height_ = video_frame.height(); + if (file_ == NULL) + return; + PrintI420VideoFrame(video_frame, file_); + } + + const std::string basename_; + VideoRenderer* const renderer_; + FILE* file_; + size_t count_; + int last_width_; + int last_height_; +}; + +void RtpReplay() { + scoped_ptr playback_video(test::VideoRenderer::Create( + "Playback Video", 640, 480)); + FileRenderPassthrough file_passthrough(flags::OutBase(), + playback_video.get()); + + // TODO(pbos): Might be good to have a transport that prints keyframe requests + // etc. + test::NullTransport transport; + Call::Config call_config(&transport); + scoped_ptr call(Call::Create(call_config)); + + VideoReceiveStream::Config receive_config; + receive_config.rtp.remote_ssrc = flags::Ssrc(); + receive_config.rtp.local_ssrc = kReceiverLocalSsrc; + receive_config.rtp.fec.ulpfec_payload_type = flags::FecPayloadType(); + receive_config.rtp.fec.red_payload_type = flags::RedPayloadType(); + receive_config.rtp.nack.rtp_history_ms = 1000; + if (flags::TransmissionOffsetId() != -1) { + receive_config.rtp.extensions.push_back( + RtpExtension(RtpExtension::kTOffset, flags::TransmissionOffsetId())); + } + if (flags::AbsSendTimeId() != -1) { + receive_config.rtp.extensions.push_back( + RtpExtension(RtpExtension::kAbsSendTime, flags::AbsSendTimeId())); + } + receive_config.renderer = &file_passthrough; + + VideoSendStream::Config::EncoderSettings encoder_settings; + encoder_settings.payload_name = flags::Codec(); + encoder_settings.payload_type = flags::PayloadType(); + VideoCodec codec = test::CreateDecoderVideoCodec(encoder_settings); + receive_config.codecs.push_back(codec); + + VideoReceiveStream* receive_stream = + call->CreateVideoReceiveStream(receive_config); + + scoped_ptr rtp_reader(test::RtpFileReader::Create( + test::RtpFileReader::kRtpDump, flags::InputFile())); + if (rtp_reader.get() == NULL) { + rtp_reader.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap, + flags::InputFile())); + if (rtp_reader.get() == NULL) { + fprintf(stderr, + "Couldn't open input file as either a rtpdump or .pcap. Note " + "that .pcapng is not supported.\n"); + return; + } + } + receive_stream->Start(); + + uint32_t last_time_ms = 0; + int num_packets = 0; + while (true) { + test::RtpFileReader::Packet packet; + if (!rtp_reader->NextPacket(&packet)) + break; + ++num_packets; + switch (call->Receiver()->DeliverPacket(packet.data, packet.length)) { + case PacketReceiver::DELIVERY_OK: + break; + case PacketReceiver::DELIVERY_UNKNOWN_SSRC: { + RTPHeader header; + scoped_ptr parser(RtpHeaderParser::Create()); + parser->Parse(packet.data, packet.length, &header); + fprintf(stderr, "Unknown SSRC: %u!\n", header.ssrc); + break; + } + case PacketReceiver::DELIVERY_PACKET_ERROR: + fprintf(stderr, "Packet error, corrupt packets or incorrect setup?\n"); + break; + } + if (last_time_ms != 0 && last_time_ms != packet.time_ms) { + SleepMs(packet.time_ms - last_time_ms); + } + last_time_ms = packet.time_ms; + } + fprintf(stderr, "num_packets: %d\n", num_packets); + + call->DestroyVideoReceiveStream(receive_stream); +} +} // namespace webrtc + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + google::ParseCommandLineFlags(&argc, &argv, true); + + webrtc::test::RunTest(webrtc::RtpReplay); + return 0; +} diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi index 78b199f09d..ace6684386 100644 --- a/webrtc/webrtc_tests.gypi +++ b/webrtc/webrtc_tests.gypi @@ -13,6 +13,7 @@ 'dependencies': [ 'video_engine_tests', 'video_loopback', + 'video_replay', 'webrtc_perf_tests', ], }, @@ -41,6 +42,31 @@ 'webrtc', ], }, + { + 'target_name': 'video_replay', + 'type': 'executable', + 'sources': [ + 'test/mac/run_test.mm', + 'test/run_test.cc', + 'test/run_test.h', + 'video/replay.cc', + ], + 'conditions': [ + ['OS=="mac"', { + 'sources!': [ + 'test/run_test.cc', + ], + }], + ], + 'dependencies': [ + '<(DEPTH)/testing/gtest.gyp:gtest', + '<(DEPTH)/third_party/gflags/gflags.gyp:gflags', + 'system_wrappers/source/system_wrappers.gyp:field_trial_default', + 'test/webrtc_test_common.gyp:webrtc_test_common', + 'test/webrtc_test_common.gyp:webrtc_test_renderer', + 'webrtc', + ], + }, { 'target_name': 'video_engine_tests', 'type': '<(gtest_target_type)',