/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/video_coding/rtp_vp9_ref_finder.h" #include #include #include "modules/rtp_rtcp/source/frame_object.h" #include "test/gmock.h" #include "test/gtest.h" using ::testing::Contains; using ::testing::Matcher; using ::testing::MatcherInterface; using ::testing::Matches; using ::testing::MatchResultListener; using ::testing::Pointee; using ::testing::Property; using ::testing::SizeIs; using ::testing::UnorderedElementsAreArray; namespace webrtc { namespace { class Frame { public: Frame& SeqNum(uint16_t start, uint16_t end) { seq_num_start = start; seq_num_end = end; return *this; } Frame& AsKeyFrame(bool is_keyframe = true) { keyframe = is_keyframe; return *this; } Frame& Pid(int pid) { picture_id = pid; return *this; } Frame& SidAndTid(int sid, int tid) { spatial_id = sid; temporal_id = tid; return *this; } Frame& Tl0(int tl0) { tl0_idx = tl0; return *this; } Frame& AsUpswitch(bool is_up = true) { up_switch = is_up; return *this; } Frame& AsInterLayer(bool is_inter_layer = true) { inter_layer = is_inter_layer; return *this; } Frame& NotAsInterPic(bool is_inter_pic = false) { inter_pic = is_inter_pic; return *this; } Frame& Gof(GofInfoVP9* ss) { scalability_structure = ss; return *this; } Frame& FlexRefs(const std::vector& refs) { flex_refs = refs; return *this; } operator std::unique_ptr() { RTPVideoHeaderVP9 vp9_header{}; vp9_header.picture_id = *picture_id; vp9_header.temporal_idx = *temporal_id; vp9_header.spatial_idx = *spatial_id; if (tl0_idx.has_value()) { RTC_DCHECK(flex_refs.empty()); vp9_header.flexible_mode = false; vp9_header.tl0_pic_idx = *tl0_idx; } else { vp9_header.flexible_mode = true; vp9_header.num_ref_pics = flex_refs.size(); for (size_t i = 0; i < flex_refs.size(); ++i) { vp9_header.pid_diff[i] = flex_refs.at(i); } } vp9_header.temporal_up_switch = up_switch; vp9_header.inter_layer_predicted = inter_layer; vp9_header.inter_pic_predicted = inter_pic && !keyframe; if (scalability_structure != nullptr) { vp9_header.ss_data_available = true; vp9_header.gof = *scalability_structure; } RTPVideoHeader video_header; video_header.frame_type = keyframe ? VideoFrameType::kVideoFrameKey : VideoFrameType::kVideoFrameDelta; video_header.video_type_header = vp9_header; // clang-format off return std::make_unique( seq_num_start, seq_num_end, /*markerBit=*/true, /*times_nacked=*/0, /*first_packet_received_time=*/0, /*last_packet_received_time=*/0, /*rtp_timestamp=*/0, /*ntp_time_ms=*/0, VideoSendTiming(), /*payload_type=*/0, kVideoCodecVP9, kVideoRotation_0, VideoContentType::UNSPECIFIED, video_header, /*color_space=*/absl::nullopt, RtpPacketInfos(), EncodedImageBuffer::Create(/*size=*/0)); // clang-format on } private: uint16_t seq_num_start = 0; uint16_t seq_num_end = 0; bool keyframe = false; absl::optional picture_id; absl::optional spatial_id; absl::optional temporal_id; absl::optional tl0_idx; bool up_switch = false; bool inter_layer = false; bool inter_pic = true; GofInfoVP9* scalability_structure = nullptr; std::vector flex_refs; }; using FrameVector = std::vector>; // Would have been nice to use the MATCHER_P3 macro instead, but when used it // fails to infer the type of the vector if not explicitly given in the class HasFrameMatcher : public MatcherInterface { public: explicit HasFrameMatcher(int64_t frame_id, const std::vector& expected_refs) : frame_id_(frame_id), expected_refs_(expected_refs) {} bool MatchAndExplain(const FrameVector& frames, MatchResultListener* result_listener) const override { auto it = std::find_if(frames.begin(), frames.end(), [this](const std::unique_ptr& f) { return f->Id() == frame_id_; }); if (it == frames.end()) { if (result_listener->IsInterested()) { *result_listener << "No frame with frame_id:" << frame_id_; } return false; } rtc::ArrayView actual_refs((*it)->references, (*it)->num_references); if (!Matches(UnorderedElementsAreArray(expected_refs_))(actual_refs)) { if (result_listener->IsInterested()) { *result_listener << "Frame with frame_id:" << frame_id_ << " and " << actual_refs.size() << " references { "; for (auto r : actual_refs) { *result_listener << r << " "; } *result_listener << "}"; } return false; } return true; } void DescribeTo(std::ostream* os) const override { *os << "frame with frame_id:" << frame_id_ << " and " << expected_refs_.size() << " references { "; for (auto r : expected_refs_) { *os << r << " "; } *os << "}"; } private: const int64_t frame_id_; const std::vector expected_refs_; }; } // namespace class RtpVp9RefFinderTest : public ::testing::Test { protected: RtpVp9RefFinderTest() : ref_finder_(std::make_unique()) {} void Insert(std::unique_ptr frame) { for (auto& f : ref_finder_->ManageFrame(std::move(frame))) { frames_.push_back(std::move(f)); } } std::unique_ptr ref_finder_; FrameVector frames_; }; Matcher HasFrameWithIdAndRefs(int64_t frame_id, std::vector refs) { return MakeMatcher(new HasFrameMatcher(frame_id, refs)); } TEST_F(RtpVp9RefFinderTest, GofInsertOneFrame) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode1); Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).AsKeyFrame().Gof(&ss)); EXPECT_EQ(frames_.size(), 1UL); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayers_0) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode1); // Only 1 spatial layer. Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).AsKeyFrame().Gof(&ss)); Insert(Frame().Pid(2).SidAndTid(0, 0).Tl0(1)); EXPECT_EQ(frames_.size(), 2UL); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {5})); } TEST_F(RtpVp9RefFinderTest, GofSpatialLayers_2) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode1); // Only 1 spatial layer. Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).AsKeyFrame().Gof(&ss)); Insert(Frame().Pid(2).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(2).SidAndTid(1, 0).Tl0(1).NotAsInterPic()); Insert(Frame().Pid(3).SidAndTid(0, 0).Tl0(2)); Insert(Frame().Pid(3).SidAndTid(1, 0).Tl0(2)); EXPECT_EQ(frames_.size(), 5UL); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {5})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(11, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(16, {11})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayersReordered_0) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode1); // Only 1 spatial layer. Insert(Frame().Pid(2).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(2).SidAndTid(1, 0).Tl0(1).NotAsInterPic()); Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).AsKeyFrame().Gof(&ss)); Insert(Frame().Pid(3).SidAndTid(0, 0).Tl0(2)); Insert(Frame().Pid(3).SidAndTid(1, 0).Tl0(2)); Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(3)); Insert(Frame().Pid(5).SidAndTid(1, 0).Tl0(4)); Insert(Frame().Pid(4).SidAndTid(1, 0).Tl0(3)); Insert(Frame().Pid(5).SidAndTid(0, 0).Tl0(4)); EXPECT_EQ(frames_.size(), 9UL); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {5})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(11, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(16, {11})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {15})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(21, {16})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(26, {21})); } TEST_F(RtpVp9RefFinderTest, GofSkipFramesTemporalLayers_01) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode2); // 0101 pattern Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1).SidAndTid(0, 1).Tl0(0)); // Skip GOF with tl0 1 Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(2).AsKeyFrame().Gof(&ss)); Insert(Frame().Pid(5).SidAndTid(0, 1).Tl0(2)); // Skip GOF with tl0 3 // Skip GOF with tl0 4 Insert(Frame().Pid(10).SidAndTid(0, 0).Tl0(5).Gof(&ss)); Insert(Frame().Pid(11).SidAndTid(0, 1).Tl0(5)); ASSERT_EQ(6UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(50, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(55, {50})); } TEST_F(RtpVp9RefFinderTest, GofSkipFramesTemporalLayers_0212) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode3); // 02120212 pattern Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1).SidAndTid(0, 2).Tl0(0)); Insert(Frame().Pid(2).SidAndTid(0, 1).Tl0(0)); Insert(Frame().Pid(3).SidAndTid(0, 2).Tl0(0)); ASSERT_EQ(4UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); // Skip frames with tl0 = 1 Insert(Frame().Pid(8).SidAndTid(0, 0).Tl0(2).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(9).SidAndTid(0, 2).Tl0(2)); Insert(Frame().Pid(10).SidAndTid(0, 1).Tl0(2)); Insert(Frame().Pid(11).SidAndTid(0, 2).Tl0(2)); ASSERT_EQ(8UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(40, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(45, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(50, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(55, {50})); // Now insert frames with tl0 = 1 Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(1).AsKeyFrame().Gof(&ss)); Insert(Frame().Pid(7).SidAndTid(0, 2).Tl0(1)); ASSERT_EQ(9UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {})); Insert(Frame().Pid(5).SidAndTid(0, 2).Tl0(1)); Insert(Frame().Pid(6).SidAndTid(0, 1).Tl0(1)); ASSERT_EQ(12UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(30, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(35, {30})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayers_01) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode2); // 0101 pattern Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1).SidAndTid(0, 1).Tl0(0)); Insert(Frame().Pid(2).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(3).SidAndTid(0, 1).Tl0(1)); ASSERT_EQ(4UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayersReordered_01) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode2); // 01 pattern Insert(Frame().Pid(1).SidAndTid(0, 1).Tl0(0)); Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(2).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(2)); Insert(Frame().Pid(3).SidAndTid(0, 1).Tl0(1)); Insert(Frame().Pid(5).SidAndTid(0, 1).Tl0(2)); Insert(Frame().Pid(7).SidAndTid(0, 1).Tl0(3)); Insert(Frame().Pid(6).SidAndTid(0, 0).Tl0(3)); Insert(Frame().Pid(8).SidAndTid(0, 0).Tl0(4)); Insert(Frame().Pid(9).SidAndTid(0, 1).Tl0(4)); ASSERT_EQ(10UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(30, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(35, {30})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(40, {30})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(45, {40})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayers_0212) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode3); // 0212 pattern Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1).SidAndTid(0, 2).Tl0(0)); Insert(Frame().Pid(2).SidAndTid(0, 1).Tl0(0)); Insert(Frame().Pid(3).SidAndTid(0, 2).Tl0(0)); Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(5).SidAndTid(0, 2).Tl0(1)); Insert(Frame().Pid(6).SidAndTid(0, 1).Tl0(1)); Insert(Frame().Pid(7).SidAndTid(0, 2).Tl0(1)); ASSERT_EQ(8UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(30, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(35, {30})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayersReordered_0212) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode3); // 0212 pattern Insert(Frame().Pid(2).SidAndTid(0, 1).Tl0(0)); Insert(Frame().Pid(1).SidAndTid(0, 2).Tl0(0)); Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(3).SidAndTid(0, 2).Tl0(0)); Insert(Frame().Pid(6).SidAndTid(0, 1).Tl0(1)); Insert(Frame().Pid(5).SidAndTid(0, 2).Tl0(1)); Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(9).SidAndTid(0, 2).Tl0(2)); Insert(Frame().Pid(7).SidAndTid(0, 2).Tl0(1)); Insert(Frame().Pid(8).SidAndTid(0, 0).Tl0(2)); Insert(Frame().Pid(11).SidAndTid(0, 2).Tl0(2)); Insert(Frame().Pid(10).SidAndTid(0, 1).Tl0(2)); ASSERT_EQ(12UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(30, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(35, {30})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(40, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(45, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(50, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(55, {50})); } TEST_F(RtpVp9RefFinderTest, GofTemporalLayersReordered_01_0212) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode2); // 01 pattern Insert(Frame().Pid(1).SidAndTid(0, 1).Tl0(0)); Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(3).SidAndTid(0, 1).Tl0(1)); Insert(Frame().Pid(6).SidAndTid(0, 1).Tl0(2)); ss.SetGofInfoVP9(kTemporalStructureMode3); // 0212 pattern Insert(Frame().Pid(4).SidAndTid(0, 0).Tl0(2).Gof(&ss)); Insert(Frame().Pid(2).SidAndTid(0, 0).Tl0(1)); Insert(Frame().Pid(5).SidAndTid(0, 2).Tl0(2)); Insert(Frame().Pid(8).SidAndTid(0, 0).Tl0(3)); Insert(Frame().Pid(10).SidAndTid(0, 1).Tl0(3)); Insert(Frame().Pid(7).SidAndTid(0, 2).Tl0(2)); Insert(Frame().Pid(11).SidAndTid(0, 2).Tl0(3)); Insert(Frame().Pid(9).SidAndTid(0, 2).Tl0(3)); ASSERT_EQ(12UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(15, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(25, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(30, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(35, {30})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(40, {20})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(45, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(50, {40})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(55, {50})); } TEST_F(RtpVp9RefFinderTest, FlexibleModeOneFrame) { Insert(Frame().Pid(0).SidAndTid(0, 0).AsKeyFrame()); ASSERT_EQ(1UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); } TEST_F(RtpVp9RefFinderTest, FlexibleModeTwoSpatialLayers) { Insert(Frame().Pid(0).SidAndTid(0, 0).AsKeyFrame()); Insert(Frame().Pid(0).SidAndTid(1, 0).AsKeyFrame().AsInterLayer()); Insert(Frame().Pid(1).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(2).SidAndTid(0, 0).FlexRefs({2})); Insert(Frame().Pid(2).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(3).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(4).SidAndTid(0, 0).FlexRefs({2})); Insert(Frame().Pid(4).SidAndTid(1, 0).FlexRefs({1})); ASSERT_EQ(8UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(1, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(6, {1})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(11, {6})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(16, {11})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(21, {16})); } TEST_F(RtpVp9RefFinderTest, FlexibleModeTwoSpatialLayersReordered) { Insert(Frame().Pid(0).SidAndTid(1, 0).AsKeyFrame().AsInterLayer()); Insert(Frame().Pid(1).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(0).SidAndTid(0, 0).AsKeyFrame()); Insert(Frame().Pid(2).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(3).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(2).SidAndTid(0, 0).FlexRefs({2})); Insert(Frame().Pid(4).SidAndTid(1, 0).FlexRefs({1})); Insert(Frame().Pid(4).SidAndTid(0, 0).FlexRefs({2})); ASSERT_EQ(8UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(1, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(6, {1})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(10, {0})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(11, {6})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(16, {11})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(20, {10})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(21, {16})); } TEST_F(RtpVp9RefFinderTest, WrappingFlexReference) { Insert(Frame().Pid(0).SidAndTid(0, 0).FlexRefs({1})); ASSERT_EQ(1UL, frames_.size()); const EncodedFrame& frame = *frames_[0]; ASSERT_EQ(frame.Id() - frame.references[0], 5); } TEST_F(RtpVp9RefFinderTest, GofPidJump) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode3); Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1000).SidAndTid(0, 0).Tl0(1)); } TEST_F(RtpVp9RefFinderTest, GofTl0Jump) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode3); Insert(Frame() .Pid(0) .SidAndTid(0, 0) .Tl0(125) .AsUpswitch() .AsKeyFrame() .NotAsInterPic() .Gof(&ss)); Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).Gof(&ss)); } TEST_F(RtpVp9RefFinderTest, GofTidTooHigh) { const int kMaxTemporalLayers = 5; GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode2); ss.temporal_idx[1] = kMaxTemporalLayers; Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(1)); ASSERT_EQ(1UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); } TEST_F(RtpVp9RefFinderTest, GofZeroFrames) { GofInfoVP9 ss; ss.num_frames_in_gof = 0; Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0).AsKeyFrame().NotAsInterPic().Gof( &ss)); Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(1)); ASSERT_EQ(2UL, frames_.size()); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(0, {})); EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {0})); } TEST_F(RtpVp9RefFinderTest, SpatialIndex) { Insert(Frame().Pid(0).SidAndTid(0, 0).AsKeyFrame()); Insert(Frame().Pid(0).SidAndTid(1, 0).AsKeyFrame()); Insert(Frame().Pid(0).SidAndTid(2, 0).AsKeyFrame()); ASSERT_EQ(3UL, frames_.size()); EXPECT_THAT(frames_, Contains(Pointee(Property(&EncodedFrame::SpatialIndex, 0)))); EXPECT_THAT(frames_, Contains(Pointee(Property(&EncodedFrame::SpatialIndex, 1)))); EXPECT_THAT(frames_, Contains(Pointee(Property(&EncodedFrame::SpatialIndex, 2)))); } TEST_F(RtpVp9RefFinderTest, StashedFramesDoNotWrapTl0Backwards) { GofInfoVP9 ss; ss.SetGofInfoVP9(kTemporalStructureMode1); Insert(Frame().Pid(0).SidAndTid(0, 0).Tl0(0)); EXPECT_THAT(frames_, SizeIs(0)); Insert(Frame().Pid(128).SidAndTid(0, 0).Tl0(128).AsKeyFrame().Gof(&ss)); EXPECT_THAT(frames_, SizeIs(1)); Insert(Frame().Pid(129).SidAndTid(0, 0).Tl0(129)); EXPECT_THAT(frames_, SizeIs(2)); } } // namespace webrtc