diff --git a/webrtc/modules/video_coding/main/source/frame_buffer.cc b/webrtc/modules/video_coding/main/source/frame_buffer.cc index bc1407b2b..69ef0a212 100644 --- a/webrtc/modules/video_coding/main/source/frame_buffer.cc +++ b/webrtc/modules/video_coding/main/source/frame_buffer.cc @@ -216,6 +216,12 @@ VCMFrameBuffer::GetNackCount() const return _nackCount; } +bool +VCMFrameBuffer::HaveFirstPacket() const +{ + return _sessionInfo.HaveFirstPacket(); +} + bool VCMFrameBuffer::HaveLastPacket() const { diff --git a/webrtc/modules/video_coding/main/source/frame_buffer.h b/webrtc/modules/video_coding/main/source/frame_buffer.h index 1d1fd24b9..81400a277 100644 --- a/webrtc/modules/video_coding/main/source/frame_buffer.h +++ b/webrtc/modules/video_coding/main/source/frame_buffer.h @@ -44,6 +44,7 @@ public: bool IsRetransmitted() const; bool IsSessionComplete() const; + bool HaveFirstPacket() const; bool HaveLastPacket() const; // Makes sure the session contain a decodable stream. void MakeSessionDecodable(); diff --git a/webrtc/modules/video_coding/main/source/jitter_buffer.cc b/webrtc/modules/video_coding/main/source/jitter_buffer.cc index 849d6412f..86683ff9b 100644 --- a/webrtc/modules/video_coding/main/source/jitter_buffer.cc +++ b/webrtc/modules/video_coding/main/source/jitter_buffer.cc @@ -878,11 +878,19 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size, return NULL; } if (last_decoded_state_.in_initial_state()) { - const bool have_non_empty_frame = frame_list_.end() != find_if( - frame_list_.begin(), frame_list_.end(), HasNonEmptyState); - *request_key_frame = have_non_empty_frame; - *nack_list_size = 0; - return NULL; + bool first_frame_is_key = !frame_list_.empty() && + frame_list_.front()->FrameType() == kVideoFrameKey && + frame_list_.front()->HaveFirstPacket(); + if (!first_frame_is_key) { + const bool have_non_empty_frame = frame_list_.end() != find_if( + frame_list_.begin(), frame_list_.end(), HasNonEmptyState); + bool found_key_frame = RecycleFramesUntilKeyFrame(); + if (!found_key_frame) { + *request_key_frame = have_non_empty_frame; + *nack_list_size = 0; + return NULL; + } + } } if (TooLargeNackList()) { TRACE_EVENT_INSTANT1("webrtc", "JB::NackListTooLarge", diff --git a/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc b/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc index 08f78a9cb..7107ccbc7 100644 --- a/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc +++ b/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc @@ -494,6 +494,24 @@ TEST_F(TestJitterBufferNack, NackListBuiltBeforeFirstDecode) { EXPECT_TRUE(list != NULL); } +TEST_F(TestJitterBufferNack, UseNackToRecoverFirstKeyFrame) { + stream_generator->Init(0, 0, clock_->TimeInMilliseconds()); + stream_generator->GenerateFrame(kVideoFrameKey, 3, 0, + clock_->TimeInMilliseconds()); + EXPECT_EQ(kFirstPacket, InsertPacketAndPop(0)); + // Drop second packet. + EXPECT_EQ(kIncomplete, InsertPacketAndPop(1)); + EXPECT_FALSE(DecodeCompleteFrame()); + uint16_t nack_list_size = 0; + bool extended = false; + uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended); + EXPECT_EQ(1, nack_list_size); + ASSERT_TRUE(list != NULL); + VCMPacket packet; + stream_generator->GetPacket(&packet, 0); + EXPECT_EQ(packet.seqNum, list[0]); +} + TEST_F(TestJitterBufferNack, NormalOperation) { EXPECT_EQ(kNack, jitter_buffer_->nack_mode()); diff --git a/webrtc/modules/video_coding/main/source/session_info.cc b/webrtc/modules/video_coding/main/source/session_info.cc index eb3282257..6db57f2d2 100644 --- a/webrtc/modules/video_coding/main/source/session_info.cc +++ b/webrtc/modules/video_coding/main/source/session_info.cc @@ -353,6 +353,11 @@ int VCMSessionInfo::MakeDecodable() { return return_length; } +bool +VCMSessionInfo::HaveFirstPacket() const { + return !packets_.empty() && packets_.front().isFirstPacket; +} + bool VCMSessionInfo::HaveLastPacket() const { return (!packets_.empty() && packets_.back().markerBit); diff --git a/webrtc/modules/video_coding/main/source/session_info.h b/webrtc/modules/video_coding/main/source/session_info.h index 3d7dcd99d..18ee7a499 100644 --- a/webrtc/modules/video_coding/main/source/session_info.h +++ b/webrtc/modules/video_coding/main/source/session_info.h @@ -59,6 +59,7 @@ class VCMSessionInfo { // Returns the number of bytes deleted from the session. int MakeDecodable(); int SessionLength() const; + bool HaveFirstPacket() const; bool HaveLastPacket() const; bool session_nack() const; webrtc::FrameType FrameType() const { return frame_type_; }