The second step towards a list based SessionInfo.

Added unittests for most of public functions of SessionInfo.

BUG=
TEST=

Review URL: http://webrtc-codereview.appspot.com/301014

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1166 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org
2011-12-13 07:54:56 +00:00
parent c28e7980ef
commit 076fa6e674
6 changed files with 1139 additions and 981 deletions

View File

@@ -59,13 +59,13 @@ VCMFrameBuffer::SetPreviousFrameLoss()
WebRtc_Word32
VCMFrameBuffer::GetLowSeqNum() const
{
return _sessionInfo.GetLowSeqNum();
return _sessionInfo.LowSequenceNumber();
}
WebRtc_Word32
VCMFrameBuffer::GetHighSeqNum() const
{
return _sessionInfo.GetHighSeqNum();
return _sessionInfo.HighSequenceNumber();
}
int VCMFrameBuffer::PictureId() const {
@@ -87,7 +87,7 @@ bool VCMFrameBuffer::NonReference() const {
bool
VCMFrameBuffer::IsSessionComplete() const
{
return _sessionInfo.IsSessionComplete();
return _sessionInfo.complete();
}
// Insert packet
@@ -124,11 +124,6 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs,
{
return kSizeError;
}
if ((packet.frameType != kFrameEmpty) &&
(!_sessionInfo.HaveStartSeqNumber()))
{
_sessionInfo.SetStartSeqNumber(packet.seqNum);
}
if (packet.dataPtr != NULL)
{
_payloadType = packet.payloadType;
@@ -166,14 +161,14 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs,
{
return kSizeError;
}
_sessionInfo.UpdateDataPointers(_buffer, prevBuffer);
_sessionInfo.UpdateDataPointers(_buffer - prevBuffer);
}
CopyCodecSpecific(&packet.codecSpecificHeader);
WebRtc_Word64 retVal = _sessionInfo.InsertPacket(packet, _buffer,
enableDecodableState,
rttMS);
int retVal = _sessionInfo.InsertPacket(packet, _buffer,
enableDecodableState,
rttMS);
if (retVal == -1)
{
return kSizeError;
@@ -187,9 +182,9 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs,
_latestPacketTimeMs = timeInMs;
if (_sessionInfo.IsSessionComplete()) {
if (_sessionInfo.complete()) {
return kCompleteSession;
} else if (_sessionInfo.IsSessionDecodable()) {
} else if (_sessionInfo.decodable()) {
SetState(kStateDecodable);
return kDecodableSession;
} else {
@@ -272,11 +267,11 @@ VCMFrameBuffer::MakeSessionDecodable()
WebRtc_UWord32 retVal;
#ifdef INDEPENDENT_PARTITIONS
if (_codec != kVideoCodecVP8) {
retVal = _sessionInfo.MakeDecodable(_buffer);
retVal = _sessionInfo.MakeDecodable();
_length -= retVal;
}
#else
retVal = _sessionInfo.MakeDecodable(_buffer);
retVal = _sessionInfo.MakeDecodable();
_length -= retVal;
#endif
}
@@ -350,7 +345,7 @@ VCMFrameBuffer::RestructureFrameInformation()
{
PrepareForDecode();
_frameType = ConvertFrameType(_sessionInfo.FrameType());
_completeFrame = _sessionInfo.IsSessionComplete();
_completeFrame = _sessionInfo.complete();
_missingFrame = _sessionInfo.PreviousFrameLoss();
}
@@ -371,14 +366,14 @@ VCMFrameBuffer::ExtractFromStorage(const EncodedVideoData& frameFromStorage)
{
return VCM_MEMORY;
}
_sessionInfo.UpdateDataPointers(_buffer, prevBuffer);
_sessionInfo.UpdateDataPointers(_buffer - prevBuffer);
memcpy(_buffer, frameFromStorage.payloadData, frameFromStorage.payloadSize);
_length = frameFromStorage.payloadSize;
return VCM_OK;
}
int VCMFrameBuffer::NotDecodablePackets() const {
return _sessionInfo.NotDecodablePackets();
return _sessionInfo.packets_not_decodable();
}
// Set counted status (as counted by JB or not)
@@ -410,7 +405,7 @@ VCMFrameBuffer::GetState(WebRtc_UWord32& timeStamp) const
bool
VCMFrameBuffer::IsRetransmitted() const
{
return _sessionInfo.IsRetransmitted();
return _sessionInfo.session_nack();
}
void
@@ -425,10 +420,10 @@ VCMFrameBuffer::PrepareForDecode()
}
else
{
_length = _sessionInfo.PrepareForDecode(_buffer, _codec);
_length = _sessionInfo.PrepareForDecode(_buffer);
}
#else
_length = _sessionInfo.PrepareForDecode(_buffer, _codec);
_length = _sessionInfo.PrepareForDecode(_buffer);
#endif
}

View File

@@ -25,7 +25,7 @@ enum VCMJitterBufferEnum
{
kMaxConsecutiveOldFrames = 60,
kMaxConsecutiveOldPackets = 300,
kMaxPacketsInJitterBuffer = 800,
kMaxPacketsInSession = 800,
kBufferIncStepSizeBytes = 30000, // >20 packets
kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte
};

File diff suppressed because it is too large Load Diff

View File

@@ -11,138 +11,121 @@
#ifndef WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
#define WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
#include "typedefs.h"
#include "module_common_types.h"
#include "packet.h"
#include <cstddef>
#include <list>
namespace webrtc
{
#include "modules/interface/module_common_types.h"
#include "modules/video_coding/main/source/packet.h"
#include "typedefs.h" // NOLINT(build/include)
enum { kMaxVP8Partitions = 9 };
namespace webrtc {
class VCMSessionInfo
{
public:
VCMSessionInfo();
virtual ~VCMSessionInfo();
class VCMSessionInfo {
public:
VCMSessionInfo();
VCMSessionInfo(const VCMSessionInfo& rhs);
void UpdateDataPointers(ptrdiff_t address_delta);
int ZeroOutSeqNum(int* seq_num_list,
int seq_num_list_length);
void UpdateDataPointers(const WebRtc_UWord8* frame_buffer,
const WebRtc_UWord8* prev_buffer_address);
// Hybrid version: Zero out seq num for NACK list
// Selectively NACK packets.
int ZeroOutSeqNumHybrid(int* seq_num_list,
int seq_num_list_length,
int rtt_ms);
void Reset();
int InsertPacket(const VCMPacket& packet,
uint8_t* frame_buffer,
bool enable_decodable_state,
int rtt_ms);
bool complete() const;
bool decodable() const;
WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list,
WebRtc_Word32 numberOfSeqNum);
// Hybrid version: Zero out seq num for NACK list
// Selectively NACK packets.
WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list,
WebRtc_Word32 numberOfSeqNum,
WebRtc_UWord32 rttMs);
virtual void Reset();
// Builds fragmentation headers for VP8, each fragment being a decodable
// VP8 partition. Returns the total number of bytes which are decodable. Is
// used instead of MakeDecodable for VP8.
int BuildVP8FragmentationHeader(uint8_t* frame_buffer,
int frame_buffer_length,
RTPFragmentationHeader* fragmentation);
WebRtc_Word64 InsertPacket(const VCMPacket& packet,
WebRtc_UWord8* ptrStartOfLayer,
bool enableDecodableState,
WebRtc_UWord32 rttMs);
WebRtc_Word32 InformOfEmptyPacket(const WebRtc_UWord16 seqNum);
// Makes the frame decodable. I.e., only contain decodable NALUs. All
// non-decodable NALUs will be deleted and packets will be moved to in
// memory to remove any empty space.
// Returns the number of bytes deleted from the session.
int MakeDecodable();
int SessionLength() const;
bool HaveLastPacket() const;
bool session_nack() const;
webrtc::FrameType FrameType() const { return frame_type_; }
int LowSequenceNumber() const;
virtual bool IsSessionComplete() const;
virtual bool IsSessionDecodable() const;
// Returns highest sequence number, media or empty.
int HighSequenceNumber() const;
int PictureId() const;
int TemporalId() const;
int Tl0PicId() const;
bool NonReference() const;
int PrepareForDecode(uint8_t* frame_buffer);
void SetPreviousFrameLoss() { previous_frame_loss_ = true; }
bool PreviousFrameLoss() const { return previous_frame_loss_; }
// Builds fragmentation headers for VP8, each fragment being a decodable
// VP8 partition. Returns the total number of bytes which are decodable. Is
// used instead of MakeDecodable for VP8.
int BuildVP8FragmentationHeader(WebRtc_UWord8* frame_buffer,
int frame_buffer_length,
RTPFragmentationHeader* fragmentation);
// The number of packets discarded because the decoder can't make use of
// them.
int packets_not_decodable() const;
// Makes the frame decodable. I.e., only contain decodable NALUs. All
// non-decodable NALUs will be deleted and packets will be moved to in
// memory to remove any empty space.
// Returns the number of bytes deleted from the session.
WebRtc_UWord32 MakeDecodable(WebRtc_UWord8* ptrStartOfLayer);
private:
enum { kMaxVP8Partitions = 9 };
WebRtc_UWord32 GetSessionLength();
bool HaveLastPacket() const;
bool IsRetransmitted() const;
webrtc::FrameType FrameType() const { return _frameType; }
typedef std::list<VCMPacket> PacketList;
typedef PacketList::iterator PacketIterator;
typedef PacketList::const_iterator PacketIteratorConst;
typedef PacketList::reverse_iterator ReversePacketIterator;
virtual WebRtc_Word32 GetHighestPacketIndex();
void InformOfEmptyPacket(uint16_t seq_num);
void SetStartSeqNumber(WebRtc_UWord16 seqNumber);
// Finds the packet of the beginning of the next VP8 partition. If
// none is found the returned iterator points to |packets_.end()|.
// |it| is expected to point to the last packet of the previous partition,
// or to the first packet of the frame. |packets_skipped| is incremented
// for each packet found which doesn't have the beginning bit set.
PacketIterator FindNextPartitionBeginning(PacketIterator it,
int* packets_skipped) const;
bool HaveStartSeqNumber();
// Returns an iterator pointing to the last packet of the partition pointed to
// by |it|.
PacketIterator FindPartitionEnd(PacketIterator it) const;
static bool InSequence(const PacketIterator& it,
const PacketIterator& prev_it);
static int PacketsMissing(const PacketIterator& packet_it,
const PacketIterator& prev_packet_it);
int InsertBuffer(uint8_t* frame_buffer,
PacketIterator packetIterator);
void ShiftSubsequentPackets(PacketIterator it, int steps_to_shift);
PacketIterator FindNaluEnd(PacketIterator packet_iter) const;
// Deletes the data of all packets between |start| and |end|, inclusively.
// Note that this function doesn't delete the actual packets.
int DeletePacketData(PacketIterator start,
PacketIterator end);
void UpdateCompleteSession();
WebRtc_Word32 GetLowSeqNum() const;
// returns highest seqNum, media or empty
WebRtc_Word32 GetHighSeqNum() const;
int PictureId() const;
int TemporalId() const;
int Tl0PicId() const;
bool NonReference() const;
// When enabled, determine if session is decodable, i.e. incomplete but
// would be sent to the decoder.
void UpdateDecodableSession(int rtt_ms);
WebRtc_UWord32 PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer,
VideoCodecType codec);
void SetPreviousFrameLoss() { _previousFrameLoss = true; }
bool PreviousFrameLoss() const { return _previousFrameLoss; }
// The number of packets discarded because the decoder can't make use of
// them.
int NotDecodablePackets() const;
private:
// Finds the packet index of the beginning of the next VP8 partition. If
// none is found _highestPacketIndex + 1 is returned. packet_index is
// expected to be the index of the last decodable packet of the previous
// partitions + 1, or 0 for the first partition.
int FindNextPartitionBeginning(int packet_index);
// Finds the packet index of the end of the partition with index
// partitionIndex.
int FindPartitionEnd(int packet_index) const;
static bool InSequence(WebRtc_UWord16 seqNum, WebRtc_UWord16 prevSeqNum);
WebRtc_UWord32 InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
WebRtc_Word32 packetIndex,
const VCMPacket& packet);
void FindNaluBorder(WebRtc_Word32 packetIndex,
WebRtc_Word32& startIndex,
WebRtc_Word32& endIndex);
WebRtc_UWord32 DeletePackets(WebRtc_UWord8* ptrStartOfLayer,
WebRtc_Word32 startIndex,
WebRtc_Word32 endIndex);
void UpdateCompleteSession();
// When enabled, determine if session is decodable, i.e. incomplete but
// would be sent to the decoder.
void UpdateDecodableSession(WebRtc_UWord32 rttMs);
// If we have inserted a packet with markerbit into this frame
bool _markerBit;
// If this session has been NACKed by JB
bool _sessionNACK;
bool _completeSession;
bool _decodableSession;
webrtc::FrameType _frameType;
bool _previousFrameLoss;
// Lowest/Highest packet sequence number in a session
WebRtc_Word32 _lowSeqNum;
WebRtc_Word32 _highSeqNum;
// Highest packet index in this frame
WebRtc_UWord16 _highestPacketIndex;
// Packets in this frame.
// TODO(holmer): Replace this with a std::list<VCMPacket*>. Doing that will
// make it possible to get rid of _markerBit, _lowSeqNum,
// _highSeqNum, _highestPacketIndex, etc.
VCMPacket _packets[kMaxPacketsInJitterBuffer];
WebRtc_Word32 _emptySeqNumLow;
WebRtc_Word32 _emptySeqNumHigh;
// Store the sequence number that marks the last media packet
WebRtc_Word32 _markerSeqNum;
// Number of packets discarded because the decoder can't use them.
int _packetsNotDecodable;
int _pictureId;
// If this session has been NACKed by the jitter buffer.
bool session_nack_;
bool complete_;
bool decodable_;
webrtc::FrameType frame_type_;
bool previous_frame_loss_;
// Packets in this frame.
PacketList packets_;
int empty_seq_num_low_;
int empty_seq_num_high_;
// Number of packets discarded because the decoder can't use them.
int packets_not_decodable_;
};
} // namespace webrtc
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
#endif // WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_

