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}
This commit is contained in:
@ -26,11 +26,19 @@ RtpFrameReferenceFinder::RtpFrameReferenceFinder(
|
|||||||
: last_picture_id_(-1),
|
: last_picture_id_(-1),
|
||||||
last_unwrap_(-1),
|
last_unwrap_(-1),
|
||||||
current_ss_idx_(0),
|
current_ss_idx_(0),
|
||||||
|
cleared_to_seq_num_(-1),
|
||||||
frame_callback_(frame_callback) {}
|
frame_callback_(frame_callback) {}
|
||||||
|
|
||||||
void RtpFrameReferenceFinder::ManageFrame(
|
void RtpFrameReferenceFinder::ManageFrame(
|
||||||
std::unique_ptr<RtpFrameObject> frame) {
|
std::unique_ptr<RtpFrameObject> frame) {
|
||||||
rtc::CritScope lock(&crit_);
|
rtc::CritScope lock(&crit_);
|
||||||
|
|
||||||
|
// If we have cleared past this frame, drop it.
|
||||||
|
if (cleared_to_seq_num_ != -1 &&
|
||||||
|
AheadOf<uint16_t>(cleared_to_seq_num_, frame->first_seq_num())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (frame->codec_type()) {
|
switch (frame->codec_type()) {
|
||||||
case kVideoCodecULPFEC:
|
case kVideoCodecULPFEC:
|
||||||
case kVideoCodecRED:
|
case kVideoCodecRED:
|
||||||
@ -61,6 +69,20 @@ void RtpFrameReferenceFinder::PaddingReceived(uint16_t seq_num) {
|
|||||||
RetryStashedFrames();
|
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<uint16_t>(cleared_to_seq_num_, (*it)->first_seq_num())) {
|
||||||
|
it = stashed_frames_.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RtpFrameReferenceFinder::UpdateLastPictureIdWithPadding(uint16_t seq_num) {
|
void RtpFrameReferenceFinder::UpdateLastPictureIdWithPadding(uint16_t seq_num) {
|
||||||
auto gop_seq_num_it = last_seq_num_gop_.upper_bound(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.
|
// Clean up stashed frames if there are too many.
|
||||||
while (stashed_frames_.size() > kMaxStashedFrames)
|
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
|
// Since frames are stashed if there is not enough data to determine their
|
||||||
// frame references we should at most check |stashed_frames_.size()| in
|
// frame references we should at most check |stashed_frames_.size()| in
|
||||||
// order to not pop and push frames in and endless loop.
|
// 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) {
|
for (size_t i = 0; i < num_stashed_frames && !stashed_frames_.empty(); ++i) {
|
||||||
std::unique_ptr<RtpFrameObject> frame = std::move(stashed_frames_.front());
|
std::unique_ptr<RtpFrameObject> frame = std::move(stashed_frames_.front());
|
||||||
stashed_frames_.pop();
|
stashed_frames_.pop_front();
|
||||||
ManageFrame(std::move(frame));
|
ManageFrame(std::move(frame));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,7 +152,7 @@ void RtpFrameReferenceFinder::ManageFrameGeneric(
|
|||||||
|
|
||||||
// We have received a frame but not yet a keyframe, stash this frame.
|
// We have received a frame but not yet a keyframe, stash this frame.
|
||||||
if (last_seq_num_gop_.empty()) {
|
if (last_seq_num_gop_.empty()) {
|
||||||
stashed_frames_.emplace(std::move(frame));
|
stashed_frames_.push_back(std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +180,7 @@ void RtpFrameReferenceFinder::ManageFrameGeneric(
|
|||||||
if (frame->frame_type() == kVideoFrameDelta) {
|
if (frame->frame_type() == kVideoFrameDelta) {
|
||||||
uint16_t prev_seq_num = frame->first_seq_num() - 1;
|
uint16_t prev_seq_num = frame->first_seq_num() - 1;
|
||||||
if (prev_seq_num != last_picture_id_with_padding_gop) {
|
if (prev_seq_num != last_picture_id_with_padding_gop) {
|
||||||
stashed_frames_.emplace(std::move(frame));
|
stashed_frames_.push_back(std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +261,7 @@ void RtpFrameReferenceFinder::ManageFrameVp8(
|
|||||||
|
|
||||||
// If we don't have the base layer frame yet, stash this frame.
|
// If we don't have the base layer frame yet, stash this frame.
|
||||||
if (layer_info_it == layer_info_.end()) {
|
if (layer_info_it == layer_info_.end()) {
|
||||||
stashed_frames_.emplace(std::move(frame));
|
stashed_frames_.push_back(std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +300,7 @@ void RtpFrameReferenceFinder::ManageFrameVp8(
|
|||||||
if (not_received_frame_it != not_yet_received_frames_.end() &&
|
if (not_received_frame_it != not_yet_received_frames_.end() &&
|
||||||
AheadOf<uint16_t, kPicIdLength>(frame->picture_id,
|
AheadOf<uint16_t, kPicIdLength>(frame->picture_id,
|
||||||
*not_received_frame_it)) {
|
*not_received_frame_it)) {
|
||||||
stashed_frames_.emplace(std::move(frame));
|
stashed_frames_.push_back(std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +422,7 @@ void RtpFrameReferenceFinder::ManageFrameVp9(
|
|||||||
|
|
||||||
// Gof info for this frame is not available yet, stash this frame.
|
// Gof info for this frame is not available yet, stash this frame.
|
||||||
if (gof_info_it == gof_info_.end()) {
|
if (gof_info_it == gof_info_.end()) {
|
||||||
stashed_frames_.emplace(std::move(frame));
|
stashed_frames_.push_back(std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +432,7 @@ void RtpFrameReferenceFinder::ManageFrameVp9(
|
|||||||
// Make sure we don't miss any frame that could potentially have the
|
// Make sure we don't miss any frame that could potentially have the
|
||||||
// up switch flag set.
|
// up switch flag set.
|
||||||
if (MissingRequiredFrameVp9(frame->picture_id, *info)) {
|
if (MissingRequiredFrameVp9(frame->picture_id, *info)) {
|
||||||
stashed_frames_.emplace(std::move(frame));
|
stashed_frames_.push_back(std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <queue>
|
#include <deque>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -40,9 +40,22 @@ class OnCompleteFrameCallback {
|
|||||||
class RtpFrameReferenceFinder {
|
class RtpFrameReferenceFinder {
|
||||||
public:
|
public:
|
||||||
explicit RtpFrameReferenceFinder(OnCompleteFrameCallback* frame_callback);
|
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<RtpFrameObject> frame);
|
void ManageFrame(std::unique_ptr<RtpFrameObject> 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);
|
void PaddingReceived(uint16_t seq_num);
|
||||||
|
|
||||||
|
// Clear all stashed frames that include packets older than |seq_num|.
|
||||||
|
void ClearTo(uint16_t seq_num);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint16_t kPicIdLength = 1 << 7;
|
static const uint16_t kPicIdLength = 1 << 7;
|
||||||
static const uint8_t kMaxTemporalLayers = 5;
|
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
|
// Frames that have been fully received but didn't have all the information
|
||||||
// needed to determine their references.
|
// needed to determine their references.
|
||||||
std::queue<std::unique_ptr<RtpFrameObject>> stashed_frames_ GUARDED_BY(crit_);
|
std::deque<std::unique_ptr<RtpFrameObject>> stashed_frames_ GUARDED_BY(crit_);
|
||||||
|
|
||||||
// Holds the information about the last completed frame for a given temporal
|
// Holds the information about the last completed frame for a given temporal
|
||||||
// layer given a Tl0 picture index.
|
// layer given a Tl0 picture index.
|
||||||
@ -177,6 +190,11 @@ class RtpFrameReferenceFinder {
|
|||||||
kMaxTemporalLayers>
|
kMaxTemporalLayers>
|
||||||
missing_frames_for_layer_ GUARDED_BY(crit_);
|
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_;
|
OnCompleteFrameCallback* frame_callback_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -272,6 +272,24 @@ TEST_F(TestRtpFrameReferenceFinder, PaddingPacketsReorderedMultipleKeyframes) {
|
|||||||
EXPECT_EQ(4UL, frames_from_callback_.size());
|
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) {
|
TEST_F(TestRtpFrameReferenceFinder, Vp8NoPictureId) {
|
||||||
uint16_t sn = Rand();
|
uint16_t sn = Rand();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user