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:
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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, ×tamp));
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
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, ×tamp));
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
}
|
||||
|
||||
// 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, ×tamp));
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
// 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, ×tamp));
|
||||
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
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, ×tamp));
|
||||
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
}
|
||||
|
||||
packet_->seqNum++;
|
||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||
&retransmitted));
|
||||
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
||||
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
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, ×tamp));
|
||||
|
||||
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, ×tamp));
|
||||
// At least two frames must be present before an incomplete can be decoded.
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
packet_->seqNum += 3;
|
||||
packet_->timestamp += 33*90*2;
|
||||
|
||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||
&retransmitted));
|
||||
|
||||
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
||||
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
jitter_buffer_->DecodeErrorMode(kNoErrors);
|
||||
|
||||
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
// 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, ×tamp));
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
|
||||
packet_->seqNum -= 2;
|
||||
packet_->markerBit = false;
|
||||
packet_->isFirstPacket = true;
|
||||
|
||||
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
|
||||
&retransmitted));
|
||||
EXPECT_TRUE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
||||
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, ×tamp));
|
||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user