Added logic for kSelectiveErrors to VCMJitterBuffer and corresponding unit tests.

R=marpan@google.com, mikhal@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/1943004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4503 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
agalusza@google.com
2013-08-08 01:12:33 +00:00
parent 676ff1ed89
commit d177c10e2d
8 changed files with 375 additions and 55 deletions

View File

@ -207,6 +207,14 @@ VCMFrameBuffer::Reset() {
VCMEncodedFrame::Reset();
}
void
VCMFrameBuffer::ClearStateIfIncomplete() {
if (_state == kStateDecodable) {
_state = kStateIncomplete;
_sessionInfo.ClearStateIfIncomplete();
}
}
// Set state of frame
void
VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state) {

View File

@ -83,6 +83,12 @@ class VCMFrameBuffer : public VCMEncodedFrame {
// them.
int NotDecodablePackets() const;
// If _state is kStateDecodable, changes it to kStateIncomplete.
// Used by the dual decoder. After the mode is changed to kNoErrors from
// kWithErrors or kSelective errors, any states that have been marked
// decodable and are not complete are marked as non-decodable.
void ClearStateIfIncomplete();
private:
void SetState(VCMFrameBufferStateEnum state); // Set state of frame

View File

@ -427,9 +427,11 @@ bool VCMJitterBuffer::CompleteSequenceWithNextFrame() {
CriticalSectionScoped cs(crit_sect_);
// Finding oldest frame ready for decoder, check sequence number and size
CleanUpOldOrEmptyFrames();
if (!decodable_frames_.empty())
return true;
if (incomplete_frames_.size() <= 1) {
if (!decodable_frames_.empty()) {
if (decodable_frames_.Front()->GetState() == kStateComplete) {
return true;
}
} else if (incomplete_frames_.size() <= 1) {
// Frame not ready to be decoded.
return true;
}
@ -447,7 +449,8 @@ bool VCMJitterBuffer::NextCompleteTimestamp(
}
CleanUpOldOrEmptyFrames();
if (decodable_frames_.empty()) {
if (decodable_frames_.empty() ||
decodable_frames_.Front()->GetState() != kStateComplete) {
const int64_t end_wait_time_ms = clock_->TimeInMilliseconds() +
max_wait_time_ms;
int64_t wait_time_ms = max_wait_time_ms;
@ -464,7 +467,8 @@ bool VCMJitterBuffer::NextCompleteTimestamp(
}
// Finding oldest frame ready for decoder.
CleanUpOldOrEmptyFrames();
if (decodable_frames_.empty()) {
if (decodable_frames_.empty() ||
decodable_frames_.Front()->GetState() != kStateComplete) {
wait_time_ms = end_wait_time_ms - clock_->TimeInMilliseconds();
} else {
break;
@ -478,7 +482,8 @@ bool VCMJitterBuffer::NextCompleteTimestamp(
// We already have a frame, reset the event.
frame_event_->Reset();
}
if (decodable_frames_.empty()) {
if (decodable_frames_.empty() ||
decodable_frames_.Front()->GetState() != kStateComplete) {
crit_sect_->Leave();
return false;
}
@ -499,14 +504,16 @@ bool VCMJitterBuffer::NextMaybeIncompleteTimestamp(uint32_t* timestamp) {
CleanUpOldOrEmptyFrames();
VCMFrameBuffer* oldest_frame = NextFrame();
if (!oldest_frame) {
if (decodable_frames_.empty()) {
return false;
}
if (decodable_frames_.empty() && incomplete_frames_.size() <= 1
VCMFrameBuffer* oldest_frame = decodable_frames_.Front();
// If we have exactly one frame in the buffer, release it only if it is
// complete. We know decodable_frames_ is not empty due to the prevoius
// check.
if (decodable_frames_.size() == 1 && incomplete_frames_.empty()
&& oldest_frame->GetState() != kStateComplete) {
// If we have only one frame in the buffer, release it only if it is
// complete.
return false;
}
// Always start with a complete key frame.
@ -749,19 +756,18 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
" size:%d type %d",
this, frame, frame->Length(), frame->FrameType());
}
// Don't let the first packet be overridden by a complete session.
ret = kCompleteSession;
// Only update return value for a JB flush indicator.
*retransmitted = (frame->GetNackCount() > 0);
CountFrame(*frame);
frame->SetCountedFrame(true);
*retransmitted = (frame->GetNackCount() > 0);
if (IsContinuous(*frame) && previous_state != kStateComplete) {
if (!first) {
incomplete_frames_.PopFrame(packet.timestamp);
if (previous_state != kStateDecodable) {
if (!first) {
incomplete_frames_.PopFrame(packet.timestamp);
}
decodable_frames_.InsertFrame(frame);
FindAndInsertContinuousFrames(*frame);
}
decodable_frames_.InsertFrame(frame);
FindAndInsertContinuousFrames(*frame);
// Signal that we have a decodable frame.
frame_event_->Set();
} else if (first) {
@ -772,6 +778,23 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
break;
}
case kDecodableSession:
assert(previous_state != kStateComplete);
*retransmitted = (frame->GetNackCount() > 0);
frame->SetCountedFrame(true);
if ((IsContinuous(*frame) || decode_error_mode_ == kWithErrors)
&& previous_state != kStateDecodable) {
incomplete_frames_.PopFrame(packet.timestamp);
decodable_frames_.InsertFrame(frame);
FindAndInsertContinuousFrames(*frame);
// Signal that we have a decodable frame.
frame_event_->Set();
} else if (first) {
ret = kFirstPacket;
incomplete_frames_.InsertFrame(frame);
}
// Signal that we have a received packet.
packet_event_->Set();
break;
case kIncomplete: {
// No point in storing empty continuous frames.
if (frame->GetState() == kStateEmpty &&
@ -780,6 +803,9 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
frame->Reset();
frame = NULL;
ret = kNoError;
} else if (previous_state == kStateDecodable) {
decodable_frames_.PopFrame(packet.timestamp);
incomplete_frames_.InsertFrame(frame);
} else if (first) {
ret = kFirstPacket;
incomplete_frames_.InsertFrame(frame);
@ -957,9 +983,10 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
return NULL;
}
if (last_decoded_state_.in_initial_state()) {
const bool first_frame_is_key = NextFrame() &&
NextFrame()->FrameType() == kVideoFrameKey &&
NextFrame()->HaveFirstPacket();
VCMFrameBuffer* next_frame = NextFrame();
const bool first_frame_is_key = next_frame &&
next_frame->FrameType() == kVideoFrameKey &&
next_frame->HaveFirstPacket();
if (!first_frame_is_key) {
bool have_non_empty_frame = decodable_frames_.end() != find_if(
decodable_frames_.begin(), decodable_frames_.end(),
@ -1015,6 +1042,39 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
return &nack_seq_nums_[0];
}
void VCMJitterBuffer::DecodeErrorMode(VCMDecodeErrorMode error_mode) {
// If we are not moving from kWithErrors or KSelectiveErrors to kNoErrors,
// set decode_error_mode_ and apply new error mode only to new packets.
// Also no need for further processing if we have no old, previously
// decodable (and potentially incomplete) frames.
if (decode_error_mode_ == kNoErrors || error_mode != kNoErrors ||
decodable_frames_.empty()) {
decode_error_mode_ = error_mode;
return;
} else {
// We just went from kWithErrors or kSelectiveErrors to kNoErrors. Make
// sure no incomplete frames are marked decodable.
// Begin by skipping over all complete frames.
FrameList::const_iterator it = decodable_frames_.begin();
VCMFrameBuffer* frame;
for (; it != decodable_frames_.end(); ++it) {
if (it->second->GetState() != kStateComplete) {
break;
}
}
// Continue from first incomplete and previously decodable frame and move
// subsequent frames to incomplete_frames_.
while (it != decodable_frames_.end()) {
frame = it->second;
++it;
frame = decodable_frames_.PopFrame(frame->TimeStamp());
frame->ClearStateIfIncomplete();
incomplete_frames_.InsertFrame(frame);
}
decode_error_mode_ = error_mode;
}
}
VCMFrameBuffer* VCMJitterBuffer::NextFrame() const {
if (!decodable_frames_.empty())
return decodable_frames_.Front();

View File

@ -175,10 +175,11 @@ class VCMJitterBuffer {
// Returns a list of the sequence numbers currently missing.
uint16_t* GetNackList(uint16_t* nack_list_size, bool* request_key_frame);
// Enable/disable decoding with errors.
// TODO(agalusza): Add logic for handling kSelectiveErrors.
void DecodeErrorMode(VCMDecodeErrorMode error_mode)
{decode_error_mode_ = error_mode;}
// Set decode error mode. Setting kNoErrors will have immediate effect.
// Setting kWithErrors and kSelectiveErrors will take full effect once the
// existing incomplete frames leave the JB or have a packet added (as that
// would cause their state to be reevlauated).
void DecodeErrorMode(VCMDecodeErrorMode error_mode);
int64_t LastDecodedTimestamp() const;
VCMDecodeErrorMode decode_error_mode() const {return decode_error_mode_;}
@ -245,6 +246,8 @@ class VCMJitterBuffer {
bool RecycleFramesUntilKeyFrame();
// Updates the frame statistics.
// Counts only complete frames, so decodable incomplete frames will not be
// counted.
void CountFrame(const VCMFrameBuffer& frame);
// Update rolling average of packets per frame.

View File

@ -69,6 +69,7 @@ class TestBasicJitterBuffer : public ::testing::Test {
VCMEncodedFrame* frame = jitter_buffer_->ExtractAndSetDecode(timestamp);
return frame;
}
void CheckOutFrame(VCMEncodedFrame* frame_out,
unsigned int size,
bool startCode) {
@ -242,6 +243,13 @@ TEST_F(TestBasicJitterBuffer, StopRunning) {
EXPECT_TRUE(NULL == DecodeCompleteFrame());
EXPECT_TRUE(NULL == DecodeIncompleteFrame());
jitter_buffer_->Start();
// Allow selective errors.
jitter_buffer_->DecodeErrorMode(kSelectiveErrors);
// No packets inserted.
EXPECT_TRUE(NULL == DecodeCompleteFrame());
EXPECT_TRUE(NULL == DecodeIncompleteFrame());
// Allow decoding with errors.
jitter_buffer_->DecodeErrorMode(kWithErrors);
@ -559,12 +567,168 @@ TEST_F(TestBasicJitterBuffer, H264InsertStartCode) {
&retransmitted));
frame_out = DecodeCompleteFrame();
CheckOutFrame(frame_out, size_ * 2 + 4 * 2, true);
EXPECT_EQ(kVideoFrameKey, frame_out->FrameType());
}
TEST_F(TestBasicJitterBuffer, PacketLossWithSelectiveErrorrs) {
jitter_buffer_->DecodeErrorMode(kSelectiveErrors);
// Always start with a key frame. Use 10 packets to test Decodable State
// boundaries.
packet_->frameType = kVideoFrameKey;
packet_->isFirstPacket = true;
packet_->markerBit = false;
packet_->seqNum = seq_num_;
packet_->timestamp = timestamp_;
bool retransmitted = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
uint32_t timestamp = 0;
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
packet_->isFirstPacket = false;
for (int i = 1; i < 9; ++i) {
packet_->seqNum++;
EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
}
// last packet
packet_->markerBit = true;
packet_->seqNum++;
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
VCMEncodedFrame* frame_out = DecodeCompleteFrame();
CheckOutFrame(frame_out, 10 * size_, false);
EXPECT_EQ(kVideoFrameKey, frame_out->FrameType());
// An incomplete frame can only be decoded once a subsequent frame has begun
// to arrive. Insert packet in distant frame for this purpose.
packet_->frameType = kVideoFrameDelta;
packet_->isFirstPacket = true;
packet_->markerBit = false;
packet_->seqNum += 100;
packet_->timestamp += 33*90*8;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
// Insert second frame
packet_->seqNum -= 99;
packet_->timestamp -= 33*90*7;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
packet_->isFirstPacket = false;
for (int i = 1; i < 8; ++i) {
packet_->seqNum++;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
}
packet_->seqNum++;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
frame_out = DecodeIncompleteFrame();
ASSERT_FALSE(NULL == frame_out);
CheckOutFrame(frame_out, 9 * size_, false);
EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType());
packet_->markerBit = true;
packet_->seqNum++;
EXPECT_EQ(kOldPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
}
TEST_F(TestBasicJitterBuffer, PacketLossStateChangedFromErrorsToNone) {
jitter_buffer_->DecodeErrorMode(kWithErrors);
// First frame is always a key frame.
packet_->frameType = kVideoFrameKey;
packet_->isFirstPacket = true;
packet_->markerBit = true;
packet_->seqNum = seq_num_;
packet_->timestamp = timestamp_;
bool retransmitted = false;
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
uint32_t timestamp = 0;
EXPECT_TRUE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
VCMEncodedFrame* frame_out = DecodeCompleteFrame();
CheckOutFrame(frame_out, size_, false);
EXPECT_EQ(kVideoFrameKey, frame_out->FrameType());
packet_->frameType = kVideoFrameDelta;
packet_->isFirstPacket = false;
packet_->markerBit = false;
packet_->seqNum += 2;
packet_->timestamp += 33*90;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
// At least two frames must be present before an incomplete can be decoded.
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
packet_->seqNum += 3;
packet_->timestamp += 33*90*2;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
jitter_buffer_->DecodeErrorMode(kNoErrors);
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
// Complete the next frame.
packet_->seqNum -= 2;
packet_->markerBit = true;
packet_->timestamp -= 33*90*2;
EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
packet_->seqNum -= 2;
packet_->markerBit = false;
packet_->isFirstPacket = true;
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_TRUE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
frame_out = DecodeCompleteFrame();
ASSERT_FALSE(frame_out == NULL);
CheckOutFrame(frame_out, 3 * size_, false);
EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType());
EXPECT_EQ(packet_->timestamp, frame_out->TimeStamp());
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &timestamp));
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(&timestamp));
}
TEST_F(TestBasicJitterBuffer, PacketLoss) {
// Verify missing packets statistics and not decodable packets statistics.
// Insert 10 frames consisting of 4 packets and remove one from all of them.
@ -584,8 +748,8 @@ TEST_F(TestBasicJitterBuffer, PacketLoss) {
packet_->completeNALU = kNaluStart;
bool retransmitted = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
for (int i = 0; i < 11; ++i) {
webrtc::FrameType frametype = kVideoFrameDelta;
seq_num_++;
@ -597,8 +761,8 @@ TEST_F(TestBasicJitterBuffer, PacketLoss) {
packet_->timestamp = timestamp_;
packet_->completeNALU = kNaluStart;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
VCMEncodedFrame* frame_out = DecodeCompleteFrame();
@ -1134,8 +1298,8 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->markerBit = false;
bool retransmitted = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
seq_num_ += 2; // Skip one packet
packet_->seqNum = seq_num_;
@ -1145,7 +1309,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->markerBit = false;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
seq_num_++;
packet_->seqNum = seq_num_;
@ -1155,14 +1319,14 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->markerBit = false;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
seq_num_++;
packet_->seqNum = seq_num_;
packet_->completeNALU = kNaluComplete;
packet_->markerBit = true; // Last packet
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
// The JB will only output (incomplete) frames if a packet belonging to a
// subsequent frame was already inserted. Insert one packet of a subsequent
// frame. place high timestamp so the JB would always have a next frame
@ -1175,8 +1339,8 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->completeNALU = kNaluStart;
packet_->markerBit = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
VCMEncodedFrame* frame_out = DecodeIncompleteFrame();
@ -1199,8 +1363,8 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->markerBit = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
insertedLength += packet_->sizeBytes; // This packet should be decoded.
seq_num_--;
@ -1211,7 +1375,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->completeNALU = kNaluStart;
packet_->markerBit = false;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
insertedLength += packet_->sizeBytes; // This packet should be decoded.
seq_num_ += 3; // One packet drop
@ -1222,10 +1386,10 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->completeNALU = kNaluComplete;
packet_->markerBit = false;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
insertedLength += packet_->sizeBytes; // This packet should be decoded.
seq_num_ += 1;
seq_num_++;
packet_->seqNum = seq_num_;
packet_->timestamp = timestamp_;
packet_->frameType = kVideoFrameKey;
@ -1233,7 +1397,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->completeNALU = kNaluStart;
packet_->markerBit = false;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
// This packet should be decoded since it's the beginning of a NAL.
insertedLength += packet_->sizeBytes;
@ -1245,7 +1409,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->completeNALU = kNaluEnd;
packet_->markerBit = true;
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
&retransmitted));
// This packet should not be decoded because it is an incomplete NAL if it
// is the last.
frame_out = DecodeIncompleteFrame();
@ -1255,7 +1419,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
// Test to insert empty packet.
seq_num_ += 1;
seq_num_++;
timestamp_ += 33 * 90;
VCMPacket emptypacket(data_, 0, seq_num_, timestamp_, true);
emptypacket.seqNum = seq_num_;
@ -1276,7 +1440,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
// Test that a frame can include an empty packet.
seq_num_ += 1;
seq_num_++;
timestamp_ += 33 * 90;
packet_->seqNum = seq_num_;
@ -1286,10 +1450,10 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
packet_->completeNALU = kNaluComplete;
packet_->markerBit = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
seq_num_ += 1;
seq_num_++;
emptypacket.seqNum = seq_num_;
emptypacket.timestamp = timestamp_;
emptypacket.frameType = kVideoFrameKey;
@ -1327,8 +1491,8 @@ TEST_F(TestBasicJitterBuffer, NextFrameWhenIncomplete) {
packet_->markerBit = false;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
frame_out = DecodeIncompleteFrame();
EXPECT_TRUE(frame_out == NULL);
@ -1338,8 +1502,8 @@ TEST_F(TestBasicJitterBuffer, NextFrameWhenIncomplete) {
packet_->isFirstPacket = true;
EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
&retransmitted));
frame_out = DecodeIncompleteFrame();
@ -1694,7 +1858,7 @@ TEST_F(TestJitterBufferNack, NormalOperation) {
stream_generator_->GenerateFrame(kVideoFrameKey, 100, 0,
clock_->TimeInMilliseconds());
clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs);
EXPECT_EQ(kFirstPacket, InsertPacketAndPop(0));
EXPECT_EQ(kDecodableSession, InsertPacketAndPop(0));
// Verify that the frame is incomplete.
EXPECT_FALSE(DecodeCompleteFrame());
while (stream_generator_->PacketsRemaining() > 1) {

View File

@ -375,6 +375,12 @@ int VCMSessionInfo::MakeDecodable() {
return return_length;
}
void VCMSessionInfo::ClearStateIfIncomplete() {
// We don't need to check for completeness first because the two are
// orthogonal. If complete_ is true, decodable_ is irrelevant.
decodable_ = false;
}
bool
VCMSessionInfo::HaveFirstPacket() const {
return !packets_.empty() && packets_.front().isFirstPacket;

View File

@ -65,6 +65,13 @@ class VCMSessionInfo {
// memory to remove any empty space.
// Returns the number of bytes deleted from the session.
int MakeDecodable();
// Sets decodable_ to false.
// Used by the dual decoder. After the mode is changed to kNoErrors from
// kWithErrors or kSelective errors, any states that have been marked
// decodable and are not complete are marked as non-decodable.
void ClearStateIfIncomplete();
int SessionLength() const;
int NumPackets() const;
bool HaveFirstPacket() const;

View File

@ -227,6 +227,71 @@ TEST_F(TestSessionInfo, NormalOperation) {
}
}
TEST_F(TestSessionInfo, ErrorsEqualDecodableState) {
packet_.seqNum = 0xFFFF;
packet_.isFirstPacket = false;
packet_.markerBit = false;
FillPacket(3);
ASSERT_EQ(session_.InsertPacket(packet_,
frame_buffer_,
kWithErrors,
frame_data),
packet_buffer_size());
EXPECT_EQ(0, session_.packets_not_decodable());
EXPECT_TRUE(session_.decodable());
}
TEST_F(TestSessionInfo, SelectiveDecodableState) {
packet_.seqNum = 0xFFFF;
packet_.isFirstPacket = false;
packet_.markerBit = false;
FillPacket(1);
frame_data.rolling_average_packets_per_frame = 11;
frame_data.rtt_ms = 150;
ASSERT_EQ(session_.InsertPacket(packet_,
frame_buffer_,
kSelectiveErrors,
frame_data),
packet_buffer_size());
EXPECT_EQ(0, session_.packets_not_decodable());
EXPECT_FALSE(session_.decodable());
packet_.seqNum -= 1;
FillPacket(0);
packet_.isFirstPacket = true;
ASSERT_EQ(session_.InsertPacket(packet_,
frame_buffer_,
kSelectiveErrors,
frame_data),
packet_buffer_size());
EXPECT_EQ(0, session_.packets_not_decodable());
EXPECT_TRUE(session_.decodable());
packet_.isFirstPacket = false;
packet_.seqNum += 1;
for (int i = 2; i < 8; ++i) {
packet_.seqNum += 1;
FillPacket(i);
ASSERT_EQ(session_.InsertPacket(packet_,
frame_buffer_,
kSelectiveErrors,
frame_data),
packet_buffer_size());
EXPECT_EQ(0, session_.packets_not_decodable());
EXPECT_TRUE(session_.decodable());
}
packet_.seqNum += 1;
FillPacket(8);
ASSERT_EQ(session_.InsertPacket(packet_,
frame_buffer_,
kSelectiveErrors,
frame_data),
packet_buffer_size());
EXPECT_EQ(0, session_.packets_not_decodable());
EXPECT_TRUE(session_.decodable());
}
TEST_F(TestVP8Partitions, TwoPartitionsOneLoss) {
// Partition 0 | Partition 1
// [ 0 ] [ 2 ] | [ 3 ]
@ -943,4 +1008,5 @@ TEST_F(TestNalUnits, ReorderWrapLosses) {
EXPECT_EQ(0, session_.SessionLength());
EXPECT_EQ(2, session_.packets_not_decodable());
}
} // namespace webrtc