blob: 285cf9ce2d7d9d0f2e666b9d81ad21bbc1864ed0 [file] [log] [blame]
/*
* 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