VCM/JB: Skip to the next complete key frame
Review URL: https://webrtc-codereview.appspot.com/1317006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3885 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -54,12 +54,11 @@ class FrameEqualTimestamp {
|
|||||||
uint32_t timestamp_;
|
uint32_t timestamp_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CompleteDecodableKeyFrameCriteria {
|
class CompleteKeyFrameCriteria {
|
||||||
public:
|
public:
|
||||||
bool operator()(VCMFrameBuffer* frame) {
|
bool operator()(VCMFrameBuffer* frame) {
|
||||||
return (frame->FrameType() == kVideoFrameKey) &&
|
return (frame->FrameType() == kVideoFrameKey &&
|
||||||
(frame->GetState() == kStateComplete ||
|
frame->GetState() == kStateComplete);
|
||||||
frame->GetState() == kStateDecodable);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -435,24 +434,19 @@ bool VCMJitterBuffer::CompleteSequenceWithNextFrame() {
|
|||||||
VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(
|
VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(
|
||||||
uint32_t max_wait_time_ms) {
|
uint32_t max_wait_time_ms) {
|
||||||
TRACE_EVENT0("webrtc", "JB::GetCompleteFrame");
|
TRACE_EVENT0("webrtc", "JB::GetCompleteFrame");
|
||||||
|
crit_sect_->Enter();
|
||||||
if (!running_) {
|
if (!running_) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
crit_sect_->Enter();
|
|
||||||
|
|
||||||
CleanUpOldOrEmptyFrames();
|
CleanUpOldOrEmptyFrames();
|
||||||
|
|
||||||
if (last_decoded_state_.in_initial_state() && WaitForRetransmissions()) {
|
if (last_decoded_state_.in_initial_state()) {
|
||||||
waiting_for_key_frame_ = true;
|
waiting_for_key_frame_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameList::iterator it = FindOldestCompleteContinuousFrame();
|
FrameList::iterator it = FindOldestCompleteContinuousFrame();
|
||||||
if (it == frame_list_.end()) {
|
if (it == frame_list_.end()) {
|
||||||
if (max_wait_time_ms == 0) {
|
|
||||||
crit_sect_->Leave();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
const int64_t end_wait_time_ms = clock_->TimeInMilliseconds() +
|
const int64_t end_wait_time_ms = clock_->TimeInMilliseconds() +
|
||||||
max_wait_time_ms;
|
max_wait_time_ms;
|
||||||
int64_t wait_time_ms = max_wait_time_ms;
|
int64_t wait_time_ms = max_wait_time_ms;
|
||||||
@@ -462,7 +456,7 @@ VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(
|
|||||||
frame_event_->Wait(static_cast<uint32_t>(wait_time_ms));
|
frame_event_->Wait(static_cast<uint32_t>(wait_time_ms));
|
||||||
crit_sect_->Enter();
|
crit_sect_->Enter();
|
||||||
if (ret == kEventSignaled) {
|
if (ret == kEventSignaled) {
|
||||||
// are we closing down the Jitter buffer
|
// Are we closing down the Jitter buffer?
|
||||||
if (!running_) {
|
if (!running_) {
|
||||||
crit_sect_->Leave();
|
crit_sect_->Leave();
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -490,11 +484,23 @@ VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(
|
|||||||
|
|
||||||
if (it == frame_list_.end()) {
|
if (it == frame_list_.end()) {
|
||||||
// Even after signaling we're still missing a complete continuous frame.
|
// Even after signaling we're still missing a complete continuous frame.
|
||||||
|
// Look for a complete key frame.
|
||||||
|
it = find_if(frame_list_.begin(), frame_list_.end(),
|
||||||
|
CompleteKeyFrameCriteria());
|
||||||
|
if (it == frame_list_.end()) {
|
||||||
|
crit_sect_->Leave();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VCMFrameBuffer* oldest_frame = *it;
|
||||||
|
|
||||||
|
// Are we waiting for a key frame?
|
||||||
|
if (waiting_for_key_frame_ && oldest_frame->FrameType() != kVideoFrameKey) {
|
||||||
crit_sect_->Leave();
|
crit_sect_->Leave();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMFrameBuffer* oldest_frame = *it;
|
|
||||||
it = frame_list_.erase(it);
|
it = frame_list_.erase(it);
|
||||||
if (frame_list_.empty()) {
|
if (frame_list_.empty()) {
|
||||||
TRACE_EVENT_INSTANT1("webrtc", "JB::FrameListEmptied",
|
TRACE_EVENT_INSTANT1("webrtc", "JB::FrameListEmptied",
|
||||||
@@ -1003,9 +1009,9 @@ VCMEncodedFrame* VCMJitterBuffer::GetFrameForDecodingNACK() {
|
|||||||
}
|
}
|
||||||
FrameList::iterator it = FindOldestCompleteContinuousFrame();
|
FrameList::iterator it = FindOldestCompleteContinuousFrame();
|
||||||
if (it == frame_list_.end()) {
|
if (it == frame_list_.end()) {
|
||||||
// If we didn't find one we're good with a complete key/decodable frame.
|
// If we didn't find one we're good with a complete key frame.
|
||||||
it = find_if(frame_list_.begin(), frame_list_.end(),
|
it = find_if(frame_list_.begin(), frame_list_.end(),
|
||||||
CompleteDecodableKeyFrameCriteria());
|
CompleteKeyFrameCriteria());
|
||||||
if (it == frame_list_.end()) {
|
if (it == frame_list_.end()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -373,6 +373,16 @@ TEST_F(TestRunningJitterBuffer, StatisticsTest) {
|
|||||||
EXPECT_EQ(kDefaultBitrateKbps, bitrate);
|
EXPECT_EQ(kDefaultBitrateKbps, bitrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TestRunningJitterBuffer, SkipToKeyFrame) {
|
||||||
|
// Insert delta frames.
|
||||||
|
EXPECT_GE(InsertFrames(5, kVideoFrameDelta), kNoError);
|
||||||
|
// Can't decode without a key frame.
|
||||||
|
EXPECT_FALSE(DecodeCompleteFrame());
|
||||||
|
InsertFrame(kVideoFrameKey);
|
||||||
|
// Skip to the next key frame.
|
||||||
|
EXPECT_TRUE(DecodeCompleteFrame());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestJitterBufferNack, EmptyPackets) {
|
TEST_F(TestJitterBufferNack, EmptyPackets) {
|
||||||
// Make sure empty packets doesn't clog the jitter buffer.
|
// Make sure empty packets doesn't clog the jitter buffer.
|
||||||
jitter_buffer_->SetNackMode(kNack, media_optimization::kLowRttNackMs, -1);
|
jitter_buffer_->SetNackMode(kNack, media_optimization::kLowRttNackMs, -1);
|
||||||
@@ -408,12 +418,12 @@ TEST_F(TestJitterBufferNack, NackTooOldPackets) {
|
|||||||
EXPECT_FALSE(DecodeCompleteFrame());
|
EXPECT_FALSE(DecodeCompleteFrame());
|
||||||
EXPECT_FALSE(DecodeFrame());
|
EXPECT_FALSE(DecodeFrame());
|
||||||
|
|
||||||
EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError);
|
|
||||||
// The next complete continuous frame isn't a key frame, but we're waiting
|
// The next complete continuous frame isn't a key frame, but we're waiting
|
||||||
// for one.
|
// for one.
|
||||||
EXPECT_FALSE(DecodeCompleteFrame());
|
EXPECT_FALSE(DecodeCompleteFrame());
|
||||||
|
EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError);
|
||||||
// Skipping ahead to the key frame.
|
// Skipping ahead to the key frame.
|
||||||
EXPECT_TRUE(DecodeFrame());
|
EXPECT_TRUE(DecodeCompleteFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestJitterBufferNack, NackLargeJitterBuffer) {
|
TEST_F(TestJitterBufferNack, NackLargeJitterBuffer) {
|
||||||
@@ -453,16 +463,13 @@ TEST_F(TestJitterBufferNack, NackListFull) {
|
|||||||
EXPECT_TRUE(request_key_frame);
|
EXPECT_TRUE(request_key_frame);
|
||||||
|
|
||||||
EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError);
|
EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError);
|
||||||
// Waiting for a key frame.
|
|
||||||
EXPECT_FALSE(DecodeCompleteFrame());
|
|
||||||
EXPECT_FALSE(DecodeFrame());
|
|
||||||
|
|
||||||
EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError);
|
|
||||||
// The next complete continuous frame isn't a key frame, but we're waiting
|
// The next complete continuous frame isn't a key frame, but we're waiting
|
||||||
// for one.
|
// for one.
|
||||||
EXPECT_FALSE(DecodeCompleteFrame());
|
EXPECT_FALSE(DecodeCompleteFrame());
|
||||||
|
EXPECT_FALSE(DecodeFrame());
|
||||||
|
EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError);
|
||||||
// Skipping ahead to the key frame.
|
// Skipping ahead to the key frame.
|
||||||
EXPECT_TRUE(DecodeFrame());
|
EXPECT_TRUE(DecodeCompleteFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestJitterBufferNack, NoNackListReturnedBeforeFirstDecode) {
|
TEST_F(TestJitterBufferNack, NoNackListReturnedBeforeFirstDecode) {
|
||||||
|
|||||||
Reference in New Issue
Block a user