From 463d3011ceeb6d361411a42fa974b92d9dbc53e1 Mon Sep 17 00:00:00 2001 From: philipel Date: Fri, 9 Sep 2016 03:32:44 -0700 Subject: [PATCH] Added ClearTo(seq_num) to RtpFrameReferenceFinder. In order to be able to clear out any potentially stashed old frames from the RtpFrameReferenceFinder we can now clear frames that contain packets older than |seq_num|. BUG=webrtc:5514 Review-Url: https://codereview.webrtc.org/2304723004 Cr-Commit-Position: refs/heads/master@{#14156} --- .../rtp_frame_reference_finder.cc | 40 +++++++++++++++---- .../video_coding/rtp_frame_reference_finder.h | 22 +++++++++- .../rtp_frame_reference_finder_unittest.cc | 18 +++++++++ 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/webrtc/modules/video_coding/rtp_frame_reference_finder.cc b/webrtc/modules/video_coding/rtp_frame_reference_finder.cc index 998d757a7b..218a52d880 100644 --- a/webrtc/modules/video_coding/rtp_frame_reference_finder.cc +++ b/webrtc/modules/video_coding/rtp_frame_reference_finder.cc @@ -26,11 +26,19 @@ RtpFrameReferenceFinder::RtpFrameReferenceFinder( : last_picture_id_(-1), last_unwrap_(-1), current_ss_idx_(0), + cleared_to_seq_num_(-1), frame_callback_(frame_callback) {} void RtpFrameReferenceFinder::ManageFrame( std::unique_ptr frame) { rtc::CritScope lock(&crit_); + + // If we have cleared past this frame, drop it. + if (cleared_to_seq_num_ != -1 && + AheadOf(cleared_to_seq_num_, frame->first_seq_num())) { + return; + } + switch (frame->codec_type()) { case kVideoCodecULPFEC: case kVideoCodecRED: @@ -61,6 +69,20 @@ void RtpFrameReferenceFinder::PaddingReceived(uint16_t seq_num) { RetryStashedFrames(); } +void RtpFrameReferenceFinder::ClearTo(uint16_t seq_num) { + rtc::CritScope lock(&crit_); + cleared_to_seq_num_ = seq_num; + + auto it = stashed_frames_.begin(); + while (it != stashed_frames_.end()) { + if (AheadOf(cleared_to_seq_num_, (*it)->first_seq_num())) { + it = stashed_frames_.erase(it); + } else { + ++it; + } + } +} + void RtpFrameReferenceFinder::UpdateLastPictureIdWithPadding(uint16_t seq_num) { auto gop_seq_num_it = last_seq_num_gop_.upper_bound(seq_num); @@ -92,14 +114,16 @@ void RtpFrameReferenceFinder::RetryStashedFrames() { // Clean up stashed frames if there are too many. while (stashed_frames_.size() > kMaxStashedFrames) - stashed_frames_.pop(); + stashed_frames_.pop_front(); // Since frames are stashed if there is not enough data to determine their // frame references we should at most check |stashed_frames_.size()| in // order to not pop and push frames in and endless loop. + // NOTE! This function may be called recursively, hence the + // "!stashed_frames_.empty()" condition. for (size_t i = 0; i < num_stashed_frames && !stashed_frames_.empty(); ++i) { std::unique_ptr frame = std::move(stashed_frames_.front()); - stashed_frames_.pop(); + stashed_frames_.pop_front(); ManageFrame(std::move(frame)); } } @@ -128,7 +152,7 @@ void RtpFrameReferenceFinder::ManageFrameGeneric( // We have received a frame but not yet a keyframe, stash this frame. if (last_seq_num_gop_.empty()) { - stashed_frames_.emplace(std::move(frame)); + stashed_frames_.push_back(std::move(frame)); return; } @@ -156,7 +180,7 @@ void RtpFrameReferenceFinder::ManageFrameGeneric( if (frame->frame_type() == kVideoFrameDelta) { uint16_t prev_seq_num = frame->first_seq_num() - 1; if (prev_seq_num != last_picture_id_with_padding_gop) { - stashed_frames_.emplace(std::move(frame)); + stashed_frames_.push_back(std::move(frame)); return; } } @@ -237,7 +261,7 @@ void RtpFrameReferenceFinder::ManageFrameVp8( // If we don't have the base layer frame yet, stash this frame. if (layer_info_it == layer_info_.end()) { - stashed_frames_.emplace(std::move(frame)); + stashed_frames_.push_back(std::move(frame)); return; } @@ -276,7 +300,7 @@ void RtpFrameReferenceFinder::ManageFrameVp8( if (not_received_frame_it != not_yet_received_frames_.end() && AheadOf(frame->picture_id, *not_received_frame_it)) { - stashed_frames_.emplace(std::move(frame)); + stashed_frames_.push_back(std::move(frame)); return; } @@ -398,7 +422,7 @@ void RtpFrameReferenceFinder::ManageFrameVp9( // Gof info for this frame is not available yet, stash this frame. if (gof_info_it == gof_info_.end()) { - stashed_frames_.emplace(std::move(frame)); + stashed_frames_.push_back(std::move(frame)); return; } @@ -408,7 +432,7 @@ void RtpFrameReferenceFinder::ManageFrameVp9( // Make sure we don't miss any frame that could potentially have the // up switch flag set. if (MissingRequiredFrameVp9(frame->picture_id, *info)) { - stashed_frames_.emplace(std::move(frame)); + stashed_frames_.push_back(std::move(frame)); return; } diff --git a/webrtc/modules/video_coding/rtp_frame_reference_finder.h b/webrtc/modules/video_coding/rtp_frame_reference_finder.h index a812303b7e..e9e7d60a33 100644 --- a/webrtc/modules/video_coding/rtp_frame_reference_finder.h +++ b/webrtc/modules/video_coding/rtp_frame_reference_finder.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -40,9 +40,22 @@ class OnCompleteFrameCallback { class RtpFrameReferenceFinder { public: explicit RtpFrameReferenceFinder(OnCompleteFrameCallback* frame_callback); + + // Manage this frame until: + // - We have all information needed to determine its references, after + // which |frame_callback_| is called with the completed frame, or + // - We have too many stashed frames (determined by |kMaxStashedFrames) + // so we drop this frame, or + // - It gets cleared by ClearTo, which also means we drop it. void ManageFrame(std::unique_ptr frame); + + // Notifies that padding has been received, which the reference finder + // might need to calculate the references of a frame. void PaddingReceived(uint16_t seq_num); + // Clear all stashed frames that include packets older than |seq_num|. + void ClearTo(uint16_t seq_num); + private: static const uint16_t kPicIdLength = 1 << 7; static const uint8_t kMaxTemporalLayers = 5; @@ -146,7 +159,7 @@ class RtpFrameReferenceFinder { // Frames that have been fully received but didn't have all the information // needed to determine their references. - std::queue> stashed_frames_ GUARDED_BY(crit_); + std::deque> stashed_frames_ GUARDED_BY(crit_); // Holds the information about the last completed frame for a given temporal // layer given a Tl0 picture index. @@ -177,6 +190,11 @@ class RtpFrameReferenceFinder { kMaxTemporalLayers> missing_frames_for_layer_ GUARDED_BY(crit_); + // How far frames have been cleared by sequence number. A frame will be + // cleared if it contains a packet with a sequence number older than + // |cleared_to_seq_num_|. + int cleared_to_seq_num_ GUARDED_BY(crit_); + OnCompleteFrameCallback* frame_callback_; }; diff --git a/webrtc/modules/video_coding/rtp_frame_reference_finder_unittest.cc b/webrtc/modules/video_coding/rtp_frame_reference_finder_unittest.cc index 967acfc42b..1efd1c35b9 100644 --- a/webrtc/modules/video_coding/rtp_frame_reference_finder_unittest.cc +++ b/webrtc/modules/video_coding/rtp_frame_reference_finder_unittest.cc @@ -272,6 +272,24 @@ TEST_F(TestRtpFrameReferenceFinder, PaddingPacketsReorderedMultipleKeyframes) { EXPECT_EQ(4UL, frames_from_callback_.size()); } +TEST_F(TestRtpFrameReferenceFinder, ClearTo) { + uint16_t sn = Rand(); + + InsertGeneric(sn, sn + 1, true); + InsertGeneric(sn + 4, sn + 5, false); // stashed + EXPECT_EQ(1UL, frames_from_callback_.size()); + + InsertGeneric(sn + 6, sn + 7, true); // keyframe + EXPECT_EQ(2UL, frames_from_callback_.size()); + reference_finder_->ClearTo(sn + 7); + + InsertGeneric(sn + 8, sn + 9, false); // first frame after keyframe. + EXPECT_EQ(3UL, frames_from_callback_.size()); + + InsertGeneric(sn + 2, sn + 3, false); // late, cleared past this frame. + EXPECT_EQ(3UL, frames_from_callback_.size()); +} + TEST_F(TestRtpFrameReferenceFinder, Vp8NoPictureId) { uint16_t sn = Rand();