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

View File

@@ -25,7 +25,7 @@ enum VCMJitterBufferEnum
{ {
kMaxConsecutiveOldFrames = 60, kMaxConsecutiveOldFrames = 60,
kMaxConsecutiveOldPackets = 300, kMaxConsecutiveOldPackets = 300,
kMaxPacketsInJitterBuffer = 800, kMaxPacketsInSession = 800,
kBufferIncStepSizeBytes = 30000, // >20 packets kBufferIncStepSizeBytes = 30000, // >20 packets
kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte 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_ #ifndef WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
#define WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_ #define WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
#include "typedefs.h" #include <cstddef>
#include "module_common_types.h" #include <list>
#include "packet.h"
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 class VCMSessionInfo {
{ public:
public: VCMSessionInfo();
VCMSessionInfo();
virtual ~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, // Hybrid version: Zero out seq num for NACK list
const WebRtc_UWord8* prev_buffer_address); // 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, // Builds fragmentation headers for VP8, each fragment being a decodable
WebRtc_Word32 numberOfSeqNum); // VP8 partition. Returns the total number of bytes which are decodable. Is
// Hybrid version: Zero out seq num for NACK list // used instead of MakeDecodable for VP8.
// Selectively NACK packets. int BuildVP8FragmentationHeader(uint8_t* frame_buffer,
WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list, int frame_buffer_length,
WebRtc_Word32 numberOfSeqNum, RTPFragmentationHeader* fragmentation);
WebRtc_UWord32 rttMs);
virtual void Reset();
WebRtc_Word64 InsertPacket(const VCMPacket& packet, // Makes the frame decodable. I.e., only contain decodable NALUs. All
WebRtc_UWord8* ptrStartOfLayer, // non-decodable NALUs will be deleted and packets will be moved to in
bool enableDecodableState, // memory to remove any empty space.
WebRtc_UWord32 rttMs); // Returns the number of bytes deleted from the session.
WebRtc_Word32 InformOfEmptyPacket(const WebRtc_UWord16 seqNum); 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; // Returns highest sequence number, media or empty.
virtual bool IsSessionDecodable() const; 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 // The number of packets discarded because the decoder can't make use of
// VP8 partition. Returns the total number of bytes which are decodable. Is // them.
// used instead of MakeDecodable for VP8. int packets_not_decodable() const;
int BuildVP8FragmentationHeader(WebRtc_UWord8* frame_buffer,
int frame_buffer_length,
RTPFragmentationHeader* fragmentation);
// Makes the frame decodable. I.e., only contain decodable NALUs. All private:
// non-decodable NALUs will be deleted and packets will be moved to in enum { kMaxVP8Partitions = 9 };
// memory to remove any empty space.
// Returns the number of bytes deleted from the session.
WebRtc_UWord32 MakeDecodable(WebRtc_UWord8* ptrStartOfLayer);
WebRtc_UWord32 GetSessionLength(); typedef std::list<VCMPacket> PacketList;
bool HaveLastPacket() const; typedef PacketList::iterator PacketIterator;
bool IsRetransmitted() const; typedef PacketList::const_iterator PacketIteratorConst;
webrtc::FrameType FrameType() const { return _frameType; } 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; // When enabled, determine if session is decodable, i.e. incomplete but
// returns highest seqNum, media or empty // would be sent to the decoder.
WebRtc_Word32 GetHighSeqNum() const; void UpdateDecodableSession(int rtt_ms);
int PictureId() const;
int TemporalId() const;
int Tl0PicId() const;
bool NonReference() const;
WebRtc_UWord32 PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, // If this session has been NACKed by the jitter buffer.
VideoCodecType codec); bool session_nack_;
bool complete_;
void SetPreviousFrameLoss() { _previousFrameLoss = true; } bool decodable_;
bool PreviousFrameLoss() const { return _previousFrameLoss; } webrtc::FrameType frame_type_;
bool previous_frame_loss_;
// The number of packets discarded because the decoder can't make use of // Packets in this frame.
// them. PacketList packets_;
int NotDecodablePackets() const; int empty_seq_num_low_;
int empty_seq_num_high_;
private: // Number of packets discarded because the decoder can't use them.
// Finds the packet index of the beginning of the next VP8 partition. If int packets_not_decodable_;
// 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;
}; };
} // 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 <string.h>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "module_common_types.h" #include "modules/interface/module_common_types.h"
#include "packet.h" #include "modules/video_coding/main/source/packet.h"
#include "session_info.h" #include "modules/video_coding/main/source/session_info.h"
using webrtc::RTPFragmentationHeader; namespace webrtc {
using webrtc::RTPVideoHeaderVP8;
using webrtc::VCMPacket;
using webrtc::VCMSessionInfo;
using webrtc::WebRtcRTPHeader;
enum { kPacketBufferSize = 10 }; class TestSessionInfo : public ::testing::Test {
enum { kFrameBufferSize = 10*kPacketBufferSize };
class TestVP8MakeDecodable : public ::testing::Test {
protected: protected:
enum { kPacketBufferSize = 10 };
enum { kFrameBufferSize = 10 * kPacketBufferSize };
virtual void SetUp() { virtual void SetUp() {
memset(packet_buffer_, 0, kPacketBufferSize); memset(packet_buffer_, 0, kPacketBufferSize);
memset(frame_buffer_, 0, kFrameBufferSize); memset(frame_buffer_, 0, kFrameBufferSize);
vp8_header_ = &packet_header_.type.Video.codecHeader.VP8; session_.Reset();
packet_header_.frameType = webrtc::kVideoFrameDelta; packet_.Reset();
packet_header_.type.Video.codec = webrtc::kRTPVideoVP8; packet_.frameType = kVideoFrameDelta;
vp8_header_->InitRTPVideoHeaderVP8(); packet_.sizeBytes = kPacketBufferSize;
fragmentation_.VerifyAndAllocateFragmentationHeader( packet_.dataPtr = packet_buffer_;
webrtc::kMaxVP8Partitions); 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) for (int i = 0; i < kPacketBufferSize; ++i)
packet_buffer_[i] = start_value + 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, bool VerifyPartition(int partition_id,
int packets_expected, int packets_expected,
int start_value) { 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]); fragmentation_.fragmentationLength[partition_id]);
for (int i = 0; i < packets_expected; ++i) { for (int i = 0; i < packets_expected; ++i) {
int packet_index = fragmentation_.fragmentationOffset[partition_id] + int packet_index = fragmentation_.fragmentationOffset[partition_id] +
i * kPacketBufferSize; i * kPacketBufferSize;
for (int j = 0; j < kPacketBufferSize; ++j) { if (packet_index + kPacketBufferSize > kFrameBufferSize)
if (packet_index + j > kFrameBufferSize) return false;
return false; VerifyPacket(frame_buffer_ + packet_index, start_value + i);
EXPECT_EQ(start_value + i + j, frame_buffer_[packet_index + j]);
}
} }
return true; return true;
} }
WebRtc_UWord8 packet_buffer_[kPacketBufferSize]; WebRtcRTPHeader packet_header_;
WebRtc_UWord8 frame_buffer_[kFrameBufferSize]; RTPVideoHeaderVP8* vp8_header_;
WebRtcRTPHeader packet_header_; RTPFragmentationHeader fragmentation_;
VCMSessionInfo session_;
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 // Partition 0 | Partition 1
// [ 0 ] [ 2 ] | [ 3 ] // [ 0 ] [ 2 ] | [ 3 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -78,7 +211,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
FillPacket(0); FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
@@ -106,7 +238,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
delete packet; delete packet;
// One packet should be removed (end of partition 0). // One packet should be removed (end of partition 0).
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
2*kPacketBufferSize); 2*kPacketBufferSize);
@@ -116,7 +248,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss) {
EXPECT_TRUE(VerifyPartition(1, 1, 3)); EXPECT_TRUE(VerifyPartition(1, 1, 3));
} }
TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) { TEST_F(TestVP8Partitions, TwoPartitionsOneLoss2) {
// Partition 0 | Partition 1 // Partition 0 | Partition 1
// [ 1 ] [ 2 ] | [ 3 ] [ 5 ] // [ 1 ] [ 2 ] | [ 3 ] [ 5 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -127,7 +259,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
FillPacket(1); FillPacket(1);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0) ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0)
, kPacketBufferSize); , kPacketBufferSize);
delete packet; delete packet;
@@ -166,7 +297,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
delete packet; delete packet;
// One packet should be removed (end of partition 2), 3 left. // One packet should be removed (end of partition 2), 3 left.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
3*kPacketBufferSize); 3*kPacketBufferSize);
@@ -174,9 +305,10 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsOneLoss2) {
EXPECT_TRUE(VerifyPartition(0, 2, 1)); EXPECT_TRUE(VerifyPartition(0, 2, 1));
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(1, 1, 3)); 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 // Partition 0 | Partition 1
// [ fffd ] [ fffe ] | [ ffff ] [ 0 ] // [ fffd ] [ fffe ] | [ ffff ] [ 0 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -187,7 +319,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
FillPacket(0); FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
@@ -226,7 +357,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
delete packet; delete packet;
// No packet should be removed. // No packet should be removed.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
4*kPacketBufferSize); 4*kPacketBufferSize);
@@ -234,9 +365,10 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsNoLossWrap) {
EXPECT_TRUE(VerifyPartition(0, 2, 0)); EXPECT_TRUE(VerifyPartition(0, 2, 0));
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(1, 2, 2)); 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 // Partition 0 | Partition 1
// [ fffd ] [ fffe ] | [ ffff ] [ 1 ] // [ fffd ] [ fffe ] | [ ffff ] [ 1 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -247,7 +379,6 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
FillPacket(0); FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
@@ -286,7 +417,7 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
delete packet; delete packet;
// One packet should be removed from the last partition // One packet should be removed from the last partition
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
3*kPacketBufferSize); 3*kPacketBufferSize);
@@ -294,10 +425,11 @@ TEST_F(TestVP8MakeDecodable, TwoPartitionsLossWrap) {
EXPECT_TRUE(VerifyPartition(0, 2, 0)); EXPECT_TRUE(VerifyPartition(0, 2, 0));
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(1, 1, 2)); 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 // Partition 1 |Partition 2 | Partition 3
// [ 1 ] [ 2 ] | | [ 5 ] | [ 6 ] // [ 1 ] [ 2 ] | | [ 5 ] | [ 6 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -308,7 +440,6 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
FillPacket(1); FillPacket(1);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
@@ -347,7 +478,7 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
delete packet; delete packet;
// No packet should be removed. // No packet should be removed.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
4*kPacketBufferSize); 4*kPacketBufferSize);
@@ -355,9 +486,10 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsOneMissing) {
EXPECT_TRUE(VerifyPartition(0, 2, 1)); EXPECT_TRUE(VerifyPartition(0, 2, 1));
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(2, 2, 5)); 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 // Partition 0 |Partition 1 | Partition 2
// [ 1 ] [ 2 ] | [ 4 ] [ 5 ] | [ 6 ] [ 7 ] // [ 1 ] [ 2 ] | [ 4 ] [ 5 ] | [ 6 ] [ 7 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -368,7 +500,6 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
FillPacket(1); FillPacket(1);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
@@ -429,7 +560,7 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
delete packet; delete packet;
// 2 partitions left. 2 packets removed from second partition // 2 partitions left. 2 packets removed from second partition
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
4*kPacketBufferSize); 4*kPacketBufferSize);
@@ -437,9 +568,10 @@ TEST_F(TestVP8MakeDecodable, ThreePartitionsLossInSecond) {
EXPECT_TRUE(VerifyPartition(0, 2, 1)); EXPECT_TRUE(VerifyPartition(0, 2, 1));
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(2, 2, 6)); 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 // Partition 0 | Partition 1 | Partition 2
// [ 0 | ] [ 1 ] | [ 2 ] // [ 0 | ] [ 1 ] | [ 2 ]
packet_header_.type.Video.isFirstPacket = true; packet_header_.type.Video.isFirstPacket = true;
@@ -450,7 +582,6 @@ TEST_F(TestVP8MakeDecodable, AggregationOverTwoPackets) {
FillPacket(0); FillPacket(0);
VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize, VCMPacket* packet = new VCMPacket(packet_buffer_, kPacketBufferSize,
packet_header_); packet_header_);
session_.SetStartSeqNumber(packet_header_.header.sequenceNumber);
ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0), ASSERT_EQ(session_.InsertPacket(*packet, frame_buffer_, false, 0),
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
@@ -477,11 +608,12 @@ TEST_F(TestVP8MakeDecodable, AggregationOverTwoPackets) {
kPacketBufferSize); kPacketBufferSize);
delete packet; delete packet;
// One packet should be removed (end of partition 0). // No packets removed.
ASSERT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_, EXPECT_EQ(session_.BuildVP8FragmentationHeader(frame_buffer_,
kFrameBufferSize, kFrameBufferSize,
&fragmentation_), &fragmentation_),
3*kPacketBufferSize); 3*kPacketBufferSize);
EXPECT_EQ(0, session_.packets_not_decodable());
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(0, 2, 0)); EXPECT_TRUE(VerifyPartition(0, 2, 0));
// This partition is aggregated in partition 0 // This partition is aggregated in partition 0
@@ -490,3 +622,338 @@ TEST_F(TestVP8MakeDecodable, AggregationOverTwoPackets) {
SCOPED_TRACE("Calling VerifyPartition"); SCOPED_TRACE("Calling VerifyPartition");
EXPECT_TRUE(VerifyPartition(2, 1, 2)); 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

View File

@@ -1868,7 +1868,7 @@ int JitterBufferTest(CmdArgs& args)
TEST(incomingFrameType == kVideoFrameDelta); TEST(incomingFrameType == kVideoFrameDelta);
loop++; loop++;
} while (loop < kMaxPacketsInJitterBuffer); } while (loop < kMaxPacketsInSession);
// Max number of packets inserted // Max number of packets inserted