mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

When disabled, the test ResolutionAdaptsToAvailableBandwidth fails when using frame buffer3. It is not clear if that is a problem with the test or if that behaviour is required, and thus it is safer to have this enabled by default and experiment with turning it off in the future. Change-Id: I7a6ae14c37a0cdc3e203f39f6cc0c3ad87038a60 Bug: webrtc:13343 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/247700 Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#35764}
344 lines
14 KiB
C++
344 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2021 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/frame_buffer3.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "api/video/encoded_frame.h"
|
|
#include "test/field_trial.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
using ::testing::ElementsAre;
|
|
using ::testing::Eq;
|
|
using ::testing::IsEmpty;
|
|
using ::testing::Matches;
|
|
|
|
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) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
// Ref must be less than the id of this frame.
|
|
buffer.InsertFrame(Builder().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());
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(1));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, LastContinuousUpdatesOnInsertedFrames) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt));
|
|
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
|
|
|
|
buffer.InsertFrame(Builder().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());
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(2));
|
|
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(2));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, LastContinuousFrameReordering) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
|
|
buffer.InsertFrame(Builder().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());
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(3));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, LastContinuousTemporalUnit) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
buffer.InsertFrame(Builder().Time(10).Id(1).Build());
|
|
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
|
|
buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).AsLast().Build());
|
|
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(2));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, LastContinuousTemporalUnitReordering) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
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());
|
|
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
|
|
|
|
buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).AsLast().Build());
|
|
EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(4));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, NextDecodable) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(),
|
|
Eq(absl::nullopt));
|
|
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(10U));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, AdvanceNextDecodableOnExtraction) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
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());
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(10U));
|
|
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(1)));
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(20U));
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(2)));
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(30U));
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(3)));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, AdvanceLastDecodableOnExtraction) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
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());
|
|
EXPECT_THAT(buffer.LastDecodableTemporalUnitRtpTimestamp(), Eq(10U));
|
|
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(1)));
|
|
EXPECT_THAT(buffer.LastDecodableTemporalUnitRtpTimestamp(), Eq(30U));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, FrameUpdatesNextDecodable) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build());
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(20U));
|
|
|
|
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
|
|
EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(10U));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, KeyframeClearsFullBuffer) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/5, /*max_decode_history=*/10);
|
|
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());
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(5));
|
|
|
|
// Frame buffer is full
|
|
buffer.InsertFrame(Builder().Time(60).Id(6).Refs({5}).AsLast().Build());
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(5));
|
|
|
|
buffer.InsertFrame(Builder().Time(70).Id(7).AsLast().Build());
|
|
EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(7));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, DropNextDecodableTemporalUnit) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
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.ExtractNextDecodableTemporalUnit();
|
|
buffer.DropNextDecodableTemporalUnit();
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(3)));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, OldFramesAreIgnored) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
|
|
buffer.InsertFrame(Builder().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());
|
|
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(3)));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, ReturnFullTemporalUnitKSVC) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
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());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(1), FrameWithId(2), FrameWithId(3)));
|
|
|
|
buffer.InsertFrame(Builder().Time(20).Id(4).Refs({3}).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(4)));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, InterleavedStream) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
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());
|
|
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(1)));
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(2)));
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(3)));
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(4)));
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(5)));
|
|
|
|
buffer.InsertFrame(Builder().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());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), IsEmpty());
|
|
buffer.InsertFrame(Builder().Time(90).Id(9).Refs({7}).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(9)));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) {
|
|
{
|
|
test::ScopedFieldTrials field_trial(
|
|
"WebRTC-LegacyFrameIdJumpBehavior/Disabled/");
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(3)));
|
|
buffer.InsertFrame(Builder().Time(30).Id(2).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), IsEmpty());
|
|
}
|
|
|
|
{
|
|
// WebRTC-LegacyFrameIdJumpBehavior is disabled by default.
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
|
|
buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(3)));
|
|
buffer.InsertFrame(Builder().Time(30).Id(2).Refs({1}).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), IsEmpty());
|
|
buffer.InsertFrame(Builder().Time(40).Id(1).AsLast().Build());
|
|
EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
|
|
ElementsAre(FrameWithId(1)));
|
|
}
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, TotalNumberOfContinuousTemporalUnits) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(0));
|
|
|
|
buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
|
|
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(1));
|
|
|
|
buffer.InsertFrame(Builder().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());
|
|
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(1));
|
|
|
|
// Reordered
|
|
buffer.InsertFrame(Builder().Time(20).Id(3).Refs({2}).AsLast().Build());
|
|
EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(3));
|
|
}
|
|
|
|
TEST(FrameBuffer3Test, TotalNumberOfDroppedFrames) {
|
|
FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
|
|
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.ExtractNextDecodableTemporalUnit();
|
|
EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(0));
|
|
|
|
buffer.DropNextDecodableTemporalUnit();
|
|
EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(2));
|
|
|
|
buffer.ExtractNextDecodableTemporalUnit();
|
|
EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(2));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace webrtc
|