// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/bind.h" #include "base/message_loop.h" #include "base/message_loop_proxy.h" #include "base/string_number_conversions.h" #include "remoting/base/constants.h" #include "remoting/proto/video.pb.h" #include "remoting/protocol/fake_session.h" #include "remoting/protocol/rtp_reader.h" #include "remoting/protocol/rtp_utils.h" #include "remoting/protocol/rtp_video_writer.h" #include "testing/gtest/include/gtest/gtest.h" using net::IOBuffer; using std::string; using std::vector; namespace remoting { namespace protocol { namespace { bool ParsePacket(const string& data, RtpPacket* packet) { int header_size = UnpackRtpHeader( reinterpret_cast(&*data.begin()), data.size(), packet->mutable_header()); if (header_size < 0) { return false; } int descriptor_size = UnpackVp8Descriptor( reinterpret_cast(&*data.begin()) + header_size, data.size() - header_size, packet->mutable_vp8_descriptor()); if (descriptor_size < 0) { return false; } packet->mutable_payload()->AppendCopyOf( &*data.begin() + header_size + descriptor_size, data.size() - header_size - descriptor_size); return true; } } // namespace class RtpVideoWriterTest : public testing::Test { protected: struct ExpectedPacket { bool first; Vp8Descriptor::FragmentationInfo fragmentation_info; bool last; }; RtpVideoWriterTest() : writer_(base::MessageLoopProxy::current()) { } virtual void SetUp() { session_.reset(new FakeSession()); writer_.Init(session_.get(), base::Bind(&RtpVideoWriterTest::OnWriterInitialized, base::Unretained(this))); } void OnWriterInitialized(bool success) { ASSERT_TRUE(success); } void InitData(int size) { data_.resize(size); for (int i = 0; i < size; ++i) { data_[i] = static_cast(i); } } void InitPacket(int size, bool first, bool last) { InitData(size); packet_ = new VideoPacket(); packet_->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); if (first) packet_->set_flags(packet_->flags() | VideoPacket::FIRST_PACKET); if (last) packet_->set_flags(packet_->flags() | VideoPacket::LAST_PACKET); packet_->mutable_data()->assign(data_.begin(), data_.end()); } bool CompareData(const CompoundBuffer& buffer, char* data, int size) { scoped_refptr buffer_data = buffer.ToIOBufferWithSize(); return buffer.total_bytes() == size && memcmp(buffer_data->data(), data, size) == 0; } void VerifyResult(const ExpectedPacket expected[], int count) { const vector& rtp_packets = session_->GetDatagramChannel(kVideoRtpChannelName)->written_packets(); ASSERT_EQ(count, static_cast(rtp_packets.size())); int pos = 0; for (int i = 0; i < count; ++i) { SCOPED_TRACE("Packet " + base::IntToString(i)); RtpPacket packet; ASSERT_TRUE(ParsePacket(rtp_packets[i], &packet)); EXPECT_EQ(expected[i].first, packet.vp8_descriptor().frame_beginning); EXPECT_EQ(expected[i].last, packet.header().marker); EXPECT_EQ(expected[i].fragmentation_info, packet.vp8_descriptor().fragmentation_info); EXPECT_TRUE(CompareData(packet.payload(), &*data_.begin() + pos, packet.payload().total_bytes())); pos += packet.payload().total_bytes(); } EXPECT_EQ(pos, static_cast(data_.size())); } MessageLoop message_loop_; scoped_ptr session_; RtpVideoWriter writer_; vector data_; VideoPacket* packet_; }; TEST_F(RtpVideoWriterTest, NotFragmented_FirstPacket) { InitPacket(1024, true, false); writer_.ProcessVideoPacket(packet_, new DeleteTask(packet_)); message_loop_.RunAllPending(); ExpectedPacket expected[] = { { true, Vp8Descriptor::NOT_FRAGMENTED, false } }; VerifyResult(expected, arraysize(expected)); } TEST_F(RtpVideoWriterTest, NotFragmented_LastPackes) { InitPacket(1024, false, true); writer_.ProcessVideoPacket(packet_, new DeleteTask(packet_)); message_loop_.RunAllPending(); ExpectedPacket expected[] = { { false, Vp8Descriptor::NOT_FRAGMENTED, true } }; VerifyResult(expected, arraysize(expected)); } TEST_F(RtpVideoWriterTest, TwoFragments_FirstPacket) { InitPacket(2000, true, false); writer_.ProcessVideoPacket(packet_, new DeleteTask(packet_)); message_loop_.RunAllPending(); ExpectedPacket expected[] = { { true, Vp8Descriptor::FIRST_FRAGMENT, false }, { false, Vp8Descriptor::LAST_FRAGMENT, false }, }; VerifyResult(expected, arraysize(expected)); } TEST_F(RtpVideoWriterTest, TwoFragments_LastPacket) { InitPacket(2000, false, true); writer_.ProcessVideoPacket(packet_, new DeleteTask(packet_)); message_loop_.RunAllPending(); ExpectedPacket expected[] = { { false, Vp8Descriptor::FIRST_FRAGMENT, false }, { false, Vp8Descriptor::LAST_FRAGMENT, true }, }; VerifyResult(expected, arraysize(expected)); } TEST_F(RtpVideoWriterTest, ThreeFragments) { InitPacket(3000, true, true); writer_.ProcessVideoPacket(packet_, new DeleteTask(packet_)); message_loop_.RunAllPending(); ExpectedPacket expected[] = { { true, Vp8Descriptor::FIRST_FRAGMENT, false }, { false, Vp8Descriptor::MIDDLE_FRAGMENT, false }, { false, Vp8Descriptor::LAST_FRAGMENT, true }, }; VerifyResult(expected, arraysize(expected)); } } // namespace protocol } // namespace remoting