Don't force cont' when enabling kWithErrors
BUG= R=pbos@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2047004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4669 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -86,7 +86,7 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
int64_t timeInMs,
|
int64_t timeInMs,
|
||||||
VCMDecodeErrorMode decode_error_mode,
|
VCMDecodeErrorMode decode_error_mode,
|
||||||
const FrameData& frame_data) {
|
const FrameData& frame_data) {
|
||||||
// is this packet part of this frame
|
// Is this packet part of this frame?
|
||||||
if (TimeStamp() && (TimeStamp() != packet.timestamp)) {
|
if (TimeStamp() && (TimeStamp() != packet.timestamp)) {
|
||||||
return kTimeStampError;
|
return kTimeStampError;
|
||||||
}
|
}
|
||||||
@ -209,14 +209,6 @@ VCMFrameBuffer::Reset() {
|
|||||||
VCMEncodedFrame::Reset();
|
VCMEncodedFrame::Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
VCMFrameBuffer::SetNotDecodableIfIncomplete() {
|
|
||||||
if (_state == kStateDecodable) {
|
|
||||||
_state = kStateIncomplete;
|
|
||||||
_sessionInfo.SetNotDecodableIfIncomplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set state of frame
|
// Set state of frame
|
||||||
void
|
void
|
||||||
VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state) {
|
VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state) {
|
||||||
|
@ -79,11 +79,9 @@ class VCMFrameBuffer : public VCMEncodedFrame {
|
|||||||
|
|
||||||
int32_t ExtractFromStorage(const EncodedVideoData& frameFromStorage);
|
int32_t ExtractFromStorage(const EncodedVideoData& frameFromStorage);
|
||||||
|
|
||||||
// If _state is kStateDecodable, changes it to kStateIncomplete.
|
// The number of packets discarded because the decoder can't make use of
|
||||||
// Used by the dual decoder. After the mode is changed to kNoErrors from
|
// them.
|
||||||
// kWithErrors or kSelective errors, any states that have been marked
|
int NotDecodablePackets() const;
|
||||||
// decodable and are not complete are marked as non-decodable.
|
|
||||||
void SetNotDecodableIfIncomplete();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetState(VCMFrameBufferStateEnum state); // Set state of frame
|
void SetState(VCMFrameBufferStateEnum state); // Set state of frame
|
||||||
|
@ -603,6 +603,7 @@ VCMFrameBufferEnum VCMJitterBuffer::GetFrame(const VCMPacket& packet,
|
|||||||
*frame = decodable_frames_.FindFrame(packet.timestamp);
|
*frame = decodable_frames_.FindFrame(packet.timestamp);
|
||||||
if (*frame)
|
if (*frame)
|
||||||
return kNoError;
|
return kNoError;
|
||||||
|
|
||||||
// No match, return empty frame.
|
// No match, return empty frame.
|
||||||
*frame = GetEmptyFrame();
|
*frame = GetEmptyFrame();
|
||||||
VCMFrameBufferEnum ret = kNoError;
|
VCMFrameBufferEnum ret = kNoError;
|
||||||
@ -633,9 +634,6 @@ int64_t VCMJitterBuffer::LastPacketTime(const VCMEncodedFrame* frame,
|
|||||||
VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
||||||
bool* retransmitted) {
|
bool* retransmitted) {
|
||||||
CriticalSectionScoped cs(crit_sect_);
|
CriticalSectionScoped cs(crit_sect_);
|
||||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
||||||
VCMFrameBufferEnum buffer_return = kSizeError;
|
|
||||||
VCMFrameBufferEnum ret = kSizeError;
|
|
||||||
|
|
||||||
VCMFrameBuffer* frame = NULL;
|
VCMFrameBuffer* frame = NULL;
|
||||||
const VCMFrameBufferEnum error = GetFrame(packet, &frame);
|
const VCMFrameBufferEnum error = GetFrame(packet, &frame);
|
||||||
@ -643,19 +641,20 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are keeping track of the first seq num, the latest seq num and
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
|
// We are keeping track of the first and latest seq numbers, and
|
||||||
// the number of wraps to be able to calculate how many packets we expect.
|
// the number of wraps to be able to calculate how many packets we expect.
|
||||||
if (first_packet_since_reset_) {
|
if (first_packet_since_reset_) {
|
||||||
// Now it's time to start estimating jitter
|
// Now it's time to start estimating jitter
|
||||||
// reset the delay estimate.
|
// reset the delay estimate.
|
||||||
inter_frame_delay_.Reset(clock_->TimeInMilliseconds());
|
inter_frame_delay_.Reset(now_ms);
|
||||||
}
|
}
|
||||||
if (last_decoded_state_.IsOldPacket(&packet)) {
|
if (last_decoded_state_.IsOldPacket(&packet)) {
|
||||||
// This packet belongs to an old, already decoded frame, we want to update
|
// This packet belongs to an old, already decoded frame, we want to update
|
||||||
// the last decoded sequence number.
|
// the last decoded sequence number.
|
||||||
last_decoded_state_.UpdateOldPacket(&packet);
|
last_decoded_state_.UpdateOldPacket(&packet);
|
||||||
drop_count_++;
|
drop_count_++;
|
||||||
// Flush() if this happens consistently.
|
// Flush if this happens consistently.
|
||||||
num_consecutive_old_frames_++;
|
num_consecutive_old_frames_++;
|
||||||
if (num_consecutive_old_frames_ > kMaxConsecutiveOldFrames) {
|
if (num_consecutive_old_frames_ > kMaxConsecutiveOldFrames) {
|
||||||
Flush();
|
Flush();
|
||||||
@ -663,6 +662,7 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
}
|
}
|
||||||
return kNoError;
|
return kNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_consecutive_old_frames_ = 0;
|
num_consecutive_old_frames_ = 0;
|
||||||
|
|
||||||
// Empty packets may bias the jitter estimate (lacking size component),
|
// Empty packets may bias the jitter estimate (lacking size component),
|
||||||
@ -688,22 +688,18 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
// Check for first packet. High sequence number will be -1 if neither an empty
|
// Check for first packet. High sequence number will be -1 if neither an empty
|
||||||
// packet nor a media packet has been inserted.
|
// packet nor a media packet has been inserted.
|
||||||
bool first = (frame->GetHighSeqNum() == -1);
|
bool first = (frame->GetHighSeqNum() == -1);
|
||||||
// When in Hybrid mode, we allow for a decodable state
|
|
||||||
// Note: Under current version, a decodable frame will never be
|
|
||||||
// triggered, as the body of the function is empty.
|
|
||||||
// TODO(mikhal): Update when decodable is enabled.
|
|
||||||
FrameData frame_data;
|
FrameData frame_data;
|
||||||
frame_data.rtt_ms = rtt_ms_;
|
frame_data.rtt_ms = rtt_ms_;
|
||||||
frame_data.rolling_average_packets_per_frame = average_packets_per_frame_;
|
frame_data.rolling_average_packets_per_frame = average_packets_per_frame_;
|
||||||
buffer_return = frame->InsertPacket(packet,
|
VCMFrameBufferEnum buffer_return = frame->InsertPacket(packet,
|
||||||
now_ms,
|
now_ms,
|
||||||
decode_error_mode_,
|
decode_error_mode_,
|
||||||
frame_data);
|
frame_data);
|
||||||
if (!frame->GetCountedFrame()) {
|
if (!frame->GetCountedFrame()) {
|
||||||
TRACE_EVENT_ASYNC_BEGIN1("webrtc", "Video", frame->TimeStamp(),
|
TRACE_EVENT_ASYNC_BEGIN1("webrtc", "Video", frame->TimeStamp(),
|
||||||
"timestamp", frame->TimeStamp());
|
"timestamp", frame->TimeStamp());
|
||||||
}
|
}
|
||||||
ret = buffer_return;
|
|
||||||
if (buffer_return > 0) {
|
if (buffer_return > 0) {
|
||||||
incoming_bit_count_ += packet.sizeBytes << 3;
|
incoming_bit_count_ += packet.sizeBytes << 3;
|
||||||
if (first_packet_since_reset_) {
|
if (first_packet_since_reset_) {
|
||||||
@ -721,51 +717,55 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
latest_received_sequence_number_, packet.seqNum);
|
latest_received_sequence_number_, packet.seqNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the frame already in the decodable list?
|
||||||
|
bool update_decodable_list = (previous_state != kStateDecodable &&
|
||||||
|
previous_state != kStateComplete);
|
||||||
|
bool continuous = IsContinuous(*frame);
|
||||||
switch (buffer_return) {
|
switch (buffer_return) {
|
||||||
case kGeneralError:
|
case kGeneralError:
|
||||||
case kTimeStampError:
|
case kTimeStampError:
|
||||||
case kSizeError: {
|
case kSizeError: {
|
||||||
// This frame will be cleaned up later from the frame lists.
|
// This frame will be cleaned up later from the frame list.
|
||||||
frame->Reset();
|
frame->Reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kCompleteSession: {
|
case kCompleteSession: {
|
||||||
if (master_) {
|
if (update_decodable_list) {
|
||||||
// Only trace the primary jitter buffer to make it possible to parse
|
if (master_) {
|
||||||
// and plot the trace file.
|
// Only trace the primary jitter buffer to make it possible to parse
|
||||||
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
|
// and plot the trace file.
|
||||||
VCMId(vcm_id_, receiver_id_),
|
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
|
||||||
"JB(0x%x) FB(0x%x): Complete frame added to jitter buffer,"
|
VCMId(vcm_id_, receiver_id_),
|
||||||
" size:%d type %d",
|
"JB(0x%x) FB(0x%x): Complete frame added to jitter"
|
||||||
this, frame, frame->Length(), frame->FrameType());
|
"buffer, size:%d type %d",
|
||||||
}
|
this, frame, frame->Length(), frame->FrameType());
|
||||||
CountFrame(*frame);
|
}
|
||||||
frame->SetCountedFrame(true);
|
CountFrame(*frame);
|
||||||
if (previous_state == kStateComplete) {
|
frame->SetCountedFrame(true);
|
||||||
*retransmitted = (frame->GetNackCount() > 0);
|
if (continuous) {
|
||||||
packet_event_->Set();
|
// Signal that we have a complete session.
|
||||||
break;
|
frame_event_->Set();
|
||||||
}
|
|
||||||
}
|
|
||||||
case kDecodableSession: {
|
|
||||||
*retransmitted = (frame->GetNackCount() > 0);
|
|
||||||
if (previous_state != kStateDecodable) {
|
|
||||||
if (IsContinuous(*frame) || decode_error_mode_ == kWithErrors) {
|
|
||||||
if (!first) {
|
|
||||||
incomplete_frames_.PopFrame(packet.timestamp);
|
|
||||||
}
|
|
||||||
decodable_frames_.InsertFrame(frame);
|
|
||||||
FindAndInsertContinuousFrames(*frame);
|
|
||||||
if (buffer_return == kCompleteSession) {
|
|
||||||
// Signal that we have a complete session
|
|
||||||
frame_event_->Set();
|
|
||||||
}
|
|
||||||
} else if (first) {
|
|
||||||
incomplete_frames_.InsertFrame(frame);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Note: There is no break here - continuing to kDecodableSession.
|
||||||
|
case kDecodableSession: {
|
||||||
|
*retransmitted = (frame->GetNackCount() > 0);
|
||||||
// Signal that we have a received packet.
|
// Signal that we have a received packet.
|
||||||
packet_event_->Set();
|
packet_event_->Set();
|
||||||
|
if (!update_decodable_list) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (continuous) {
|
||||||
|
if (!first) {
|
||||||
|
incomplete_frames_.PopFrame(packet.timestamp);
|
||||||
|
}
|
||||||
|
decodable_frames_.InsertFrame(frame);
|
||||||
|
FindAndInsertContinuousFrames(*frame);
|
||||||
|
} else if (first) {
|
||||||
|
incomplete_frames_.InsertFrame(frame);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kIncomplete: {
|
case kIncomplete: {
|
||||||
@ -775,10 +775,7 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
free_frames_.push_back(frame);
|
free_frames_.push_back(frame);
|
||||||
frame->Reset();
|
frame->Reset();
|
||||||
frame = NULL;
|
frame = NULL;
|
||||||
ret = kNoError;
|
return kNoError;
|
||||||
} else if (previous_state == kStateDecodable) {
|
|
||||||
decodable_frames_.PopFrame(packet.timestamp);
|
|
||||||
incomplete_frames_.InsertFrame(frame);
|
|
||||||
} else if (first) {
|
} else if (first) {
|
||||||
incomplete_frames_.InsertFrame(frame);
|
incomplete_frames_.InsertFrame(frame);
|
||||||
}
|
}
|
||||||
@ -792,17 +789,18 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kFlushIndicator:
|
case kFlushIndicator:
|
||||||
ret = kFlushIndicator;
|
return kFlushIndicator;
|
||||||
break;
|
|
||||||
default: {
|
default: {
|
||||||
assert(false && "JitterBuffer::InsertPacket: Undefined value");
|
assert(false && "JitterBuffer::InsertPacket: Undefined value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return buffer_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VCMJitterBuffer::IsContinuousInState(const VCMFrameBuffer& frame,
|
bool VCMJitterBuffer::IsContinuousInState(const VCMFrameBuffer& frame,
|
||||||
const VCMDecodingState& decoding_state) const {
|
const VCMDecodingState& decoding_state) const {
|
||||||
|
if (decode_error_mode_ == kWithErrors)
|
||||||
|
return true;
|
||||||
// Is this frame (complete or decodable) and continuous?
|
// Is this frame (complete or decodable) and continuous?
|
||||||
// kStateDecodable will never be set when decode_error_mode_ is false
|
// kStateDecodable will never be set when decode_error_mode_ is false
|
||||||
// as SessionInfo determines this state based on the error mode (and frame
|
// as SessionInfo determines this state based on the error mode (and frame
|
||||||
@ -1017,36 +1015,7 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
|
|||||||
|
|
||||||
void VCMJitterBuffer::SetDecodeErrorMode(VCMDecodeErrorMode error_mode) {
|
void VCMJitterBuffer::SetDecodeErrorMode(VCMDecodeErrorMode error_mode) {
|
||||||
CriticalSectionScoped cs(crit_sect_);
|
CriticalSectionScoped cs(crit_sect_);
|
||||||
// If we are not moving from kWithErrors or KSelectiveErrors to kNoErrors,
|
decode_error_mode_ = error_mode;
|
||||||
// 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->SetNotDecodableIfIncomplete();
|
|
||||||
incomplete_frames_.InsertFrame(frame);
|
|
||||||
}
|
|
||||||
decode_error_mode_ = error_mode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMFrameBuffer* VCMJitterBuffer::NextFrame() const {
|
VCMFrameBuffer* VCMJitterBuffer::NextFrame() const {
|
||||||
|
@ -175,10 +175,8 @@ class VCMJitterBuffer {
|
|||||||
// Returns a list of the sequence numbers currently missing.
|
// Returns a list of the sequence numbers currently missing.
|
||||||
uint16_t* GetNackList(uint16_t* nack_list_size, bool* request_key_frame);
|
uint16_t* GetNackList(uint16_t* nack_list_size, bool* request_key_frame);
|
||||||
|
|
||||||
// Set decode error mode. Setting kNoErrors will have immediate effect.
|
// Set decode error mode - Should not be changed in the middle of the
|
||||||
// Setting kWithErrors and kSelectiveErrors will take full effect once the
|
// session. Changes will not influence frames already in the buffer.
|
||||||
// existing incomplete frames leave the JB or have a packet added (as that
|
|
||||||
// would cause their state to be reevlauated).
|
|
||||||
void SetDecodeErrorMode(VCMDecodeErrorMode error_mode);
|
void SetDecodeErrorMode(VCMDecodeErrorMode error_mode);
|
||||||
int64_t LastDecodedTimestamp() const;
|
int64_t LastDecodedTimestamp() const;
|
||||||
VCMDecodeErrorMode decode_error_mode() const {return decode_error_mode_;}
|
VCMDecodeErrorMode decode_error_mode() const {return decode_error_mode_;}
|
||||||
|
@ -259,11 +259,12 @@ TEST_F(TestBasicJitterBuffer, StopRunning) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestBasicJitterBuffer, SinglePacketFrame) {
|
TEST_F(TestBasicJitterBuffer, SinglePacketFrame) {
|
||||||
// Always start with a complete key frame.
|
// Always start with a complete key frame when not allowing errors.
|
||||||
|
jitter_buffer_->SetDecodeErrorMode(kNoErrors);
|
||||||
packet_->frameType = kVideoFrameKey;
|
packet_->frameType = kVideoFrameKey;
|
||||||
packet_->isFirstPacket = true;
|
packet_->isFirstPacket = true;
|
||||||
packet_->markerBit = true;
|
packet_->markerBit = true;
|
||||||
packet_->timestamp += 123*90;
|
packet_->timestamp += 123 * 90;
|
||||||
|
|
||||||
// Insert the packet to the jitter buffer and get a frame.
|
// Insert the packet to the jitter buffer and get a frame.
|
||||||
bool retransmitted = false;
|
bool retransmitted = false;
|
||||||
@ -614,7 +615,8 @@ TEST_F(TestBasicJitterBuffer, PacketLossWithSelectiveErrorsThresholdCheck) {
|
|||||||
packet_->isFirstPacket = true;
|
packet_->isFirstPacket = true;
|
||||||
packet_->markerBit = false;
|
packet_->markerBit = false;
|
||||||
packet_->seqNum += 100;
|
packet_->seqNum += 100;
|
||||||
packet_->timestamp += 33*90*8;
|
packet_->timestamp += 33 * 90 * 8;
|
||||||
|
|
||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
||||||
@ -622,7 +624,7 @@ TEST_F(TestBasicJitterBuffer, PacketLossWithSelectiveErrorsThresholdCheck) {
|
|||||||
|
|
||||||
// Insert second frame
|
// Insert second frame
|
||||||
packet_->seqNum -= 99;
|
packet_->seqNum -= 99;
|
||||||
packet_->timestamp -= 33*90*7;
|
packet_->timestamp -= 33 * 90 * 7;
|
||||||
|
|
||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
@ -778,84 +780,47 @@ TEST_F(TestBasicJitterBuffer, PacketLossWithSelectiveErrorsMissingFirstPacket) {
|
|||||||
EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType());
|
EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure incoplete decodable packets are removed from decodable frames
|
TEST_F(TestBasicJitterBuffer, DiscontinuousStreamWhenDecodingWithErrors) {
|
||||||
// and marked incomplete if the decode error mode is changed from kWithErrors
|
// Will use one packet per frame.
|
||||||
// or kSelectiveErrors to kNoErrors.
|
|
||||||
// Also make sure these frames are marked complete once all the packets are
|
|
||||||
// present (ie they are not dropped).
|
|
||||||
TEST_F(TestBasicJitterBuffer, PacketLossStateChangedFromErrorsToNone) {
|
|
||||||
jitter_buffer_->SetDecodeErrorMode(kWithErrors);
|
jitter_buffer_->SetDecodeErrorMode(kWithErrors);
|
||||||
|
|
||||||
// First frame is always a key frame.
|
|
||||||
packet_->frameType = kVideoFrameKey;
|
packet_->frameType = kVideoFrameKey;
|
||||||
packet_->isFirstPacket = true;
|
packet_->isFirstPacket = true;
|
||||||
packet_->markerBit = true;
|
packet_->markerBit = true;
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
packet_->timestamp = timestamp_;
|
packet_->timestamp = timestamp_;
|
||||||
|
|
||||||
bool retransmitted = false;
|
bool retransmitted = false;
|
||||||
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
uint32_t timestamp = 0;
|
uint32_t next_timestamp;
|
||||||
EXPECT_TRUE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
EXPECT_TRUE(jitter_buffer_->NextCompleteTimestamp(0, &next_timestamp));
|
||||||
|
EXPECT_EQ(packet_->timestamp, next_timestamp);
|
||||||
VCMEncodedFrame* frame_out = DecodeCompleteFrame();
|
VCMEncodedFrame* frame = jitter_buffer_->ExtractAndSetDecode(next_timestamp);
|
||||||
CheckOutFrame(frame_out, size_, false);
|
EXPECT_TRUE(frame != NULL);
|
||||||
EXPECT_EQ(kVideoFrameKey, frame_out->FrameType());
|
jitter_buffer_->ReleaseFrame(frame);
|
||||||
|
|
||||||
|
// Drop a complete frame.
|
||||||
|
timestamp_ += 2 * 33 * 90;
|
||||||
|
seq_num_ += 2;
|
||||||
packet_->frameType = kVideoFrameDelta;
|
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_->SetDecodeErrorMode(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;
|
packet_->isFirstPacket = true;
|
||||||
|
packet_->markerBit = false;
|
||||||
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_,
|
packet_->seqNum = seq_num_;
|
||||||
&retransmitted));
|
packet_->timestamp = timestamp_;
|
||||||
EXPECT_TRUE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
frame_out = DecodeCompleteFrame();
|
&retransmitted));
|
||||||
ASSERT_FALSE(frame_out == NULL);
|
// Insert a packet (so the previous one will be released).
|
||||||
|
timestamp_ += 33 * 90;
|
||||||
CheckOutFrame(frame_out, 3 * size_, false);
|
seq_num_ += 2;
|
||||||
EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType());
|
packet_->frameType = kVideoFrameDelta;
|
||||||
EXPECT_EQ(packet_->timestamp, frame_out->TimeStamp());
|
packet_->isFirstPacket = true;
|
||||||
|
packet_->markerBit = false;
|
||||||
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, ×tamp));
|
packet_->seqNum = seq_num_;
|
||||||
EXPECT_FALSE(jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp));
|
packet_->timestamp = timestamp_;
|
||||||
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
|
&retransmitted));
|
||||||
|
EXPECT_FALSE(jitter_buffer_->NextCompleteTimestamp(0, &next_timestamp));
|
||||||
|
EXPECT_TRUE(jitter_buffer_->NextMaybeIncompleteTimestamp(&next_timestamp));
|
||||||
|
EXPECT_EQ(packet_->timestamp - 33 * 90, next_timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestBasicJitterBuffer, PacketLoss) {
|
TEST_F(TestBasicJitterBuffer, PacketLoss) {
|
||||||
@ -916,8 +881,7 @@ TEST_F(TestBasicJitterBuffer, PacketLoss) {
|
|||||||
packet_->frameType = kFrameEmpty;
|
packet_->frameType = kFrameEmpty;
|
||||||
|
|
||||||
EXPECT_EQ(jitter_buffer_->InsertPacket(*packet_, &retransmitted),
|
EXPECT_EQ(jitter_buffer_->InsertPacket(*packet_, &retransmitted),
|
||||||
kDecodableSession);
|
kDecodableSession);
|
||||||
|
|
||||||
frame_out = DecodeIncompleteFrame();
|
frame_out = DecodeIncompleteFrame();
|
||||||
|
|
||||||
// One of the packets has been discarded by the jitter buffer.
|
// One of the packets has been discarded by the jitter buffer.
|
||||||
@ -1414,7 +1378,7 @@ TEST_F(TestBasicJitterBuffer, EmptyLastFrame) {
|
|||||||
TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
||||||
jitter_buffer_->SetNackMode(kNoNack, -1, -1);
|
jitter_buffer_->SetNackMode(kNoNack, -1, -1);
|
||||||
jitter_buffer_->SetDecodeErrorMode(kWithErrors);
|
jitter_buffer_->SetDecodeErrorMode(kWithErrors);
|
||||||
seq_num_ ++;
|
++seq_num_;
|
||||||
timestamp_ += 33 * 90;
|
timestamp_ += 33 * 90;
|
||||||
int insertedLength = 0;
|
int insertedLength = 0;
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
@ -1428,7 +1392,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
|
|
||||||
seq_num_ += 2; // Skip one packet
|
seq_num_ += 2; // Skip one packet.
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
packet_->frameType = kVideoFrameKey;
|
packet_->frameType = kVideoFrameKey;
|
||||||
packet_->isFirstPacket = false;
|
packet_->isFirstPacket = false;
|
||||||
@ -1451,7 +1415,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
seq_num_++;
|
seq_num_++;
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
packet_->completeNALU = kNaluComplete;
|
packet_->completeNALU = kNaluComplete;
|
||||||
packet_->markerBit = true; // Last packet
|
packet_->markerBit = true; // Last packet.
|
||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
// The JB will only output (incomplete) frames if a packet belonging to a
|
// The JB will only output (incomplete) frames if a packet belonging to a
|
||||||
@ -1478,7 +1442,7 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
jitter_buffer_->ReleaseFrame(frame_out);
|
jitter_buffer_->ReleaseFrame(frame_out);
|
||||||
|
|
||||||
// Test reordered start frame + 1 lost.
|
// Test reordered start frame + 1 lost.
|
||||||
seq_num_ += 2; // Re-order 1 frame.
|
seq_num_ += 2; // Re-order 1 frame.
|
||||||
timestamp_ += 33*90;
|
timestamp_ += 33*90;
|
||||||
insertedLength = 0;
|
insertedLength = 0;
|
||||||
|
|
||||||
@ -1488,12 +1452,9 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
packet_->isFirstPacket = false;
|
packet_->isFirstPacket = false;
|
||||||
packet_->completeNALU = kNaluEnd;
|
packet_->completeNALU = kNaluEnd;
|
||||||
packet_->markerBit = false;
|
packet_->markerBit = false;
|
||||||
|
|
||||||
|
|
||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
insertedLength += packet_->sizeBytes; // This packet should be decoded.
|
insertedLength += packet_->sizeBytes; // This packet should be decoded.
|
||||||
|
|
||||||
seq_num_--;
|
seq_num_--;
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
packet_->timestamp = timestamp_;
|
packet_->timestamp = timestamp_;
|
||||||
@ -1501,11 +1462,12 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
packet_->isFirstPacket = true;
|
packet_->isFirstPacket = true;
|
||||||
packet_->completeNALU = kNaluStart;
|
packet_->completeNALU = kNaluStart;
|
||||||
packet_->markerBit = false;
|
packet_->markerBit = false;
|
||||||
|
|
||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
insertedLength += packet_->sizeBytes; // This packet should be decoded.
|
insertedLength += packet_->sizeBytes; // This packet should be decoded.
|
||||||
|
|
||||||
seq_num_ += 3; // One packet drop
|
seq_num_ += 3; // One packet drop.
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
packet_->timestamp = timestamp_;
|
packet_->timestamp = timestamp_;
|
||||||
packet_->frameType = kVideoFrameKey;
|
packet_->frameType = kVideoFrameKey;
|
||||||
@ -1515,7 +1477,6 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
insertedLength += packet_->sizeBytes; // This packet should be decoded.
|
insertedLength += packet_->sizeBytes; // This packet should be decoded.
|
||||||
|
|
||||||
seq_num_++;
|
seq_num_++;
|
||||||
packet_->seqNum = seq_num_;
|
packet_->seqNum = seq_num_;
|
||||||
packet_->timestamp = timestamp_;
|
packet_->timestamp = timestamp_;
|
||||||
@ -1544,7 +1505,6 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
CheckOutFrame(frame_out, insertedLength, false);
|
CheckOutFrame(frame_out, insertedLength, false);
|
||||||
jitter_buffer_->ReleaseFrame(frame_out);
|
jitter_buffer_->ReleaseFrame(frame_out);
|
||||||
|
|
||||||
|
|
||||||
// Test to insert empty packet.
|
// Test to insert empty packet.
|
||||||
seq_num_++;
|
seq_num_++;
|
||||||
timestamp_ += 33 * 90;
|
timestamp_ += 33 * 90;
|
||||||
@ -1559,7 +1519,6 @@ TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) {
|
|||||||
&retransmitted));
|
&retransmitted));
|
||||||
// This packet should not be decoded because it is an incomplete NAL if it
|
// This packet should not be decoded because it is an incomplete NAL if it
|
||||||
// is the last.
|
// is the last.
|
||||||
insertedLength += 0;
|
|
||||||
|
|
||||||
// Will be sent to the decoder, as a packet belonging to a subsequent frame
|
// Will be sent to the decoder, as a packet belonging to a subsequent frame
|
||||||
// has arrived.
|
// has arrived.
|
||||||
@ -1628,7 +1587,6 @@ TEST_F(TestBasicJitterBuffer, NextFrameWhenIncomplete) {
|
|||||||
packet_->timestamp += 33 * 90;
|
packet_->timestamp += 33 * 90;
|
||||||
packet_->isFirstPacket = true;
|
packet_->isFirstPacket = true;
|
||||||
|
|
||||||
|
|
||||||
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
EXPECT_EQ(kDecodableSession, jitter_buffer_->InsertPacket(*packet_,
|
||||||
&retransmitted));
|
&retransmitted));
|
||||||
|
|
||||||
|
@ -187,7 +187,6 @@ void VCMSessionInfo::UpdateDecodableSession(const FrameData& frame_data) {
|
|||||||
// Irrelevant if session is already complete or decodable
|
// Irrelevant if session is already complete or decodable
|
||||||
if (complete_ || decodable_)
|
if (complete_ || decodable_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO(agalusza): Account for bursty loss.
|
// TODO(agalusza): Account for bursty loss.
|
||||||
// TODO(agalusza): Refine these values to better approximate optimal ones.
|
// TODO(agalusza): Refine these values to better approximate optimal ones.
|
||||||
if (frame_data.rtt_ms < kRttThreshold
|
if (frame_data.rtt_ms < kRttThreshold
|
||||||
|
@ -215,8 +215,7 @@ TEST_F(VCMRobustnessTest, TestDualDecoder) {
|
|||||||
|
|
||||||
|
|
||||||
ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(
|
ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(
|
||||||
VideoCodingModule::kDualDecoder,
|
VideoCodingModule::kDualDecoder, kWithErrors));
|
||||||
kWithErrors));
|
|
||||||
|
|
||||||
InsertPacket(0, 0, true, false, kVideoFrameKey);
|
InsertPacket(0, 0, true, false, kVideoFrameKey);
|
||||||
InsertPacket(0, 1, false, false, kVideoFrameKey);
|
InsertPacket(0, 1, false, false, kVideoFrameKey);
|
||||||
@ -225,7 +224,7 @@ TEST_F(VCMRobustnessTest, TestDualDecoder) {
|
|||||||
|
|
||||||
clock_->AdvanceTimeMilliseconds(33);
|
clock_->AdvanceTimeMilliseconds(33);
|
||||||
InsertPacket(3000, 3, true, false, kVideoFrameDelta);
|
InsertPacket(3000, 3, true, false, kVideoFrameDelta);
|
||||||
// Packet 4 missing
|
// Packet 4 missing.
|
||||||
InsertPacket(3000, 5, false, true, kVideoFrameDelta);
|
InsertPacket(3000, 5, false, true, kVideoFrameDelta);
|
||||||
EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user