Add test::FakeEncodedFrame for testing

Change-Id: I1c8fabe5caf2c723487ec1cd71a379e922026a9d
Bug: webrtc:13996
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/260001
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36654}
This commit is contained in:
Evan Shrubsole
2022-04-26 10:09:04 +02:00
committed by WebRTC LUCI CQ
parent 65dcc47b8b
commit a0ee64c57e
9 changed files with 602 additions and 414 deletions

View File

@ -1279,6 +1279,7 @@ if (rtc_include_tests) {
"../../system_wrappers",
"../../system_wrappers:field_trial",
"../../system_wrappers:metrics",
"../../test:fake_encoded_frame",
"../../test:fake_video_codecs",
"../../test:field_trial",
"../../test:fileutils",

View File

@ -12,6 +12,7 @@
#include <vector>
#include "api/video/encoded_frame.h"
#include "test/fake_encoded_frame.h"
#include "test/field_trial.h"
#include "test/gmock.h"
#include "test/gtest.h"
@ -29,67 +30,19 @@ MATCHER_P(FrameWithId, id, "") {
return Matches(Eq(id))(arg->Id());
}
class FakeEncodedFrame : public EncodedFrame {
public:
int64_t ReceivedTime() const override { return 0; }
int64_t RenderTime() const override { return 0; }
};
class Builder {
public:
Builder& Time(uint32_t rtp_timestamp) {
rtp_timestamp_ = rtp_timestamp;
return *this;
}
Builder& Id(int64_t frame_id) {
frame_id_ = frame_id;
return *this;
}
Builder& AsLast() {
last_spatial_layer_ = true;
return *this;
}
Builder& Refs(const std::vector<int64_t>& references) {
references_ = references;
return *this;
}
std::unique_ptr<FakeEncodedFrame> Build() {
RTC_CHECK_LE(references_.size(), EncodedFrame::kMaxFrameReferences);
RTC_CHECK(rtp_timestamp_.has_value());
RTC_CHECK(frame_id_.has_value());
auto frame = std::make_unique<FakeEncodedFrame>();
frame->SetTimestamp(*rtp_timestamp_);
frame->SetId(*frame_id_);
frame->is_last_spatial_layer = last_spatial_layer_;
for (int64_t ref : references_) {
frame->references[frame->num_references] = ref;
frame->num_references++;
}
return frame;
}
private:
absl::optional<uint32_t> rtp_timestamp_;
absl::optional<int64_t> frame_id_;
bool last_spatial_layer_ = false;
std::vector<int64_t> references_;
};
TEST(FrameBuffer3Test, RejectInvalidRefs) {
test::ScopedKeyValueConfig field_trials;
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
// Ref must be less than the id of this frame.
buffer.InsertFrame(Builder().Time(0).Id(0).Refs({0}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(0).Id(0).Refs({0}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt));
// Duplicate ids are also invalid.
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1, 1}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1, 1}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(1));
}
@ -100,11 +53,12 @@ TEST(FrameBuffer3Test, LastContinuousUpdatesOnInsertedFrames) {
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt));
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
buffer.InsertFrame(Builder().Time(10).Id(1).Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(1));
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(10).Id(2).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(2));
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(2));
}
@ -114,11 +68,13 @@ TEST(FrameBuffer3Test, LastContinuousFrameReordering) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({2}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(1));
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(3));
}
@ -127,9 +83,10 @@ TEST(FrameBuffer3Test, LastContinuousTemporalUnit) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).Build());
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(10).Id(2).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(2));
}
@ -138,12 +95,14 @@ TEST(FrameBuffer3Test, LastContinuousTemporalUnitReordering) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).Build());
buffer.InsertFrame(Builder().Time(20).Id(3).Refs({1}).Build());
buffer.InsertFrame(Builder().Time(20).Id(4).Refs({2, 3}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(20).Id(3).Refs({1}).Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(4).Refs({2, 3}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(10).Id(2).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(4));
}
@ -154,7 +113,7 @@ TEST(FrameBuffer3Test, NextDecodable) {
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(),
Eq(absl::nullopt));
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(10U));
}
@ -163,9 +122,10 @@ TEST(FrameBuffer3Test, AdvanceNextDecodableOnExtraction) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(20).Id(2).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({2}).AsLast().Build());
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(10U));
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
@ -183,9 +143,11 @@ TEST(FrameBuffer3Test, AdvanceLastDecodableOnExtraction) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.LastDecodableTemporalUnitRtpTimestamp(), Eq(10U));
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
@ -198,10 +160,10 @@ TEST(FrameBuffer3Test, FrameUpdatesNextDecodable) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(20).Id(2).AsLast().Build());
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(20U));
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(10U));
}
@ -209,18 +171,23 @@ TEST(FrameBuffer3Test, KeyframeClearsFullBuffer) {
test::ScopedKeyValueConfig field_trials;
FrameBuffer buffer(/*max_frame_slots=*/5, /*max_decode_history=*/10,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(Builder().Time(40).Id(4).Refs({3}).AsLast().Build());
buffer.InsertFrame(Builder().Time(50).Id(5).Refs({4}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(40).Id(4).Refs({3}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(50).Id(5).Refs({4}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(5));
// Frame buffer is full
buffer.InsertFrame(Builder().Time(60).Id(6).Refs({5}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(60).Id(6).Refs({5}).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(5));
buffer.InsertFrame(Builder().Time(70).Id(7).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(70).Id(7).AsLast().Build());
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(7));
}
@ -228,9 +195,11 @@ TEST(FrameBuffer3Test, DropNextDecodableTemporalUnit) {
test::ScopedKeyValueConfig field_trials;
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({1}).AsLast().Build());
buffer.ExtractNextDecodableTemporalUnit();
buffer.DropNextDecodableTemporalUnit();
@ -242,15 +211,18 @@ TEST(FrameBuffer3Test, OldFramesAreIgnored) {
test::ScopedKeyValueConfig field_trials;
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.ExtractNextDecodableTemporalUnit();
buffer.ExtractNextDecodableTemporalUnit();
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(3)));
@ -260,13 +232,15 @@ TEST(FrameBuffer3Test, ReturnFullTemporalUnitKSVC) {
test::ScopedKeyValueConfig field_trials;
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).Build());
buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).Build());
buffer.InsertFrame(Builder().Time(10).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(2).Refs({1}).Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(10).Id(3).Refs({2}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(1), FrameWithId(2), FrameWithId(3)));
buffer.InsertFrame(Builder().Time(20).Id(4).Refs({3}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(4).Refs({3}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(4)));
}
@ -275,11 +249,15 @@ TEST(FrameBuffer3Test, InterleavedStream) {
test::ScopedKeyValueConfig field_trials;
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build());
buffer.InsertFrame(Builder().Time(40).Id(4).Refs({2}).AsLast().Build());
buffer.InsertFrame(Builder().Time(50).Id(5).Refs({3}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(3).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(40).Id(4).Refs({2}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(50).Id(5).Refs({3}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(1)));
@ -292,12 +270,15 @@ TEST(FrameBuffer3Test, InterleavedStream) {
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(5)));
buffer.InsertFrame(Builder().Time(70).Id(7).Refs({5}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(70).Id(7).Refs({5}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(7)));
buffer.InsertFrame(Builder().Time(60).Id(6).Refs({4}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(60).Id(6).Refs({4}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), IsEmpty());
buffer.InsertFrame(Builder().Time(90).Id(9).Refs({7}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(90).Id(9).Refs({7}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(9)));
}
@ -309,10 +290,12 @@ TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(3).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(3)));
buffer.InsertFrame(Builder().Time(30).Id(2).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(2).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), IsEmpty());
}
@ -322,12 +305,15 @@ TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) {
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
field_trials);
buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(3).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(3)));
buffer.InsertFrame(Builder().Time(30).Id(2).Refs({1}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(30).Id(2).Refs({1}).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), IsEmpty());
buffer.InsertFrame(Builder().Time(40).Id(1).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(40).Id(1).AsLast().Build());
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
ElementsAre(FrameWithId(1)));
}
@ -339,18 +325,20 @@ TEST(FrameBuffer3Test, TotalNumberOfContinuousTemporalUnits) {
field_trials);
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(0));
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(1));
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).Build());
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(1));
buffer.InsertFrame(Builder().Time(40).Id(4).Refs({2}).Build());
buffer.InsertFrame(Builder().Time(40).Id(5).Refs({3, 4}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(40).Id(4).Refs({2}).Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(40).Id(5).Refs({3, 4}).AsLast().Build());
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(1));
// Reordered
buffer.InsertFrame(Builder().Time(20).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(3).Refs({2}).AsLast().Build());
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(3));
}
@ -360,11 +348,13 @@ TEST(FrameBuffer3Test, TotalNumberOfDroppedFrames) {
field_trials);
EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(0));
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).Build());
buffer.InsertFrame(Builder().Time(20).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(Builder().Time(40).Id(4).Refs({1}).Build());
buffer.InsertFrame(Builder().Time(40).Id(5).Refs({4}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(10).Id(1).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(20).Id(2).Refs({1}).Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(20).Id(3).Refs({2}).AsLast().Build());
buffer.InsertFrame(test::FakeFrameBuilder().Time(40).Id(4).Refs({1}).Build());
buffer.InsertFrame(
test::FakeFrameBuilder().Time(40).Id(5).Refs({4}).AsLast().Build());
buffer.ExtractNextDecodableTemporalUnit();
EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(0));

View File

@ -1120,3 +1120,18 @@ rtc_library("call_config_utils") {
"../rtc_base:rtc_json",
]
}
rtc_library("fake_encoded_frame") {
testonly = true
sources = [
"fake_encoded_frame.cc",
"fake_encoded_frame.h",
]
deps = [
":test_support",
"../api:rtp_packet_info",
"../api/video:encoded_frame",
"../api/video:video_rtp_headers",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}

135
test/fake_encoded_frame.cc Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2022 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 "test/fake_encoded_frame.h"
namespace webrtc::test {
void PrintTo(const EncodedFrame& frame,
std::ostream* os) /* no-presubmit-check TODO(webrtc:8982) */ {
*os << "EncodedFrame with id=" << frame.Id() << " rtp=" << frame.Timestamp()
<< " size=" << frame.size() << " refs=[";
for (size_t ref = 0; ref < frame.num_references; ++ref) {
*os << frame.references[ref] << ",";
}
*os << "]";
}
int64_t FakeEncodedFrame::ReceivedTime() const {
return received_time_;
}
int64_t FakeEncodedFrame::RenderTime() const {
return _renderTimeMs;
}
void FakeEncodedFrame::SetReceivedTime(int64_t received_time) {
received_time_ = received_time;
}
void FakeEncodedFrame::SetPayloadType(int payload_type) {
_payloadType = payload_type;
}
FakeFrameBuilder& FakeFrameBuilder::Time(uint32_t rtp_timestamp) {
rtp_timestamp_ = rtp_timestamp;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::Id(int64_t frame_id) {
frame_id_ = frame_id;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::AsLast() {
last_spatial_layer_ = true;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::Refs(
const std::vector<int64_t>& references) {
references_ = references;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::PlayoutDelay(
VideoPlayoutDelay playout_delay) {
playout_delay_ = playout_delay;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::SpatialLayer(int spatial_layer) {
spatial_layer_ = spatial_layer;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::ReceivedTime(Timestamp receive_time) {
received_time_ = receive_time;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::Size(size_t size) {
size_ = size;
return *this;
}
std::unique_ptr<FakeEncodedFrame> FakeFrameBuilder::Build() {
RTC_CHECK_LE(references_.size(), EncodedFrame::kMaxFrameReferences);
auto frame = std::make_unique<FakeEncodedFrame>();
frame->is_last_spatial_layer = last_spatial_layer_;
frame->SetEncodedData(EncodedImageBuffer::Create(size_));
if (rtp_timestamp_)
frame->SetTimestamp(*rtp_timestamp_);
if (frame_id_)
frame->SetId(*frame_id_);
if (playout_delay_)
frame->SetPlayoutDelay(*playout_delay_);
for (int64_t ref : references_) {
frame->references[frame->num_references] = ref;
frame->num_references++;
}
if (spatial_layer_)
frame->SetSpatialIndex(spatial_layer_);
if (received_time_)
frame->SetReceivedTime(received_time_->ms());
if (payload_type_)
frame->SetPayloadType(*payload_type_);
if (ntp_time_)
frame->ntp_time_ms_ = ntp_time_->ms();
if (rotation_)
frame->rotation_ = *rotation_;
if (packet_infos_)
frame->SetPacketInfos(*packet_infos_);
return frame;
}
FakeFrameBuilder& FakeFrameBuilder::PayloadType(int payload_type) {
payload_type_ = payload_type;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::NtpTime(Timestamp ntp_time) {
ntp_time_ = ntp_time;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::Rotation(VideoRotation rotation) {
rotation_ = rotation;
return *this;
}
FakeFrameBuilder& FakeFrameBuilder::PacketInfos(RtpPacketInfos packet_infos) {
packet_infos_ = packet_infos;
return *this;
}
} // namespace webrtc::test

84
test/fake_encoded_frame.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2022 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.
*/
#ifndef TEST_FAKE_ENCODED_FRAME_H_
#define TEST_FAKE_ENCODED_FRAME_H_
#include <memory>
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#include <vector>
#include "api/rtp_packet_infos.h"
#include "api/video/encoded_frame.h"
#include "api/video/video_rotation.h"
#include "test/gmock.h"
namespace webrtc::test {
// For test printing.
void PrintTo(const EncodedFrame& frame,
std::ostream* os); // no-presubmit-check TODO(webrtc:8982)
class FakeEncodedFrame : public EncodedFrame {
public:
// Always 10ms delay and on time.
int64_t ReceivedTime() const override;
int64_t RenderTime() const override;
// Setters for protected variables.
void SetReceivedTime(int64_t received_time);
void SetPayloadType(int payload_type);
private:
int64_t received_time_;
};
MATCHER_P(WithId, id, "") {
return ::testing::Matches(::testing::Eq(id))(arg.Id());
}
MATCHER_P(FrameWithSize, id, "") {
return ::testing::Matches(::testing::Eq(id))(arg.size());
}
class FakeFrameBuilder {
public:
FakeFrameBuilder& Time(uint32_t rtp_timestamp);
FakeFrameBuilder& Id(int64_t frame_id);
FakeFrameBuilder& AsLast();
FakeFrameBuilder& Refs(const std::vector<int64_t>& references);
FakeFrameBuilder& PlayoutDelay(VideoPlayoutDelay playout_delay);
FakeFrameBuilder& SpatialLayer(int spatial_layer);
FakeFrameBuilder& ReceivedTime(Timestamp receive_time);
FakeFrameBuilder& Size(size_t size);
FakeFrameBuilder& PayloadType(int payload_type);
FakeFrameBuilder& NtpTime(Timestamp ntp_time);
FakeFrameBuilder& Rotation(VideoRotation rotation);
FakeFrameBuilder& PacketInfos(RtpPacketInfos packet_infos);
std::unique_ptr<FakeEncodedFrame> Build();
private:
absl::optional<uint32_t> rtp_timestamp_;
absl::optional<int64_t> frame_id_;
absl::optional<VideoPlayoutDelay> playout_delay_;
absl::optional<int> spatial_layer_;
absl::optional<Timestamp> received_time_;
absl::optional<int> payload_type_;
absl::optional<Timestamp> ntp_time_;
absl::optional<VideoRotation> rotation_;
absl::optional<RtpPacketInfos> packet_infos_;
std::vector<int64_t> references_;
bool last_spatial_layer_ = false;
size_t size_ = 10;
};
} // namespace webrtc::test
#endif // TEST_FAKE_ENCODED_FRAME_H_

View File

@ -950,6 +950,7 @@ if (rtc_include_tests) {
"../system_wrappers:metrics",
"../test:direct_transport",
"../test:encoder_settings",
"../test:fake_encoded_frame",
"../test:fake_video_codecs",
"../test:field_trial",
"../test:fileutils",
@ -965,7 +966,6 @@ if (rtc_include_tests) {
"../test:video_test_common",
"../test/time_controller",
"adaptation:video_adaptation",
"//testing/gtest",
]
absl_deps = [
"//third_party/abseil-cpp/absl/algorithm:container",

View File

@ -28,6 +28,7 @@
#include "api/video/video_timing.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "test/fake_encoded_frame.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/run_loop.h"
@ -51,16 +52,6 @@ using ::testing::VariantWith;
namespace webrtc {
// For test printing.
void PrintTo(const EncodedFrame& frame, std::ostream* os) {
*os << "EncodedFrame with id=" << frame.Id() << " rtp=" << frame.Timestamp()
<< " size=" << frame.size() << " refs=[";
for (size_t ref = 0; ref < frame.num_references; ++ref) {
*os << frame.references[ref] << ",";
}
*os << "]";
}
namespace {
constexpr size_t kFrameSize = 10;
@ -69,28 +60,6 @@ constexpr TimeDelta kFps30Delay = 1 / Frequency::Hertz(30);
const VideoPlayoutDelay kZeroPlayoutDelay = {0, 0};
constexpr Timestamp kClockStart = Timestamp::Millis(1000);
class FakeEncodedFrame : public EncodedFrame {
public:
// Always 10ms delay and on time.
int64_t ReceivedTime() const override { return received_time_; }
int64_t RenderTime() const override { return _renderTimeMs; }
void SetReceivedTime(int64_t received_time) {
received_time_ = received_time;
}
private:
int64_t received_time_;
};
MATCHER_P(WithId, id, "") {
return Matches(Eq(id))(arg.Id());
}
MATCHER_P(FrameWithSize, id, "") {
return Matches(Eq(id))(arg.size());
}
auto TimedOut() {
return Optional(VariantWith<TimeDelta>(_));
}
@ -99,80 +68,17 @@ auto Frame(testing::Matcher<EncodedFrame> m) {
return Optional(VariantWith<std::unique_ptr<EncodedFrame>>(Pointee(m)));
}
class Builder {
public:
Builder& Time(uint32_t rtp_timestamp) {
rtp_timestamp_ = rtp_timestamp;
return *this;
std::unique_ptr<test::FakeEncodedFrame> WithReceiveTimeFromRtpTimestamp(
std::unique_ptr<test::FakeEncodedFrame> frame) {
if (frame->Timestamp() == 0) {
frame->SetReceivedTime(kClockStart.ms());
} else {
frame->SetReceivedTime(
TimeDelta::Seconds(frame->Timestamp() / 90000.0).ms() +
kClockStart.ms());
}
Builder& Id(int64_t frame_id) {
frame_id_ = frame_id;
return *this;
}
Builder& AsLast() {
last_spatial_layer_ = true;
return *this;
}
Builder& Refs(const std::vector<int64_t>& references) {
references_ = references;
return *this;
}
Builder& PlayoutDelay(VideoPlayoutDelay playout_delay) {
playout_delay_ = playout_delay;
return *this;
}
Builder& SpatialLayer(int spatial_layer) {
spatial_layer_ = spatial_layer;
return *this;
}
Builder& ReceivedTime(Timestamp receive_time) {
received_time_ = receive_time;
return *this;
}
std::unique_ptr<FakeEncodedFrame> Build() {
RTC_CHECK_LE(references_.size(), EncodedFrame::kMaxFrameReferences);
RTC_CHECK(rtp_timestamp_);
RTC_CHECK(frame_id_);
auto frame = std::make_unique<FakeEncodedFrame>();
frame->SetTimestamp(*rtp_timestamp_);
frame->SetId(*frame_id_);
frame->is_last_spatial_layer = last_spatial_layer_;
frame->SetEncodedData(EncodedImageBuffer::Create(kFrameSize));
if (playout_delay_)
frame->SetPlayoutDelay(*playout_delay_);
for (int64_t ref : references_) {
frame->references[frame->num_references] = ref;
frame->num_references++;
}
if (spatial_layer_) {
frame->SetSpatialIndex(spatial_layer_);
}
if (received_time_) {
frame->SetReceivedTime(received_time_->ms());
} else {
if (*rtp_timestamp_ == 0)
frame->SetReceivedTime(kClockStart.ms());
frame->SetReceivedTime(
TimeDelta::Seconds(*rtp_timestamp_ / 90000.0).ms() +
kClockStart.ms());
}
return frame;
}
private:
absl::optional<uint32_t> rtp_timestamp_;
absl::optional<int64_t> frame_id_;
absl::optional<VideoPlayoutDelay> playout_delay_;
absl::optional<int> spatial_layer_;
absl::optional<Timestamp> received_time_;
bool last_spatial_layer_ = false;
std::vector<int64_t> references_;
};
return frame;
}
class VCMReceiveStatisticsCallbackMock : public VCMReceiveStatisticsCallback {
public:
@ -349,19 +255,20 @@ TEST_P(FrameBufferProxyTest, KeyFramesAreScheduled) {
StartNextDecodeForceKeyframe();
time_controller_.AdvanceTime(TimeDelta::Millis(50));
auto frame = Builder().Id(0).Time(0).AsLast().Build();
auto frame = test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build();
proxy_->InsertFrame(std::move(frame));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
}
TEST_P(FrameBufferProxyTest, DeltaFrameTimeoutAfterKeyframeExtracted) {
StartNextDecodeForceKeyframe();
time_controller_.AdvanceTime(TimeDelta::Millis(50));
auto frame = Builder().Id(0).Time(0).AsLast().Build();
auto frame = test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build();
proxy_->InsertFrame(std::move(frame));
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForKeyframe), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForKeyframe),
Frame(test::WithId(0)));
StartNextDecode();
time_controller_.AdvanceTime(TimeDelta::Millis(50));
@ -376,44 +283,64 @@ TEST_P(FrameBufferProxyTest, DeltaFrameTimeoutAfterKeyframeExtracted) {
TEST_P(FrameBufferProxyTest, DependantFramesAreScheduled) {
StartNextDecodeForceKeyframe();
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
StartNextDecode();
time_controller_.AdvanceTime(kFps30Delay);
proxy_->InsertFrame(
Builder().Id(1).Time(kFps30Rtp).AsLast().Refs({0}).Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(1)));
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(1)));
}
TEST_P(FrameBufferProxyTest, SpatialLayersAreScheduled) {
StartNextDecodeForceKeyframe();
proxy_->InsertFrame(Builder().Id(0).SpatialLayer(0).Time(0).Build());
proxy_->InsertFrame(Builder().Id(1).SpatialLayer(1).Time(0).Build());
proxy_->InsertFrame(Builder().Id(2).SpatialLayer(2).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()),
Frame(AllOf(WithId(0), FrameWithSize(3 * kFrameSize))));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(0).SpatialLayer(0).Time(0).Build()));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(1).SpatialLayer(1).Time(0).Build()));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(2).SpatialLayer(2).Time(0).AsLast().Build()));
EXPECT_THAT(
WaitForFrameOrTimeout(TimeDelta::Zero()),
Frame(AllOf(test::WithId(0), test::FrameWithSize(3 * kFrameSize))));
proxy_->InsertFrame(Builder().Id(3).Time(kFps30Rtp).SpatialLayer(0).Build());
proxy_->InsertFrame(Builder().Id(4).Time(kFps30Rtp).SpatialLayer(1).Build());
proxy_->InsertFrame(
Builder().Id(5).Time(kFps30Rtp).SpatialLayer(2).AsLast().Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(3).Time(kFps30Rtp).SpatialLayer(0).Build()));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(4).Time(kFps30Rtp).SpatialLayer(1).Build()));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
.Id(5)
.Time(kFps30Rtp)
.SpatialLayer(2)
.AsLast()
.Build()));
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay * 10),
Frame(AllOf(WithId(3), FrameWithSize(3 * kFrameSize))));
EXPECT_THAT(
WaitForFrameOrTimeout(kFps30Delay * 10),
Frame(AllOf(test::WithId(3), test::FrameWithSize(3 * kFrameSize))));
}
TEST_P(FrameBufferProxyTest, OutstandingFrameTasksAreCancelledAfterDeletion) {
StartNextDecodeForceKeyframe();
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build()));
// Get keyframe. Delta frame should now be scheduled.
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
StartNextDecode();
proxy_->InsertFrame(
Builder().Id(1).Time(kFps30Rtp).AsLast().Refs({0}).Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
.Id(1)
.Time(kFps30Rtp)
.AsLast()
.Refs({0})
.Build()));
proxy_->StopOnWorker();
// Wait for 2x max wait time. Since we stopped, this should cause no timeouts
// or frame-ready callbacks.
@ -424,20 +351,24 @@ TEST_P(FrameBufferProxyTest, FramesWaitForDecoderToComplete) {
StartNextDecodeForceKeyframe();
// Start with a keyframe.
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
ResetLastResult();
// Insert a delta frame.
proxy_->InsertFrame(
Builder().Id(1).Time(kFps30Rtp).AsLast().Refs({0}).Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
// Advancing time should not result in a frame since the scheduler has not
// been signalled that we are ready.
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Eq(absl::nullopt));
// Signal ready.
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(1)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(1)));
}
TEST_P(FrameBufferProxyTest, LateFrameDropped) {
@ -445,22 +376,30 @@ TEST_P(FrameBufferProxyTest, LateFrameDropped) {
// F1
// /
// F0 --> F2
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
// Start with a keyframe.
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
StartNextDecode();
// Simulate late F1 which arrives after F2.
time_controller_.AdvanceTime(kFps30Delay * 2);
proxy_->InsertFrame(
Builder().Id(2).Time(2 * kFps30Rtp).AsLast().Refs({0}).Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(2)));
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(2)
.Time(2 * kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(2)));
StartNextDecode();
proxy_->InsertFrame(
Builder().Id(1).Time(1 * kFps30Rtp).AsLast().Refs({0}).Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(1 * kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
// Confirm frame 1 is never scheduled by timing out.
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForFrame), TimedOut());
}
@ -470,40 +409,53 @@ TEST_P(FrameBufferProxyTest, FramesFastForwardOnSystemHalt) {
// F1
// /
// F0 --> F2
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
// Start with a keyframe.
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
time_controller_.AdvanceTime(kFps30Delay);
proxy_->InsertFrame(
Builder().Id(1).Time(kFps30Rtp).AsLast().Refs({0}).Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
time_controller_.AdvanceTime(kFps30Delay);
proxy_->InsertFrame(
Builder().Id(2).Time(2 * kFps30Rtp).AsLast().Refs({0}).Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(2)
.Time(2 * kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
// Halting time should result in F1 being skipped.
time_controller_.AdvanceTime(kFps30Delay * 2);
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(2)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(2)));
EXPECT_EQ(dropped_frames(), 1);
}
TEST_P(FrameBufferProxyTest, ForceKeyFrame) {
StartNextDecodeForceKeyframe();
// Initial keyframe.
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
StartNextDecodeForceKeyframe();
// F2 is the next keyframe, and should be extracted since a keyframe was
// forced.
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(kFps30Rtp)
.AsLast()
.Refs({0})
.Build());
proxy_->InsertFrame(
Builder().Id(1).Time(kFps30Rtp).AsLast().Refs({0}).Build());
proxy_->InsertFrame(Builder().Id(2).Time(kFps30Rtp * 2).AsLast().Build());
test::FakeFrameBuilder().Id(2).Time(kFps30Rtp * 2).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay * 3), Frame(WithId(2)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay * 3), Frame(test::WithId(2)));
}
TEST_P(FrameBufferProxyTest, SlowDecoderDropsTemporalLayers) {
@ -513,40 +465,60 @@ TEST_P(FrameBufferProxyTest, SlowDecoderDropsTemporalLayers) {
// F1 --> F3 --> F5
// / / /
// F0 --> F2 --> F4
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
// Keyframe received.
// Don't start next decode until slow delay.
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
time_controller_.AdvanceTime(kFps30Delay);
proxy_->InsertFrame(
Builder().Id(1).Time(1 * kFps30Rtp).Refs({0}).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(1 * kFps30Rtp)
.Refs({0})
.AsLast()
.Build());
time_controller_.AdvanceTime(kFps30Delay);
proxy_->InsertFrame(
Builder().Id(2).Time(2 * kFps30Rtp).Refs({0}).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(2)
.Time(2 * kFps30Rtp)
.Refs({0})
.AsLast()
.Build());
// Simulate decode taking 3x FPS rate.
time_controller_.AdvanceTime(kFps30Delay * 1.5);
StartNextDecode();
// F2 is the best frame since decoding was so slow that F1 is too old.
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay * 2), Frame(WithId(2)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay * 2), Frame(test::WithId(2)));
EXPECT_EQ(dropped_frames(), 1);
time_controller_.AdvanceTime(kFps30Delay / 2);
proxy_->InsertFrame(
Builder().Id(3).Time(3 * kFps30Rtp).Refs({1, 2}).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(3)
.Time(3 * kFps30Rtp)
.Refs({1, 2})
.AsLast()
.Build());
time_controller_.AdvanceTime(kFps30Delay / 2);
proxy_->InsertFrame(
Builder().Id(4).Time(4 * kFps30Rtp).Refs({2}).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(4)
.Time(4 * kFps30Rtp)
.Refs({2})
.AsLast()
.Build());
time_controller_.AdvanceTime(kFps30Delay / 2);
// F4 is the best frame since decoding was so slow that F1 is too old.
time_controller_.AdvanceTime(kFps30Delay);
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(4)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(4)));
proxy_->InsertFrame(
Builder().Id(5).Time(5 * kFps30Rtp).Refs({3, 4}).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(5)
.Time(5 * kFps30Rtp)
.Refs({3, 4})
.AsLast()
.Build());
time_controller_.AdvanceTime(kFps30Delay / 2);
// F5 is not decodable since F4 was decoded, so a timeout is expected.
@ -563,20 +535,29 @@ TEST_P(FrameBufferProxyTest, SlowDecoderDropsTemporalLayers) {
TEST_P(FrameBufferProxyTest, NewFrameInsertedWhileWaitingToReleaseFrame) {
StartNextDecodeForceKeyframe();
// Initial keyframe.
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build()));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
time_controller_.AdvanceTime(kFps30Delay / 2);
proxy_->InsertFrame(
Builder().Id(1).Time(kFps30Rtp).Refs({0}).AsLast().Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
.Id(1)
.Time(kFps30Rtp)
.Refs({0})
.AsLast()
.Build()));
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Eq(absl::nullopt));
// Scheduler is waiting to deliver Frame 1 now. Insert Frame 2. Frame 1 should
// be delivered still.
proxy_->InsertFrame(
Builder().Id(2).Time(kFps30Rtp * 2).Refs({0}).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(1)));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
.Id(2)
.Time(kFps30Rtp * 2)
.Refs({0})
.AsLast()
.Build()));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(1)));
}
TEST_P(FrameBufferProxyTest, SameFrameNotScheduledTwice) {
@ -592,34 +573,40 @@ TEST_P(FrameBufferProxyTest, SameFrameNotScheduledTwice) {
StartNextDecodeForceKeyframe();
// First keyframe.
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Millis(15)), Frame(WithId(0)));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build()));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Millis(15)),
Frame(test::WithId(0)));
StartNextDecode();
// Warmup VCMTiming for 30fps.
for (int i = 1; i <= 30; ++i) {
proxy_->InsertFrame(Builder().Id(i).Time(i * kFps30Rtp).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(i)));
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(i).Time(i * kFps30Rtp).AsLast().Build()));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(i)));
StartNextDecode();
}
// F2 arrives and is scheduled.
proxy_->InsertFrame(Builder().Id(32).Time(32 * kFps30Rtp).AsLast().Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(32).Time(32 * kFps30Rtp).AsLast().Build()));
// F3 arrives before F2 is extracted.
time_controller_.AdvanceTime(kFps30Delay);
proxy_->InsertFrame(Builder().Id(33).Time(33 * kFps30Rtp).AsLast().Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(33).Time(33 * kFps30Rtp).AsLast().Build()));
// F1 arrives and is fast-forwarded since it is too late.
// F2 is already scheduled and should not be rescheduled.
time_controller_.AdvanceTime(kFps30Delay / 2);
proxy_->InsertFrame(Builder().Id(31).Time(31 * kFps30Rtp).AsLast().Build());
proxy_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
test::FakeFrameBuilder().Id(31).Time(31 * kFps30Rtp).AsLast().Build()));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(32)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(32)));
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(33)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(33)));
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForFrame), TimedOut());
EXPECT_EQ(dropped_frames(), 1);
@ -633,8 +620,8 @@ TEST_P(FrameBufferProxyTest, TestStatsCallback) {
// Fake timing having received decoded frame.
timing_.StopDecodeTimer(TimeDelta::Millis(1), clock_->CurrentTime());
StartNextDecodeForceKeyframe();
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
// Flush stats posted on the decode queue.
time_controller_.AdvanceTime(TimeDelta::Zero());
@ -646,8 +633,8 @@ TEST_P(FrameBufferProxyTest, FrameCompleteCalledOnceForDuplicateFrame) {
.Times(1);
StartNextDecodeForceKeyframe();
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(Builder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build());
// Flush stats posted on the decode queue.
time_controller_.AdvanceTime(TimeDelta::Zero());
}
@ -658,8 +645,8 @@ TEST_P(FrameBufferProxyTest, FrameCompleteCalledOnceForSingleTemporalUnit) {
// `OnCompleteFrame` should not be called for the first two frames since they
// do not complete the temporal layer.
EXPECT_CALL(stats_callback_, OnCompleteFrame(_, _, _)).Times(0);
proxy_->InsertFrame(Builder().Id(0).Time(0).Build());
proxy_->InsertFrame(Builder().Id(1).Time(0).Refs({0}).Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(1).Time(0).Refs({0}).Build());
time_controller_.AdvanceTime(TimeDelta::Zero());
// Flush stats posted on the decode queue.
::testing::Mock::VerifyAndClearExpectations(&stats_callback_);
@ -669,7 +656,8 @@ TEST_P(FrameBufferProxyTest, FrameCompleteCalledOnceForSingleTemporalUnit) {
EXPECT_CALL(stats_callback_,
OnCompleteFrame(false, kFrameSize, VideoContentType::UNSPECIFIED))
.Times(1);
proxy_->InsertFrame(Builder().Id(2).Time(0).Refs({0, 1}).AsLast().Build());
proxy_->InsertFrame(
test::FakeFrameBuilder().Id(2).Time(0).Refs({0, 1}).AsLast().Build());
// Flush stats posted on the decode queue.
time_controller_.AdvanceTime(TimeDelta::Zero());
}
@ -684,8 +672,9 @@ TEST_P(FrameBufferProxyTest, FrameCompleteCalledOnceForCompleteTemporalUnit) {
// do not complete the temporal layer. Frame 1 arrives later, at which time
// this frame can finally be considered complete.
EXPECT_CALL(stats_callback_, OnCompleteFrame(_, _, _)).Times(0);
proxy_->InsertFrame(Builder().Id(0).Time(0).Build());
proxy_->InsertFrame(Builder().Id(2).Time(0).Refs({0, 1}).AsLast().Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(0).Time(0).Build());
proxy_->InsertFrame(
test::FakeFrameBuilder().Id(2).Time(0).Refs({0, 1}).AsLast().Build());
time_controller_.AdvanceTime(TimeDelta::Zero());
// Flush stats posted on the decode queue.
::testing::Mock::VerifyAndClearExpectations(&stats_callback_);
@ -693,7 +682,7 @@ TEST_P(FrameBufferProxyTest, FrameCompleteCalledOnceForCompleteTemporalUnit) {
EXPECT_CALL(stats_callback_,
OnCompleteFrame(false, kFrameSize, VideoContentType::UNSPECIFIED))
.Times(1);
proxy_->InsertFrame(Builder().Id(1).Time(0).Refs({0}).Build());
proxy_->InsertFrame(test::FakeFrameBuilder().Id(1).Time(0).Refs({0}).Build());
// Flush stats posted on the decode queue.
time_controller_.AdvanceTime(TimeDelta::Zero());
}
@ -711,23 +700,23 @@ TEST_P(FrameBufferProxyTest, NextFrameWithOldTimestamp) {
// First keyframe. The receive time must be explicitly set in this test since
// the RTP derived time used in all tests does not work when the long pause
// happens later in the test.
proxy_->InsertFrame(Builder()
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(0)
.Time(kBaseRtp)
.ReceivedTime(clock_->CurrentTime())
.AsLast()
.Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(0)));
// 1 more frame to warmup VCMTiming for 30fps.
StartNextDecode();
proxy_->InsertFrame(Builder()
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(1)
.Time(kBaseRtp + kFps30Rtp)
.ReceivedTime(clock_->CurrentTime())
.AsLast()
.Build());
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(1)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(1)));
// Pause the stream for such a long time it incurs an RTP timestamp rollover
// by over half.
@ -746,7 +735,7 @@ TEST_P(FrameBufferProxyTest, NextFrameWithOldTimestamp) {
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForFrame), Eq(absl::nullopt));
time_controller_.AdvanceTime(kRolloverDelay - kMaxWaitForFrame);
StartNextDecode();
proxy_->InsertFrame(Builder()
proxy_->InsertFrame(test::FakeFrameBuilder()
.Id(2)
.Time(kRolloverRtp)
.ReceivedTime(clock_->CurrentTime())
@ -754,7 +743,7 @@ TEST_P(FrameBufferProxyTest, NextFrameWithOldTimestamp) {
.Build());
// FrameBuffer2 drops the frame, while FrameBuffer3 will continue the stream.
if (!IsFrameBuffer2Enabled(field_trials_)) {
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(WithId(2)));
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(2)));
} else {
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForFrame), TimedOut());
}
@ -776,22 +765,22 @@ TEST_P(LowLatencyFrameBufferProxyTest,
StartNextDecodeForceKeyframe();
timing_.set_min_playout_delay(TimeDelta::Zero());
timing_.set_max_playout_delay(TimeDelta::Millis(10));
auto frame = Builder().Id(0).Time(0).AsLast().Build();
auto frame = test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build();
// Playout delay of 0 implies low-latency rendering.
frame->SetPlayoutDelay({0, 10});
proxy_->InsertFrame(std::move(frame));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
// Delta frame would normally wait here, but should decode at the pacing rate
// in low-latency mode.
StartNextDecode();
frame = Builder().Id(1).Time(kFps30Rtp).AsLast().Build();
frame = test::FakeFrameBuilder().Id(1).Time(kFps30Rtp).AsLast().Build();
frame->SetPlayoutDelay({0, 10});
proxy_->InsertFrame(std::move(frame));
// Pacing is set to 16ms in the field trial so we should not decode yet.
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Eq(absl::nullopt));
time_controller_.AdvanceTime(TimeDelta::Millis(16));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(1)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(1)));
}
TEST_P(LowLatencyFrameBufferProxyTest, ZeroPlayoutDelayFullQueue) {
@ -799,15 +788,16 @@ TEST_P(LowLatencyFrameBufferProxyTest, ZeroPlayoutDelayFullQueue) {
StartNextDecodeForceKeyframe();
timing_.set_min_playout_delay(TimeDelta::Zero());
timing_.set_max_playout_delay(TimeDelta::Millis(10));
auto frame = Builder().Id(0).Time(0).AsLast().Build();
auto frame = test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build();
// Playout delay of 0 implies low-latency rendering.
frame->SetPlayoutDelay({0, 10});
proxy_->InsertFrame(std::move(frame));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
// Queue up 5 frames (configured max queue size for 0-playout delay pacing).
for (int id = 1; id <= 6; ++id) {
frame = Builder().Id(id).Time(kFps30Rtp * id).AsLast().Build();
frame =
test::FakeFrameBuilder().Id(id).Time(kFps30Rtp * id).AsLast().Build();
frame->SetPlayoutDelay({0, 10});
proxy_->InsertFrame(std::move(frame));
}
@ -815,7 +805,7 @@ TEST_P(LowLatencyFrameBufferProxyTest, ZeroPlayoutDelayFullQueue) {
// The queue is at its max size for zero playout delay pacing, so the pacing
// should be ignored and the next frame should be decoded instantly.
StartNextDecode();
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(1)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(1)));
}
TEST_P(LowLatencyFrameBufferProxyTest, MinMaxDelayZeroLowLatencyMode) {
@ -823,21 +813,21 @@ TEST_P(LowLatencyFrameBufferProxyTest, MinMaxDelayZeroLowLatencyMode) {
StartNextDecodeForceKeyframe();
timing_.set_min_playout_delay(TimeDelta::Zero());
timing_.set_max_playout_delay(TimeDelta::Zero());
auto frame = Builder().Id(0).Time(0).AsLast().Build();
auto frame = test::FakeFrameBuilder().Id(0).Time(0).AsLast().Build();
// Playout delay of 0 implies low-latency rendering.
frame->SetPlayoutDelay({0, 0});
proxy_->InsertFrame(std::move(frame));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(0)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
// Delta frame would normally wait here, but should decode at the pacing rate
// in low-latency mode.
StartNextDecode();
frame = Builder().Id(1).Time(kFps30Rtp).AsLast().Build();
frame = test::FakeFrameBuilder().Id(1).Time(kFps30Rtp).AsLast().Build();
frame->SetPlayoutDelay({0, 0});
proxy_->InsertFrame(std::move(frame));
// The min/max=0 version of low-latency rendering will result in a large
// negative decode wait time, so the frame should be ready right away.
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(WithId(1)));
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(1)));
}
INSTANTIATE_TEST_SUITE_P(

View File

@ -34,6 +34,7 @@
#include "rtc_base/event.h"
#include "system_wrappers/include/clock.h"
#include "test/fake_decoder.h"
#include "test/fake_encoded_frame.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_transport.h"
@ -59,19 +60,6 @@ using ::testing::WithoutArgs;
constexpr int kDefaultTimeOutMs = 50;
class FrameObjectFake : public EncodedFrame {
public:
void SetPayloadType(uint8_t payload_type) { _payloadType = payload_type; }
void SetRotation(const VideoRotation& rotation) { rotation_ = rotation; }
void SetNtpTime(int64_t ntp_time_ms) { ntp_time_ms_ = ntp_time_ms; }
int64_t ReceivedTime() const override { return 0; }
int64_t RenderTime() const override { return _renderTimeMs; }
};
} // namespace
class VideoReceiveStream2Test : public ::testing::Test {
@ -159,8 +147,8 @@ TEST_F(VideoReceiveStream2Test, CreateFrameFromH264FmtpSpropAndIdr) {
TEST_F(VideoReceiveStream2Test, PlayoutDelay) {
const VideoPlayoutDelay kPlayoutDelayMs = {123, 321};
std::unique_ptr<FrameObjectFake> test_frame(new FrameObjectFake());
test_frame->SetId(0);
std::unique_ptr<test::FakeEncodedFrame> test_frame =
test::FakeFrameBuilder().Id(0).AsLast().Build();
test_frame->SetPlayoutDelay(kPlayoutDelayMs);
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
@ -196,8 +184,8 @@ TEST_F(VideoReceiveStream2Test, PlayoutDelayPreservesDefaultMaxValue) {
timing_->GetTimings().max_playout_delay;
const VideoPlayoutDelay kPlayoutDelayMs = {123, -1};
std::unique_ptr<FrameObjectFake> test_frame(new FrameObjectFake());
test_frame->SetId(0);
std::unique_ptr<test::FakeEncodedFrame> test_frame =
test::FakeFrameBuilder().Id(0).AsLast().Build();
test_frame->SetPlayoutDelay(kPlayoutDelayMs);
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
@ -214,8 +202,8 @@ TEST_F(VideoReceiveStream2Test, PlayoutDelayPreservesDefaultMinValue) {
timing_->GetTimings().min_playout_delay;
const VideoPlayoutDelay kPlayoutDelayMs = {-1, 321};
std::unique_ptr<FrameObjectFake> test_frame(new FrameObjectFake());
test_frame->SetId(0);
std::unique_ptr<test::FakeEncodedFrame> test_frame =
test::FakeFrameBuilder().Id(0).AsLast().Build();
test_frame->SetPlayoutDelay(kPlayoutDelayMs);
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
@ -229,21 +217,21 @@ TEST_F(VideoReceiveStream2Test, PlayoutDelayPreservesDefaultMinValue) {
TEST_F(VideoReceiveStream2Test, MaxCompositionDelayNotSetByDefault) {
// Default with no playout delay set.
std::unique_ptr<FrameObjectFake> test_frame0(new FrameObjectFake());
test_frame0->SetId(0);
std::unique_ptr<test::FakeEncodedFrame> test_frame0 =
test::FakeFrameBuilder().Id(0).AsLast().Build();
video_receive_stream_->OnCompleteFrame(std::move(test_frame0));
EXPECT_FALSE(timing_->MaxCompositionDelayInFrames());
// Max composition delay not set for playout delay 0,0.
std::unique_ptr<FrameObjectFake> test_frame1(new FrameObjectFake());
test_frame1->SetId(1);
std::unique_ptr<test::FakeEncodedFrame> test_frame1 =
test::FakeFrameBuilder().Id(1).AsLast().Build();
test_frame1->SetPlayoutDelay({0, 0});
video_receive_stream_->OnCompleteFrame(std::move(test_frame1));
EXPECT_FALSE(timing_->MaxCompositionDelayInFrames());
// Max composition delay not set for playout delay X,Y, where X,Y>0.
std::unique_ptr<FrameObjectFake> test_frame2(new FrameObjectFake());
test_frame2->SetId(2);
std::unique_ptr<test::FakeEncodedFrame> test_frame2 =
test::FakeFrameBuilder().Id(2).AsLast().Build();
test_frame2->SetPlayoutDelay({10, 30});
video_receive_stream_->OnCompleteFrame(std::move(test_frame2));
EXPECT_FALSE(timing_->MaxCompositionDelayInFrames());
@ -253,8 +241,8 @@ TEST_F(VideoReceiveStream2Test, MaxCompositionDelaySetFromMaxPlayoutDelay) {
// Max composition delay set if playout delay X,Y, where X=0,Y>0.
const VideoPlayoutDelay kPlayoutDelayMs = {0, 50};
const int kExpectedMaxCompositionDelayInFrames = 3; // ~50 ms at 60 fps.
std::unique_ptr<FrameObjectFake> test_frame(new FrameObjectFake());
test_frame->SetId(0);
std::unique_ptr<test::FakeEncodedFrame> test_frame =
test::FakeFrameBuilder().Id(0).AsLast().Build();
test_frame->SetPlayoutDelay(kPlayoutDelayMs);
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
EXPECT_EQ(kExpectedMaxCompositionDelayInFrames,
@ -321,24 +309,29 @@ class VideoReceiveStream2TestWithFakeDecoder : public ::testing::Test {
};
TEST_F(VideoReceiveStream2TestWithFakeDecoder, PassesNtpTime) {
const int64_t kNtpTimestamp = 12345;
auto test_frame = std::make_unique<FrameObjectFake>();
test_frame->SetPayloadType(99);
test_frame->SetId(0);
test_frame->SetNtpTime(kNtpTimestamp);
const Timestamp kNtpTimestamp = Timestamp::Millis(12345);
std::unique_ptr<test::FakeEncodedFrame> test_frame =
test::FakeFrameBuilder()
.Id(0)
.PayloadType(99)
.NtpTime(kNtpTimestamp)
.AsLast()
.Build();
video_receive_stream_->Start();
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOutMs));
EXPECT_EQ(kNtpTimestamp, fake_renderer_.ntp_time_ms());
EXPECT_EQ(kNtpTimestamp.ms(), fake_renderer_.ntp_time_ms());
}
TEST_F(VideoReceiveStream2TestWithFakeDecoder, PassesRotation) {
const webrtc::VideoRotation kRotation = webrtc::kVideoRotation_180;
auto test_frame = std::make_unique<FrameObjectFake>();
test_frame->SetPayloadType(99);
test_frame->SetId(0);
test_frame->SetRotation(kRotation);
std::unique_ptr<test::FakeEncodedFrame> test_frame = test::FakeFrameBuilder()
.Id(0)
.PayloadType(99)
.Rotation(kRotation)
.AsLast()
.Build();
video_receive_stream_->Start();
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
@ -348,11 +341,13 @@ TEST_F(VideoReceiveStream2TestWithFakeDecoder, PassesRotation) {
}
TEST_F(VideoReceiveStream2TestWithFakeDecoder, PassesPacketInfos) {
auto test_frame = std::make_unique<FrameObjectFake>();
test_frame->SetPayloadType(99);
test_frame->SetId(0);
RtpPacketInfos packet_infos = CreatePacketInfos(3);
test_frame->SetPacketInfos(packet_infos);
auto test_frame = test::FakeFrameBuilder()
.Id(0)
.PayloadType(99)
.PacketInfos(packet_infos)
.AsLast()
.Build();
video_receive_stream_->Start();
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
@ -367,9 +362,8 @@ TEST_F(VideoReceiveStream2TestWithFakeDecoder, RenderedFrameUpdatesGetSources) {
constexpr uint32_t kRtpTimestamp = 12345;
// Prepare one video frame with per-packet information.
auto test_frame = std::make_unique<FrameObjectFake>();
test_frame->SetPayloadType(99);
test_frame->SetId(0);
auto test_frame =
test::FakeFrameBuilder().Id(0).PayloadType(99).AsLast().Build();
RtpPacketInfos packet_infos;
{
RtpPacketInfos::vector_type infos;
@ -439,22 +433,21 @@ TEST_F(VideoReceiveStream2TestWithFakeDecoder, RenderedFrameUpdatesGetSources) {
}
}
std::unique_ptr<FrameObjectFake> MakeFrameWithResolution(
std::unique_ptr<test::FakeEncodedFrame> MakeFrameWithResolution(
VideoFrameType frame_type,
int picture_id,
int width,
int height) {
auto frame = std::make_unique<FrameObjectFake>();
frame->SetPayloadType(99);
frame->SetId(picture_id);
auto frame =
test::FakeFrameBuilder().Id(picture_id).PayloadType(99).AsLast().Build();
frame->SetFrameType(frame_type);
frame->_encodedWidth = width;
frame->_encodedHeight = height;
return frame;
}
std::unique_ptr<FrameObjectFake> MakeFrame(VideoFrameType frame_type,
int picture_id) {
std::unique_ptr<test::FakeEncodedFrame> MakeFrame(VideoFrameType frame_type,
int picture_id) {
return MakeFrameWithResolution(frame_type, picture_id, 320, 240);
}

View File

@ -14,6 +14,7 @@
#include "api/video/i420_buffer.h"
#include "api/video_codecs/video_decoder.h"
#include "test/fake_encoded_frame.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/scoped_key_value_config.h"
@ -22,7 +23,6 @@
namespace webrtc {
namespace {
using ::testing::_;
using ::testing::ByMove;
using ::testing::NiceMock;
using ::testing::Return;
@ -127,35 +127,6 @@ class FakeVideoDecoderFactory : public VideoDecoderFactory {
NiceMock<StubVideoDecoder> av1_decoder_;
};
class FakeEncodedFrame : public EncodedFrame {
public:
int64_t ReceivedTime() const override { return 0; }
int64_t RenderTime() const override { return 0; }
// Setters for protected variables.
void SetPayloadType(int payload_type) { _payloadType = payload_type; }
};
class FrameBuilder {
public:
FrameBuilder() : frame_(std::make_unique<FakeEncodedFrame>()) {}
FrameBuilder& WithPayloadType(int payload_type) {
frame_->SetPayloadType(payload_type);
return *this;
}
FrameBuilder& WithPictureId(int picture_id) {
frame_->SetId(picture_id);
return *this;
}
std::unique_ptr<FakeEncodedFrame> Build() { return std::move(frame_); }
private:
std::unique_ptr<FakeEncodedFrame> frame_;
};
class VideoStreamDecoderImplTest : public ::testing::Test {
public:
VideoStreamDecoderImplTest()
@ -179,7 +150,8 @@ class VideoStreamDecoderImplTest : public ::testing::Test {
};
TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrame) {
video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
video_stream_decoder_.OnFrame(
test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
EXPECT_CALL(callbacks_, OnDecodedFrame);
time_controller_.AdvanceTime(TimeDelta::Millis(1));
}
@ -190,7 +162,8 @@ TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForKeyframe) {
}
TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) {
video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
video_stream_decoder_.OnFrame(
test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
EXPECT_CALL(callbacks_, OnDecodedFrame);
time_controller_.AdvanceTime(TimeDelta::Millis(1));
EXPECT_CALL(callbacks_, OnNonDecodableState);
@ -198,7 +171,8 @@ TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) {
}
TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) {
video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
video_stream_decoder_.OnFrame(
test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME));
EXPECT_CALL(callbacks_, OnDecodedFrame);
@ -207,7 +181,12 @@ TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) {
}
TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) {
video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
video_stream_decoder_.OnFrame(
test::FakeFrameBuilder()
.ReceivedTime(time_controller_.GetClock()->CurrentTime())
.PayloadType(1)
.AsLast()
.Build());
ON_CALL(decoder_factory_.Vp8Decoder(), Configure)
.WillByDefault(Return(false));
EXPECT_CALL(callbacks_, OnNonDecodableState);
@ -215,7 +194,8 @@ TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) {
}
TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) {
video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
video_stream_decoder_.OnFrame(
test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
ON_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
.WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
EXPECT_CALL(callbacks_, OnNonDecodableState);
@ -225,13 +205,13 @@ TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) {
TEST_F(VideoStreamDecoderImplTest, ChangeFramePayloadType) {
constexpr TimeDelta kFrameInterval = TimeDelta::Millis(1000 / 60);
video_stream_decoder_.OnFrame(
FrameBuilder().WithPayloadType(1).WithPictureId(0).Build());
test::FakeFrameBuilder().PayloadType(1).Id(0).AsLast().Build());
EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall);
EXPECT_CALL(callbacks_, OnDecodedFrame);
time_controller_.AdvanceTime(kFrameInterval);
video_stream_decoder_.OnFrame(
FrameBuilder().WithPayloadType(2).WithPictureId(1).Build());
test::FakeFrameBuilder().PayloadType(2).Id(1).AsLast().Build());
EXPECT_CALL(decoder_factory_.Av1Decoder(), DecodeCall);
EXPECT_CALL(callbacks_, OnDecodedFrame);
time_controller_.AdvanceTime(kFrameInterval);