View File

@@ -11,63 +11,196 @@
#include <string.h>
#include "gtest/gtest.h"
#include "module_common_types.h"
#include "packet.h"
#include "session_info.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"
using webrtc::RTPFragmentationHeader;
using webrtc::RTPVideoHeaderVP8;
using webrtc::VCMPacket;
using webrtc::VCMSessionInfo;
using webrtc::WebRtcRTPHeader;
namespace webrtc {
enum { kPacketBufferSize = 10 };
enum { kFrameBufferSize = 10*kPacketBufferSize };
class TestVP8MakeDecodable : public ::testing::Test {
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);
vp8_header_ = &packet_header_.type.Video.codecHeader.VP8;
packet_header_.frameType = webrtc::kVideoFrameDelta;
packet_header_.type.Video.codec = webrtc::kRTPVideoVP8;
vp8_header_->InitRTPVideoHeaderVP8();
fragmentation_.VerifyAndAllocateFragmentationHeader(
webrtc::kMaxVP8Partitions);
session_.Reset();
packet_.Reset();
packet_.frameType = kVideoFrameDelta;
packet_.sizeBytes = kPacketBufferSize;
packet_.dataPtr = packet_buffer_;
packet_.seqNum = 0;
packet_.timestamp = 0;
packet_.bits = false;
}
void FillPacket(WebRtc_UWord8 start_value) {
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<WebRtc_UWord32>(packets_expected * kPacketBufferSize),
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;
for (int j = 0; j < kPacketBufferSize; ++j) {
if (packet_index + j > kFrameBufferSize)
return false;
EXPECT_EQ(start_value + i + j, frame_buffer_[packet_index + j]);
}
if (packet_index + kPacketBufferSize > kFrameBufferSize)
return false;
VerifyPacket(frame_buffer_ + packet_index, start_value + i);
}
return true;
}
WebRtc_UWord8 packet_buffer_[kPacketBufferSize];
WebRtc_UWord8 frame_buffer_[kFrameBufferSize];
WebRtcRTPHeader packet_header_;
VCMSessionInfo session_;
RTPVideoHeaderVP8* vp8_header_;
RTPFragmentationHeader fragmentation_;
WebRtcRTPHeader packet_header_;
RTPVideoHeaderVP8* vp8_header_;
RTPFragmentationHeader fragmentation_;
};
TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
class TestNalUnits : public TestSessionInfo {
protected:
virtual void SetUp() {
TestSessionInfo::SetUp();
packet_.codec = kVideoCodecH264;
}
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 TestZeroOutSeqNum : 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;
@@ -78,7 +211,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize);
delete packet;
@@ -106,7 +238,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
delete packet;
// One packet should be removed (end of partition 0).
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize,
&fragmentation_),
2*kPacketBufferSize);
@@ -116,7 +248,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
EXPECT_TRUE(VerifyPartition(1, 1, 3));
}
TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
TEST_F(TestVP8Partitions, TwoPartitionsOneLoss2) {
// Partition 0 | Partition 1
// [ 1 ] [ 2 ] | [ 3 ] [ 5 ]
packet_header_.type.Video.isFirstPacket = true;
@@ -127,7 +259,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
FillPacket(1);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0)
, kPacketBufferSize);
delete packet;
@@ -166,7 +297,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
delete packet;
// One packet should be removed (end of partition 2), 3 left.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize,
&fragmentation_),
3*kPacketBufferSize);
@@ -174,9 +305,10 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
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(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
TEST_F(TestVP8Partitions, TwoPartitionsNoLossWrap) {
// Partition 0 | Partition 1
// [ fffd ] [ fffe ] | [ ffff ] [ 0 ]
packet_header_.type.Video.isFirstPacket = true;
@@ -187,7 +319,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize);
delete packet;
@@ -226,7 +357,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
delete packet;
// No packet should be removed.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize,
&fragmentation_),
4*kPacketBufferSize);
@@ -234,9 +365,10 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
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(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
TEST_F(TestVP8Partitions, TwoPartitionsLossWrap) {
// Partition 0 | Partition 1
// [ fffd ] [ fffe ] | [ ffff ] [ 1 ]
packet_header_.type.Video.isFirstPacket = true;
@@ -247,7 +379,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize);
delete packet;
@@ -286,7 +417,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
delete packet;
// One packet should be removed from the last partition
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize,
&fragmentation_),
3*kPacketBufferSize);
@@ -294,10 +425,11 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
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(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
TEST_F(TestVP8Partitions, ThreePartitionsOneMissing) {
// Partition 1 |Partition 2 | Partition 3
// [ 1 ] [ 2 ] | | [ 5 ] | [ 6 ]
packet_header_.type.Video.isFirstPacket = true;
@@ -308,7 +440,6 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
FillPacket(1);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize);
delete packet;
@@ -347,7 +478,7 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
delete packet;
// No packet should be removed.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize,
&fragmentation_),
4*kPacketBufferSize);
@@ -355,9 +486,10 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
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(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
TEST_F(TestVP8Partitions, ThreePartitionsLossInSecond) {
// Partition 0 |Partition 1 | Partition 2
// [ 1 ] [ 2 ] | [ 4 ] [ 5 ] | [ 6 ] [ 7 ]
packet_header_.type.Video.isFirstPacket = true;
@@ -368,7 +500,6 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
FillPacket(1);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize);
delete packet;
@@ -429,7 +560,7 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
delete packet;
// 2 partitions left. 2 packets removed from second partition
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize,
&fragmentation_),
4*kPacketBufferSize);
@@ -437,9 +568,10 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
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(TestVP8MakeDecodable, AggregationOverTwoPackets) {
TEST_F(TestVP8Partitions, AggregationOverTwoPackets) {
// Partition 0 | Partition 1 | Partition 2
// [ 0 | ] [ 1 ] | [ 2 ]
packet_header_.type.Video.isFirstPacket = true;
@@ -450,7 +582,6 @@ TEST_F(TestVP8MakeDecodable, AggregationOverTwoPackets) {
FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize);
delete packet;
@@ -477,11 +608,12 @@ TEST_F(TestVP8MakeDecodable, AggregationOverTwoPackets) {
kPacketBufferSize);
delete packet;
// One packet should be removed (end of partition 0).
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
// 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
@@ -490,3 +622,338 @@ TEST_F(TestVP8MakeDecodable, AggregationOverTwoPackets) {
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(TestZeroOutSeqNum, 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_.ZeroOutSeqNum(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_.ZeroOutSeqNumHybrid(seq_num_list_,
seq_num_list_length_,
60));
SCOPED_TRACE("Calling VerifyAll");
VerifyAll(-1);
}
TEST_F(TestZeroOutSeqNum, 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_.ZeroOutSeqNum(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_.ZeroOutSeqNumHybrid(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(TestZeroOutSeqNum, 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_.ZeroOutSeqNum(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_.ZeroOutSeqNumHybrid(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(TestSessionInfo, PacketPriorBitsPacketLost) {
packet_.seqNum = 0;
packet_.codecSpecificHeader.codec = kRTPVideoH263;
packet_.bits = true;
packet_.isFirstPacket = false;
packet_.markerBit = true;
FillPacket(1);
ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0),
kPacketBufferSize);
EXPECT_EQ(0, session_.PrepareForDecode(frame_buffer_));
EXPECT_EQ(0, session_.SessionLength());
EXPECT_EQ(1, session_.packets_not_decodable());
}
TEST_F(TestSessionInfo, MiddlePacketPriorBitsPacketLost) {
packet_.codecSpecificHeader.codec = kRTPVideoH263;
packet_.bits = false;
packet_.isFirstPacket = true;
packet_.seqNum = 0;
packet_.markerBit = false;
FillPacket(2);
ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0),
kPacketBufferSize);
packet_.bits = true;
packet_.isFirstPacket = false;
packet_.seqNum += 2;
packet_.markerBit = true;
FillPacket(2);
ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0),
kPacketBufferSize);
EXPECT_EQ(2 * kPacketBufferSize, session_.PrepareForDecode(frame_buffer_));
EXPECT_EQ(2 * kPacketBufferSize, session_.SessionLength());
EXPECT_EQ(1, session_.packets_not_decodable());
}
TEST_F(TestSessionInfo, ORingReorderedBitsPackets) {
const uint8_t kEndByte = 0x07;
const uint8_t kStartByte = 0xF8;
packet_.codecSpecificHeader.codec = kRTPVideoH263;
packet_.bits = true;
packet_.isFirstPacket = false;
packet_.seqNum = 1;
packet_.markerBit = true;
FillPacket(2);
packet_buffer_[0] = kStartByte;
ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0),
kPacketBufferSize);
packet_.bits = false;
packet_.isFirstPacket = true;
packet_.seqNum = 0;
packet_.markerBit = false;
FillPacket(1);
packet_buffer_[kPacketBufferSize - 1] = kEndByte;
ASSERT_EQ(session_.InsertPacket(packet_, frame_buffer_, false, 0),
kPacketBufferSize);
EXPECT_EQ(2 * kPacketBufferSize - 1,
session_.PrepareForDecode(frame_buffer_));
EXPECT_EQ(2 * kPacketBufferSize - 1, session_.SessionLength());
EXPECT_EQ(kStartByte | kEndByte, frame_buffer_[kPacketBufferSize - 1]);
EXPECT_EQ(0, session_.packets_not_decodable());
}
} // namespace webrtc