blob: bdd547a9180e24f903a0445ca3e411eeefcd5f31 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/gpu/chromeos/frame_registry.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/video_frame.h"
#include "media/gpu/chromeos/video_frame_resource.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace {
// A helper to generate a VideoFrame-backed FrameResource.
scoped_refptr<FrameResource> GenerateFrame(base::TimeDelta timestamp) {
constexpr gfx::Size kCodedSize(64, 48);
constexpr gfx::Rect kVisibleRect(64, 30);
constexpr gfx::Size kNaturalSize(120, 60);
constexpr VideoPixelFormat kPixelFormat = PIXEL_FORMAT_I420;
auto video_frame = VideoFrame::CreateFrame(
kPixelFormat, kCodedSize, kVisibleRect, kNaturalSize, timestamp);
video_frame->metadata().tracking_token = base::UnguessableToken::Create();
return VideoFrameResource::Create(std::move(video_frame));
}
} // namespace
class FrameRegistryTest : public ::testing::Test {
public:
FrameRegistryTest() : registry_(base::MakeRefCounted<FrameRegistry>()) {}
FrameRegistryTest(const FrameRegistryTest&) = delete;
FrameRegistryTest& operator=(const FrameRegistryTest&) = delete;
~FrameRegistryTest() override = default;
protected:
scoped_refptr<FrameRegistry> registry_;
};
// This tests registering a frame, accessing it, unregistering it, and ensuring
// that it is cleared from the registry.
TEST_F(FrameRegistryTest, RegisterAccessUnregister) {
constexpr base::TimeDelta kTimestamp = base::Microseconds(42);
auto frame = GenerateFrame(kTimestamp);
const base::UnguessableToken token = frame->tracking_token();
ASSERT_TRUE(!!frame);
// Transfer the reference to |frame| to the registry.
registry_->RegisterFrame(std::move(frame));
// We should be able to access the frame in the registry. Accessing the frame
// creates a new reference in the returned value.
scoped_refptr<const FrameResource> retrieved_frame =
registry_->AccessFrame(token);
ASSERT_TRUE(!!retrieved_frame);
EXPECT_EQ(kTimestamp, retrieved_frame->timestamp());
// We can even retrieve it twice (which makes another reference).
scoped_refptr<const FrameResource> retrieved_frame_two =
registry_->AccessFrame(token);
ASSERT_TRUE(!!retrieved_frame_two);
EXPECT_EQ(kTimestamp, retrieved_frame_two->timestamp());
// Resets the second retrieved frame to drop the reference count.
retrieved_frame_two.reset();
// At this point in time, there should be 2 references to the original frame:
// one in |retrieved_frame| and one in |registry_|. This checks that there are
// at least two.
EXPECT_TRUE(retrieved_frame->HasAtLeastOneRef() &&
!retrieved_frame->HasOneRef());
// Resetting the registry should release one reference to the frame. Now,
// there should be exactly one reference.
registry_->UnregisterFrame(token);
EXPECT_TRUE(retrieved_frame->HasOneRef());
// After unregistering a frame with its token, that token cannot be used
// to access the frame again.
ASSERT_DEATH({ registry_->AccessFrame(token); }, "");
}
// This tests registering a frame, accessing it, and the frame's lifecycle.
TEST_F(FrameRegistryTest, CheckRegistryLifecycle) {
constexpr base::TimeDelta kTimestamp = base::Microseconds(42);
auto frame = GenerateFrame(kTimestamp);
const base::UnguessableToken token = frame->tracking_token();
ASSERT_TRUE(!!frame);
// Transfer the reference to |frame| to the registry.
registry_->RegisterFrame(std::move(frame));
// We should be able to access the frame in the registry. Accessing the frame
// creates a new reference in the returned value.
scoped_refptr<const FrameResource> retrieved_frame =
registry_->AccessFrame(token);
ASSERT_TRUE(!!retrieved_frame);
EXPECT_EQ(kTimestamp, retrieved_frame->timestamp());
// At this point in time, there should be 2 references to the original frame:
// one in |retrieved_frame| and one in |registry_|. This checks that there are
// at least two.
EXPECT_TRUE(retrieved_frame->HasAtLeastOneRef() &&
!retrieved_frame->HasOneRef());
// Resetting the registry should release one reference to the frame. Now,
// there should be exactly one reference.
registry_.reset();
EXPECT_TRUE(retrieved_frame->HasOneRef());
}
// The does a negative test of registering a frame with an unregistered token.
TEST_F(FrameRegistryTest, InvalidFrameAccess) {
const base::UnguessableToken token = base::UnguessableToken::Create();
ASSERT_DEATH({ auto frame = registry_->AccessFrame(token); }, "");
}
} // namespace media