| /* |
| * Copyright (c) 2011 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 "gtest/gtest.h" |
| #include "modules/interface/module_common_types.h" |
| #include "modules/video_coding/main/source/packet.h" |
| #include "modules/video_coding/main/source/session_info.h" |
| |
| namespace webrtc { |
| |
| class TestSessionInfo : public ::testing::Test { |
| protected: |
| enum { kPacketBufferSize = 10 }; |
| enum { kFrameBufferSize = 10 * kPacketBufferSize }; |
| |
| virtual void SetUp() { |
| memset(packet_buffer_, 0, kPacketBufferSize); |
| memset(frame_buffer_, 0, kFrameBufferSize); |
| session_.Reset(); |
| packet_.Reset(); |
| packet_.frameType = kVideoFrameDelta; |
| packet_.sizeBytes = kPacketBufferSize; |
| packet_.dataPtr = packet_buffer_; |
| packet_.seqNum = 0; |
| packet_.timestamp = 0; |
| } |
| |
| void FillPacket(uint8_t start_value) { |
| for (int i = 0; i < kPacketBufferSize; ++i) |
| packet_buffer_[i] = start_value + i; |
| } |
| |
| void VerifyPacket(uint8_t* start_ptr, uint8_t start_value) { |
| for (int j = 0; j < kPacketBufferSize; ++j) { |
| ASSERT_EQ(start_value + j, start_ptr[j]); |
| } |
| } |
| |
| uint8_t packet_buffer_[kPacketBufferSize]; |
| uint8_t frame_buffer_[kFrameBufferSize]; |
| VCMSessionInfo session_; |
| VCMPacket packet_; |
| }; |
| |
| class TestVP8Partitions : public TestSessionInfo { |
| protected: |
| enum { kMaxVP8Partitions = 9 }; |
| |
| virtual void SetUp() { |
| TestSessionInfo::SetUp(); |
| vp8_header_ = &packet_header_.type.Video.codecHeader.VP8; |
| packet_header_.frameType = kVideoFrameDelta; |
| packet_header_.type.Video.codec = kRTPVideoVP8; |
| vp8_header_->InitRTPVideoHeaderVP8(); |
| fragmentation_.VerifyAndAllocateFragmentationHeader(kMaxVP8Partitions); |
| } |
| |
| bool VerifyPartition(int partition_id, |
| int packets_expected, |
| int start_value) { |
| EXPECT_EQ(static_cast<uint32_t>(packets_expected * kPacketBufferSize), |
| fragmentation_.fragmentationLength[partition_id]); |
| for (int i = 0; i < packets_expected; ++i) { |
| int packet_index = fragmentation_.fragmentationOffset[partition_id] + |
| i * kPacketBufferSize; |
| if (packet_index + kPacketBufferSize > kFrameBufferSize) |
| return false; |
| VerifyPacket(frame_buffer_ + packet_index, start_value + i); |
| } |
| return true; |
| } |
| |
| WebRtcRTPHeader packet_header_; |
| RTPVideoHeaderVP8* vp8_header_; |
| RTPFragmentationHeader fragmentation_; |
| }; |
| |
| class TestNalUnits : public TestSessionInfo { |
| protected: |
| virtual void SetUp() { |
| TestSessionInfo::SetUp(); |
| packet_.codec = kVideoCodecVP8; |
| } |
| |
| bool VerifyNalu(int offset, int packets_expected, int start_value) { |
| EXPECT_GE(session_.SessionLength(), |
| packets_expected * kPacketBufferSize); |
| for (int i = 0; i < packets_expected; ++i) { |
| int packet_index = offset * kPacketBufferSize + i * kPacketBufferSize; |
| VerifyPacket(frame_buffer_ + packet_index, start_value + i); |
| } |
| return true; |
| } |
| }; |
| |
| class TestNackList : public TestSessionInfo { |
| protected: |
| enum { 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) { |
| int 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_.isFirstPacket = true; |
| packet_.seqNum = 0xFFFE; |
| packet_.sizeBytes = kPacketBufferSize; |
| packet_.frameType = kVideoFrameKey; |
| FillPacket(0); |
| ASSERT_EQ(kPacketBufferSize, |
| session_.InsertPacket(packet_, frame_buffer_, false, 0)); |
| EXPECT_EQ(false, session_.HaveLastPacket()); |
| EXPECT_EQ(kVideoFrameKey, session_.FrameType()); |
| |
| packet_.isFirstPacket = false; |
| packet_.markerBit = true; |
| packet_.seqNum += 1; |
| ASSERT_EQ(kPacketBufferSize, |
| session_.InsertPacket(packet_, frame_buffer_, false, 0)); |
| EXPECT_EQ(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_.isFirstPacket = false; |
| packet_.markerBit = true; |
| packet_.seqNum = 2; |
| packet_.sizeBytes = 0; |
| packet_.frameType = kFrameEmpty; |
| ASSERT_EQ(0, |
| session_.InsertPacket(packet_, frame_buffer_, false, 0)); |
| EXPECT_EQ(packet_.seqNum, session_.HighSequenceNumber()); |
| } |
| |
| TEST_F(TestSessionInfo, NormalOperation) { |
| packet_.seqNum = 0xFFFF; |
| packet_.isFirstPacket = true; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = false; |
| for (int i = 1; i < 9; ++i) { |
| packet_.seqNum += 1; |
| FillPacket(i); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| } |
| |
| packet_.seqNum += 1; |
| packet_.markerBit = true; |
| FillPacket(9); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(0, session_.packets_not_decodable()); |
| EXPECT_EQ(10 * kPacketBufferSize, session_.SessionLength()); |
| for (int i = 0; i < 10; ++i) { |
| SCOPED_TRACE("Calling VerifyPacket"); |
| VerifyPacket(frame_buffer_ + i * kPacketBufferSize, i); |
| } |
| } |
| |
| TEST_F(TestVP8Partitions, TwoPartitionsOneLoss) { |
| // Partition 0 | Partition 1 |
| // [ 0 ] [ 2 ] | [ 3 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 0; |
| FillPacket(0); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 0; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 2; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(3); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // One packet should be removed (end of partition 0). |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 2*kPacketBufferSize); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 1, 0)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(1, 1, 3)); |
| } |
| |
| TEST_F(TestVP8Partitions, TwoPartitionsOneLoss2) { |
| // Partition 0 | Partition 1 |
| // [ 1 ] [ 2 ] | [ 3 ] [ 5 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 1; |
| FillPacket(1); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0) |
| , kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 0; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(3); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 2; |
| FillPacket(5); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // One packet should be removed (end of partition 2), 3 left. |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 3*kPacketBufferSize); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 2, 1)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(1, 1, 3)); |
| EXPECT_EQ(1, session_.packets_not_decodable()); |
| } |
| |
| TEST_F(TestVP8Partitions, TwoPartitionsNoLossWrap) { |
| // Partition 0 | Partition 1 |
| // [ fffd ] [ fffe ] | [ ffff ] [ 0 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 0xfffd; |
| FillPacket(0); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 0; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(1); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(3); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // No packet should be removed. |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 4*kPacketBufferSize); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 2, 0)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(1, 2, 2)); |
| EXPECT_EQ(0, session_.packets_not_decodable()); |
| } |
| |
| TEST_F(TestVP8Partitions, TwoPartitionsLossWrap) { |
| // Partition 0 | Partition 1 |
| // [ fffd ] [ fffe ] | [ ffff ] [ 1 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 0xfffd; |
| FillPacket(0); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 0; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(1); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 2; |
| FillPacket(3); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // One packet should be removed from the last partition |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 3*kPacketBufferSize); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 2, 0)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(1, 1, 2)); |
| EXPECT_EQ(1, session_.packets_not_decodable()); |
| } |
| |
| |
| TEST_F(TestVP8Partitions, ThreePartitionsOneMissing) { |
| // Partition 1 |Partition 2 | Partition 3 |
| // [ 1 ] [ 2 ] | | [ 5 ] | [ 6 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 1; |
| FillPacket(1); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 0; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 2; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 3; |
| FillPacket(5); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 2; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(6); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // No packet should be removed. |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 4*kPacketBufferSize); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 2, 1)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(2, 2, 5)); |
| EXPECT_EQ(0, session_.packets_not_decodable()); |
| } |
| |
| TEST_F(TestVP8Partitions, ThreePartitionsLossInSecond) { |
| // Partition 0 |Partition 1 | Partition 2 |
| // [ 1 ] [ 2 ] | [ 4 ] [ 5 ] | [ 6 ] [ 7 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 1; |
| FillPacket(1); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 0; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 2; |
| FillPacket(4); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(5); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 2; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(6); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 2; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(7); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // 2 partitions left. 2 packets removed from second partition |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 4*kPacketBufferSize); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 2, 1)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(2, 2, 6)); |
| EXPECT_EQ(2, session_.packets_not_decodable()); |
| } |
| |
| TEST_F(TestVP8Partitions, AggregationOverTwoPackets) { |
| // Partition 0 | Partition 1 | Partition 2 |
| // [ 0 | ] [ 1 ] | [ 2 ] |
| packet_header_.type.Video.isFirstPacket = true; |
| vp8_header_->beginningOfPartition = true; |
| vp8_header_->partitionId = 0; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber = 0; |
| FillPacket(0); |
| VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, |
| packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 1; |
| vp8_header_->beginningOfPartition = false; |
| packet_header_.header.markerBit = false; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(1); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| packet_header_.type.Video.isFirstPacket = false; |
| vp8_header_->partitionId = 2; |
| vp8_header_->beginningOfPartition = true; |
| packet_header_.header.markerBit = true; |
| packet_header_.header.sequenceNumber += 1; |
| FillPacket(2); |
| packet = new VCMPacket(packet_buffer_, kPacketBufferSize, packet_header_); |
| ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| delete packet; |
| |
| // No packets removed. |
| EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, |
| kFrameBufferSize, |
| &fragmentation_), |
| 3*kPacketBufferSize); |
| EXPECT_EQ(0, session_.packets_not_decodable()); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(0, 2, 0)); |
| // This partition is aggregated in partition 0 |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(1, 0, 0)); |
| SCOPED_TRACE("Calling VerifyPartition"); |
| EXPECT_TRUE(VerifyPartition(2, 1, 2)); |
| } |
| |
| TEST_F(TestNalUnits, OneIsolatedNaluLoss) { |
| packet_.isFirstPacket = true; |
| packet_.completeNALU = kNaluComplete; |
| packet_.seqNum = 0; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluComplete; |
| packet_.seqNum += 2; |
| packet_.markerBit = true; |
| FillPacket(2); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(0, session_.MakeDecodable()); |
| EXPECT_EQ(2 * kPacketBufferSize, session_.SessionLength()); |
| EXPECT_EQ(0, session_.packets_not_decodable()); |
| 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_.isFirstPacket = true; |
| packet_.completeNALU = kNaluComplete; |
| packet_.seqNum = 0; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluEnd; |
| packet_.seqNum += 2; |
| packet_.markerBit = true; |
| FillPacket(2); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(kPacketBufferSize, session_.MakeDecodable()); |
| EXPECT_EQ(kPacketBufferSize, session_.SessionLength()); |
| EXPECT_EQ(1, session_.packets_not_decodable()); |
| SCOPED_TRACE("Calling VerifyNalu"); |
| EXPECT_TRUE(VerifyNalu(0, 1, 0)); |
| } |
| |
| TEST_F(TestNalUnits, StartAndEndOfLastNalUnitLost) { |
| packet_.isFirstPacket = true; |
| packet_.completeNALU = kNaluComplete; |
| packet_.seqNum = 0; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluIncomplete; |
| packet_.seqNum += 2; |
| packet_.markerBit = false; |
| FillPacket(1); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(kPacketBufferSize, session_.MakeDecodable()); |
| EXPECT_EQ(kPacketBufferSize, session_.SessionLength()); |
| EXPECT_EQ(1, session_.packets_not_decodable()); |
| SCOPED_TRACE("Calling VerifyNalu"); |
| EXPECT_TRUE(VerifyNalu(0, 1, 0)); |
| } |
| |
| TEST_F(TestNalUnits, ReorderWrapNoLoss) { |
| packet_.seqNum = 0xFFFF; |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluIncomplete; |
| packet_.seqNum += 1; |
| packet_.markerBit = false; |
| FillPacket(1); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = true; |
| packet_.completeNALU = kNaluComplete; |
| packet_.seqNum -= 1; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluEnd; |
| packet_.seqNum += 2; |
| packet_.markerBit = true; |
| FillPacket(2); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(0, session_.MakeDecodable()); |
| EXPECT_EQ(0, session_.packets_not_decodable()); |
| EXPECT_EQ(3*kPacketBufferSize, session_.SessionLength()); |
| SCOPED_TRACE("Calling VerifyNalu"); |
| EXPECT_TRUE(VerifyNalu(0, 1, 0)); |
| } |
| |
| TEST_F(TestNalUnits, WrapLosses) { |
| packet_.seqNum = 0xFFFF; |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluIncomplete; |
| packet_.markerBit = false; |
| FillPacket(1); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluEnd; |
| packet_.seqNum += 2; |
| packet_.markerBit = true; |
| FillPacket(2); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(2 * kPacketBufferSize, session_.MakeDecodable()); |
| EXPECT_EQ(0, session_.SessionLength()); |
| EXPECT_EQ(2, session_.packets_not_decodable()); |
| } |
| |
| TEST_F(TestNalUnits, ReorderWrapLosses) { |
| packet_.seqNum = 0xFFFF; |
| |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluEnd; |
| packet_.seqNum += 2; |
| packet_.markerBit = true; |
| FillPacket(2); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| packet_.seqNum -= 2; |
| packet_.isFirstPacket = false; |
| packet_.completeNALU = kNaluIncomplete; |
| packet_.markerBit = false; |
| FillPacket(1); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(2 * kPacketBufferSize, session_.MakeDecodable()); |
| EXPECT_EQ(0, session_.SessionLength()); |
| EXPECT_EQ(2, session_.packets_not_decodable()); |
| } |
| |
| TEST_F(TestNackList, NoLosses) { |
| uint16_t low = 0xFFFF - 5; |
| |
| packet_.seqNum = low; |
| packet_.isFirstPacket = true; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| for (int i = 1; i < 9; ++i) { |
| packet_.seqNum += 1; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = false; |
| FillPacket(i + 1); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| } |
| |
| packet_.seqNum += 1; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = true; |
| FillPacket(10); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(10 * kPacketBufferSize, session_.SessionLength()); |
| BuildSeqNumList(low, packet_.seqNum); |
| EXPECT_EQ(0, session_.BuildHardNackList(seq_num_list_, seq_num_list_length_)); |
| EXPECT_EQ(false, session_.session_nack()); |
| SCOPED_TRACE("Calling VerifyAll"); |
| VerifyAll(-1); |
| |
| BuildSeqNumList(low, packet_.seqNum); |
| EXPECT_EQ(0, session_.BuildSoftNackList(seq_num_list_, seq_num_list_length_, |
| 60)); |
| SCOPED_TRACE("Calling VerifyAll"); |
| VerifyAll(-1); |
| } |
| |
| TEST_F(TestNackList, FiveLossesSpreadOut) { |
| uint16_t low = 0xFFFF - 5; |
| |
| packet_.seqNum = low; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = true; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| for (int i = 1; i < 9; ++i) { |
| packet_.seqNum += 1; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = false; |
| FillPacket(i); |
| if ((i + 1) % 2) |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| } |
| |
| packet_.seqNum++; // Simulate loss of last packet. |
| |
| EXPECT_EQ(5 * kPacketBufferSize, session_.SessionLength()); |
| BuildSeqNumList(low, packet_.seqNum); |
| EXPECT_EQ(0, session_.BuildHardNackList(seq_num_list_, seq_num_list_length_)); |
| for (int i = 0; i < seq_num_list_length_; ++i) { |
| if (i % 2) |
| EXPECT_EQ(static_cast<uint16_t>(low + i), seq_num_list_[i]); |
| else |
| EXPECT_EQ(-1, seq_num_list_[i]); |
| } |
| |
| BuildSeqNumList(low, packet_.seqNum); |
| EXPECT_EQ(0, session_.BuildSoftNackList(seq_num_list_, seq_num_list_length_, |
| 60)); |
| EXPECT_EQ(true, session_.session_nack()); |
| for (int i = 0; i < seq_num_list_length_; ++i) { |
| if (i % 2) |
| EXPECT_EQ(static_cast<uint16_t>(low + i), seq_num_list_[i]); |
| else |
| EXPECT_EQ(-1, seq_num_list_[i]); |
| } |
| } |
| |
| TEST_F(TestNackList, FirstAndLastLost) { |
| uint16_t low = 0xFFFF; |
| |
| packet_.seqNum = low + 1; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = false; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), |
| kPacketBufferSize); |
| |
| EXPECT_EQ(kPacketBufferSize, session_.SessionLength()); |
| BuildSeqNumList(low, packet_.seqNum + 1); |
| EXPECT_EQ(0, session_.BuildHardNackList(seq_num_list_, seq_num_list_length_)); |
| EXPECT_EQ(0xFFFF, seq_num_list_[0]); |
| EXPECT_EQ(-1, seq_num_list_[1]); |
| EXPECT_EQ(1, seq_num_list_[2]); |
| |
| BuildSeqNumList(low, packet_.seqNum + 1); |
| EXPECT_EQ(0, session_.BuildSoftNackList(seq_num_list_,seq_num_list_length_, |
| 60)); |
| EXPECT_EQ(true, session_.session_nack()); |
| EXPECT_EQ(0xFFFF, seq_num_list_[0]); |
| EXPECT_EQ(-1, seq_num_list_[1]); |
| EXPECT_EQ(1, seq_num_list_[2]); |
| } |
| |
| TEST_F(TestNackList, LostAllButEmptyPackets) { |
| uint16_t low = 0; |
| packet_.seqNum = low + 1; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = false; |
| packet_.frameType = kFrameEmpty; |
| packet_.sizeBytes = 0; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), 0); |
| |
| packet_.seqNum = low + 3; |
| packet_.isFirstPacket = false; |
| packet_.markerBit = false; |
| packet_.frameType = kFrameEmpty; |
| packet_.sizeBytes = 0; |
| FillPacket(0); |
| ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0), 0); |
| |
| EXPECT_EQ(0, session_.SessionLength()); |
| BuildSeqNumList(low, packet_.seqNum + 1); |
| EXPECT_EQ(0, session_.BuildSoftNackList(seq_num_list_, seq_num_list_length_, |
| 60)); |
| EXPECT_EQ(true, session_.session_nack()); |
| EXPECT_EQ(0, seq_num_list_[0]); |
| EXPECT_EQ(-1, seq_num_list_[1]); |
| EXPECT_EQ(-2, seq_num_list_[2]); |
| EXPECT_EQ(-2, seq_num_list_[3]); |
| EXPECT_EQ(4, seq_num_list_[4]); |
| } |
| } // namespace webrtc |