/* * Copyright (c) 2012 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 "modules/video_coding/session_info.h" #include #include "modules/video_coding/packet.h" #include "test/gtest.h" namespace webrtc { class TestSessionInfo : public ::testing::Test { protected: virtual void SetUp() { memset(packet_buffer_, 0, sizeof(packet_buffer_)); memset(frame_buffer_, 0, sizeof(frame_buffer_)); session_.Reset(); packet_.video_header.frame_type = VideoFrameType::kVideoFrameDelta; packet_.sizeBytes = packet_buffer_size(); packet_.dataPtr = packet_buffer_; packet_.seqNum = 0; packet_.timestamp = 0; frame_data.rtt_ms = 0; frame_data.rolling_average_packets_per_frame = -1; } void FillPacket(uint8_t start_value) { for (size_t i = 0; i < packet_buffer_size(); ++i) packet_buffer_[i] = start_value + i; } void VerifyPacket(uint8_t* start_ptr, uint8_t start_value) { for (size_t j = 0; j < packet_buffer_size(); ++j) { ASSERT_EQ(start_value + j, start_ptr[j]); } } size_t packet_buffer_size() const { return sizeof(packet_buffer_) / sizeof(packet_buffer_[0]); } size_t frame_buffer_size() const { return sizeof(frame_buffer_) / sizeof(frame_buffer_[0]); } enum { kPacketBufferSize = 10 }; uint8_t packet_buffer_[kPacketBufferSize]; uint8_t frame_buffer_[10 * kPacketBufferSize]; VCMSessionInfo session_; VCMPacket packet_; FrameData frame_data; }; class TestNalUnits : public TestSessionInfo { protected: virtual void SetUp() { TestSessionInfo::SetUp(); packet_.video_header.codec = kVideoCodecVP8; } bool VerifyNalu(int offset, int packets_expected, int start_value) { EXPECT_GE(session_.SessionLength(), packets_expected * packet_buffer_size()); for (int i = 0; i < packets_expected; ++i) { int packet_index = (offset + i) * packet_buffer_size(); VerifyPacket(frame_buffer_ + packet_index, start_value + i); } return true; } }; class TestNackList : public TestSessionInfo { protected: static const size_t kMaxSeqNumListLength = 30; virtual void SetUp() { TestSessionInfo::SetUp(); seq_num_list_length_ = 0; memset(seq_num_list_, 0, sizeof(seq_num_list_)); } void BuildSeqNumList(uint16_t low, uint16_t high) { size_t i = 0; while (low != high + 1) { EXPECT_LT(i, kMaxSeqNumListLength); if (i >= kMaxSeqNumListLength) { seq_num_list_length_ = kMaxSeqNumListLength; return; } seq_num_list_[i] = low; low++; i++; } seq_num_list_length_ = i; } void VerifyAll(int value) { for (int i = 0; i < seq_num_list_length_; ++i) EXPECT_EQ(seq_num_list_[i], value); } int seq_num_list_[kMaxSeqNumListLength]; int seq_num_list_length_; }; TEST_F(TestSessionInfo, TestSimpleAPIs) { packet_.video_header.is_first_packet_in_frame = true; packet_.seqNum = 0xFFFE; packet_.sizeBytes = packet_buffer_size(); packet_.video_header.frame_type = VideoFrameType::kVideoFrameKey; FillPacket(0); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_FALSE(session_.HaveLastPacket()); EXPECT_EQ(VideoFrameType::kVideoFrameKey, session_.FrameType()); packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = true; packet_.seqNum += 1; EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_TRUE(session_.HaveLastPacket()); EXPECT_EQ(packet_.seqNum, session_.HighSequenceNumber()); EXPECT_EQ(0xFFFE, session_.LowSequenceNumber()); // Insert empty packet which will be the new high sequence number. // To make things more difficult we will make sure to have a wrap here. packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = true; packet_.seqNum = 2; packet_.sizeBytes = 0; packet_.video_header.frame_type = VideoFrameType::kEmptyFrame; EXPECT_EQ(0, session_.InsertPacket(packet_, frame_buffer_, frame_data)); EXPECT_EQ(packet_.seqNum, session_.HighSequenceNumber()); } TEST_F(TestSessionInfo, NormalOperation) { packet_.seqNum = 0xFFFF; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = false; FillPacket(0); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = false; for (int i = 1; i < 9; ++i) { packet_.seqNum += 1; FillPacket(i); ASSERT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); } packet_.seqNum += 1; packet_.markerBit = true; FillPacket(9); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(10 * packet_buffer_size(), session_.SessionLength()); for (int i = 0; i < 10; ++i) { SCOPED_TRACE("Calling VerifyPacket"); VerifyPacket(frame_buffer_ + i * packet_buffer_size(), i); } } TEST_F(TestSessionInfo, OutOfBoundsPackets1PacketFrame) { packet_.seqNum = 0x0001; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0004; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); packet_.seqNum = 0x0000; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); } TEST_F(TestSessionInfo, SetMarkerBitOnce) { packet_.seqNum = 0x0005; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); ++packet_.seqNum; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); } TEST_F(TestSessionInfo, OutOfBoundsPacketsBase) { // Allow packets in the range 5-6. packet_.seqNum = 0x0005; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); // Insert an older packet with a first packet set. packet_.seqNum = 0x0004; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); packet_.seqNum = 0x0006; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0008; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); } TEST_F(TestSessionInfo, OutOfBoundsPacketsWrap) { packet_.seqNum = 0xFFFE; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0004; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0002; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); ASSERT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0xFFF0; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); packet_.seqNum = 0x0006; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); } TEST_F(TestSessionInfo, OutOfBoundsOutOfOrder) { // Insert out of bound regular packets, and then the first and last packet. // Verify that correct bounds are maintained. packet_.seqNum = 0x0003; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); // Insert an older packet with a first packet set. packet_.seqNum = 0x0005; packet_.video_header.is_first_packet_in_frame = true; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0004; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); packet_.seqNum = 0x0010; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0008; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = true; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum = 0x0009; packet_.video_header.is_first_packet_in_frame = false; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(-3, session_.InsertPacket(packet_, frame_buffer_, frame_data)); } TEST_F(TestNalUnits, OnlyReceivedEmptyPacket) { packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluComplete; packet_.video_header.frame_type = VideoFrameType::kEmptyFrame; packet_.sizeBytes = 0; packet_.seqNum = 0; packet_.markerBit = false; EXPECT_EQ(0, session_.InsertPacket(packet_, frame_buffer_, frame_data)); EXPECT_EQ(0U, session_.MakeDecodable()); EXPECT_EQ(0U, session_.SessionLength()); } TEST_F(TestNalUnits, OneIsolatedNaluLoss) { packet_.video_header.is_first_packet_in_frame = true; packet_.completeNALU = kNaluComplete; packet_.seqNum = 0; packet_.markerBit = false; FillPacket(0); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluComplete; packet_.seqNum += 2; packet_.markerBit = true; FillPacket(2); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(0U, session_.MakeDecodable()); EXPECT_EQ(2 * packet_buffer_size(), session_.SessionLength()); SCOPED_TRACE("Calling VerifyNalu"); EXPECT_TRUE(VerifyNalu(0, 1, 0)); SCOPED_TRACE("Calling VerifyNalu"); EXPECT_TRUE(VerifyNalu(1, 1, 2)); } TEST_F(TestNalUnits, LossInMiddleOfNalu) { packet_.video_header.is_first_packet_in_frame = true; packet_.completeNALU = kNaluComplete; packet_.seqNum = 0; packet_.markerBit = false; FillPacket(0); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluEnd; packet_.seqNum += 2; packet_.markerBit = true; FillPacket(2); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(packet_buffer_size(), session_.MakeDecodable()); EXPECT_EQ(packet_buffer_size(), session_.SessionLength()); SCOPED_TRACE("Calling VerifyNalu"); EXPECT_TRUE(VerifyNalu(0, 1, 0)); } TEST_F(TestNalUnits, StartAndEndOfLastNalUnitLost) { packet_.video_header.is_first_packet_in_frame = true; packet_.completeNALU = kNaluComplete; packet_.seqNum = 0; packet_.markerBit = false; FillPacket(0); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluIncomplete; packet_.seqNum += 2; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(packet_buffer_size(), session_.MakeDecodable()); EXPECT_EQ(packet_buffer_size(), session_.SessionLength()); SCOPED_TRACE("Calling VerifyNalu"); EXPECT_TRUE(VerifyNalu(0, 1, 0)); } TEST_F(TestNalUnits, ReorderWrapNoLoss) { packet_.seqNum = 0xFFFF; packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluIncomplete; packet_.seqNum += 1; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = true; packet_.completeNALU = kNaluComplete; packet_.seqNum -= 1; packet_.markerBit = false; FillPacket(0); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluEnd; packet_.seqNum += 2; packet_.markerBit = true; FillPacket(2); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(0U, session_.MakeDecodable()); EXPECT_EQ(3 * packet_buffer_size(), session_.SessionLength()); SCOPED_TRACE("Calling VerifyNalu"); EXPECT_TRUE(VerifyNalu(0, 1, 0)); } TEST_F(TestNalUnits, WrapLosses) { packet_.seqNum = 0xFFFF; packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluIncomplete; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluEnd; packet_.seqNum += 2; packet_.markerBit = true; FillPacket(2); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(2 * packet_buffer_size(), session_.MakeDecodable()); EXPECT_EQ(0U, session_.SessionLength()); } TEST_F(TestNalUnits, ReorderWrapLosses) { packet_.seqNum = 0xFFFF; packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluEnd; packet_.seqNum += 2; packet_.markerBit = true; FillPacket(2); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); packet_.seqNum -= 2; packet_.video_header.is_first_packet_in_frame = false; packet_.completeNALU = kNaluIncomplete; packet_.markerBit = false; FillPacket(1); EXPECT_EQ(packet_buffer_size(), static_cast(session_.InsertPacket( packet_, frame_buffer_, frame_data))); EXPECT_EQ(2 * packet_buffer_size(), session_.MakeDecodable()); EXPECT_EQ(0U, session_.SessionLength()); } } // namespace webrtc