Always unwrap VP9 TL0PicIdx forward if the frame is newer.
Bug: webrtc:12979
Change-Id: Idcc14f8f61b04f9eb194b55ffa40fb95319a881c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/226463
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34513}
diff --git a/modules/video_coding/rtp_vp9_ref_finder.cc b/modules/video_coding/rtp_vp9_ref_finder.cc
index b44bb25..d823871 100644
--- a/modules/video_coding/rtp_vp9_ref_finder.cc
+++ b/modules/video_coding/rtp_vp9_ref_finder.cc
@@ -77,8 +77,21 @@
}
GofInfo* info;
- int64_t unwrapped_tl0 =
- tl0_unwrapper_.Unwrap(codec_header.tl0_pic_idx & 0xFF);
+
+ // The VP9 `tl0_pic_idx` is 8 bits and therefor wraps often. In the case of
+ // packet loss the next received frame could have a `tl0_pic_idx` that looks
+ // older than the previously received frame. Always wrap forward if |frame| is
+ // newer in RTP packet sequence number order.
+ int64_t unwrapped_tl0;
+ auto tl0_it = gof_info_.rbegin();
+ if (tl0_it != gof_info_.rend() &&
+ AheadOf(frame->last_seq_num(), tl0_it->second.last_seq_num)) {
+ unwrapped_tl0 =
+ tl0_unwrapper_.UnwrapForward(codec_header.tl0_pic_idx & 0xFF);
+ } else {
+ unwrapped_tl0 = tl0_unwrapper_.Unwrap(codec_header.tl0_pic_idx & 0xFF);
+ }
+
if (codec_header.ss_data_available) {
if (codec_header.temporal_idx != 0) {
RTC_LOG(LS_WARNING) << "Received scalability structure on a non base "
@@ -104,9 +117,9 @@
current_ss_idx_ = Add<kMaxGofSaved>(current_ss_idx_, 1);
scalability_structures_[current_ss_idx_] = gof;
scalability_structures_[current_ss_idx_].pid_start = frame->Id();
- gof_info_.emplace(
- unwrapped_tl0,
- GofInfo(&scalability_structures_[current_ss_idx_], frame->Id()));
+ gof_info_.emplace(unwrapped_tl0,
+ GofInfo(&scalability_structures_[current_ss_idx_],
+ frame->Id(), frame->last_seq_num()));
}
const auto gof_info_it = gof_info_.find(unwrapped_tl0);
@@ -147,7 +160,8 @@
if (codec_header.temporal_idx == 0) {
gof_info_it = gof_info_
.emplace(unwrapped_tl0,
- GofInfo(gof_info_it->second.gof, frame->Id()))
+ GofInfo(gof_info_it->second.gof, frame->Id(),
+ frame->last_seq_num()))
.first;
}
diff --git a/modules/video_coding/rtp_vp9_ref_finder.h b/modules/video_coding/rtp_vp9_ref_finder.h
index 81008fea..dc912b6 100644
--- a/modules/video_coding/rtp_vp9_ref_finder.h
+++ b/modules/video_coding/rtp_vp9_ref_finder.h
@@ -42,10 +42,13 @@
enum FrameDecision { kStash, kHandOff, kDrop };
struct GofInfo {
- GofInfo(GofInfoVP9* gof, uint16_t last_picture_id)
- : gof(gof), last_picture_id(last_picture_id) {}
+ GofInfo(GofInfoVP9* gof, uint16_t last_picture_id, uint16_t last_seq_num)
+ : gof(gof),
+ last_picture_id(last_picture_id),
+ last_seq_num(last_seq_num) {}
GofInfoVP9* gof;
uint16_t last_picture_id;
+ uint16_t last_seq_num;
};
FrameDecision ManageFrameInternal(RtpFrameObject* frame);
diff --git a/modules/video_coding/rtp_vp9_ref_finder_unittest.cc b/modules/video_coding/rtp_vp9_ref_finder_unittest.cc
index 6de7ce1..9fe24c4 100644
--- a/modules/video_coding/rtp_vp9_ref_finder_unittest.cc
+++ b/modules/video_coding/rtp_vp9_ref_finder_unittest.cc
@@ -23,6 +23,7 @@
using ::testing::MatchResultListener;
using ::testing::Pointee;
using ::testing::Property;
+using ::testing::SizeIs;
using ::testing::UnorderedElementsAreArray;
namespace webrtc {
@@ -661,6 +662,24 @@
Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).Gof(&ss));
}
+TEST_F(RtpVp9RefFinderTest, DontDiscardNewerFramesWithWrappedTl0) {
+ GofInfoVP9 ss;
+ ss.SetGofInfoVP9(kTemporalStructureMode1);
+
+ Insert(
+ Frame().Pid(0).SidAndTid(0, 0).Tl0(0).SeqNum(0, 0).AsKeyFrame().Gof(&ss));
+ // ... 254 frames are lost ...
+ Insert(Frame()
+ .Pid(255)
+ .SidAndTid(0, 0)
+ .Tl0(255)
+ .SeqNum(255, 255)
+ .AsKeyFrame()
+ .Gof(&ss));
+
+ EXPECT_THAT(frames_, SizeIs(2));
+}
+
TEST_F(RtpVp9RefFinderTest, GofTidTooHigh) {
const int kMaxTemporalLayers = 5;
GofInfoVP9 ss;