mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00

This is a reland of commit 7ae48c452a
with updated RtpVp9RefFinder
RtpVp9RefFinder relied on the fact that frames with (inter_pic_predicted=true && inter_layer_predicted=true) were marked as keyframes. Since this is not the case anymore, the related code paths in RtpVp9RefFinder have been deleted.
Calculation of gof_info_[] index for non-keyframes has been updated to account for that fact it is now possible to received multiple T0 frames belonging to the same temporal unit (we don't need to do "unwrapped_tl0 - 1" in this case).
Original change's description:
> Mark frames with inter_layer_predicted=true as delta frames
>
> As it is currently implemented, the VP9 depacketizer decides packet's frame type based on p_bit ("Inter-picture predicted layer frame"). p_bit is set to 0 for upper spatial layer frames of keyframe since they do not have temporal refs. This results in marking packets of upper spatial layer frames, and, eventually these frames, of SVC keyframes as "keyframe" while they are in fact delta frames.
>
> Normally spatial layer frames are merged into a superframe and the superframe is passed to decoder. But passing individual layers to a single decoder instance is a valid scenario too and is used in downstream projects. In this case, an upper layer frame marked as keyframe may cause decoder reset [2] and break decoding.
>
> This CL changes frame type decision logic in the VP9 depacketizer such that only packets with both P and D (inter-layer predicted) bits unset are considered as keyframe packets.
>
> When spatial layer frames are merged into a superframe in CombineAndDeleteFrames [1], frame type of the superframe is inferred from the lowest spatial layer frame.
>
> [1] https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_helpers.cc;l=53
>
> [2] https://source.corp.google.com/piper///depot/google3/third_party/webrtc/files/stable/webrtc/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc;l=209
>
> Bug: webrtc:15827
> Change-Id: Idc3445636f0eae0192dac998876fedec48628560
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/343342
> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
> Cr-Commit-Position: refs/heads/main@{#41939}
Bug: webrtc:15827
Change-Id: Ic69b94989919cf6d353bceea85d0eba63bc500ee
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/344144
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41985}
649 lines
23 KiB
C++
649 lines
23 KiB
C++
/*
|
|
* 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 <utility>
|
|
#include <vector>
|
|
|
|
#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<uint8_t>& refs) {
|
|
flex_refs = refs;
|
|
return *this;
|
|
}
|
|
|
|
operator std::unique_ptr<RtpFrameObject>() {
|
|
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<RtpFrameObject>(
|
|
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<int> picture_id;
|
|
absl::optional<int> spatial_id;
|
|
absl::optional<int> temporal_id;
|
|
absl::optional<int> tl0_idx;
|
|
bool up_switch = false;
|
|
bool inter_layer = false;
|
|
bool inter_pic = true;
|
|
GofInfoVP9* scalability_structure = nullptr;
|
|
std::vector<uint8_t> flex_refs;
|
|
};
|
|
|
|
using FrameVector = std::vector<std::unique_ptr<EncodedFrame>>;
|
|
|
|
// 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<const FrameVector&> {
|
|
public:
|
|
explicit HasFrameMatcher(int64_t frame_id,
|
|
const std::vector<int64_t>& 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<EncodedFrame>& 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<int64_t> 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<int64_t> expected_refs_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
class RtpVp9RefFinderTest : public ::testing::Test {
|
|
protected:
|
|
RtpVp9RefFinderTest() : ref_finder_(std::make_unique<RtpVp9RefFinder>()) {}
|
|
|
|
void Insert(std::unique_ptr<RtpFrameObject> frame) {
|
|
for (auto& f : ref_finder_->ManageFrame(std::move(frame))) {
|
|
frames_.push_back(std::move(f));
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<RtpVp9RefFinder> ref_finder_;
|
|
FrameVector frames_;
|
|
};
|
|
|
|
Matcher<const FrameVector&> HasFrameWithIdAndRefs(int64_t frame_id,
|
|
std::vector<int64_t> 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, GofInterLayerPredS0KeyS1Delta) {
|
|
GofInfoVP9 ss;
|
|
ss.SetGofInfoVP9(kTemporalStructureMode1);
|
|
|
|
Insert(Frame().Pid(1).SidAndTid(0, 0).Tl0(0).AsKeyFrame().Gof(&ss));
|
|
Insert(Frame().Pid(1).SidAndTid(1, 0).Tl0(0).AsInterLayer().NotAsInterPic());
|
|
|
|
ASSERT_EQ(2UL, frames_.size());
|
|
EXPECT_THAT(frames_, HasFrameWithIdAndRefs(5, {}));
|
|
EXPECT_THAT(frames_, HasFrameWithIdAndRefs(6, {5}));
|
|
}
|
|
|
|
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
|