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:
mikhal@webrtc.org
2013-04-22 22:24:38 +00:00
parent 63117339dc
commit c1f243f8e7
2 changed files with 36 additions and 23 deletions

View File

@@ -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;
} }

View File

@@ -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) {