blob: 6e0f79007977b8195f3f436d4b7a2ec1464dea06 [file]
/*
* Copyright (c) 2026 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 <memory>
#include <utility>
#include "modules/desktop_capture/desktop_frame.h"
#include "modules/desktop_capture/desktop_geometry.h"
#include "modules/desktop_capture/frame_texture.h"
#include "modules/desktop_capture/shared_desktop_frame.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
// Returns a non-null, non-invalid sentinel FrameTexture::Handle for testing.
// On Windows Handle is void*, on other platforms it is int.
FrameTexture::Handle MakeHandle() {
constexpr uintptr_t kValue = 0x1234;
#if defined(WEBRTC_WIN)
return reinterpret_cast<FrameTexture::Handle>(kValue);
#else
return static_cast<FrameTexture::Handle>(kValue);
#endif
}
// A concrete FrameTexture subclass for testing purposes. Unlike the
// platform-specific DXGIFrameTexture, this doesn't own any real GPU resources.
class FakeFrameTexture : public FrameTexture {
public:
explicit FakeFrameTexture(Handle handle) : FrameTexture(handle) {}
~FakeFrameTexture() override = default;
};
// A texture-backed DesktopFrame with nullptr data, mimicking DXGIDesktopFrame.
class TextureDesktopFrame : public DesktopFrame {
public:
TextureDesktopFrame(DesktopSize size,
std::unique_ptr<FakeFrameTexture> texture)
: DesktopFrame(size,
/*stride=*/0,
FOURCC_ARGB,
/*data=*/nullptr,
/*shared_memory=*/nullptr,
texture.get()),
owned_texture_(std::move(texture)) {}
~TextureDesktopFrame() override = default;
private:
std::unique_ptr<FakeFrameTexture> owned_texture_;
};
} // namespace
TEST(FrameTextureTest, StoresHandle) {
const FrameTexture::Handle handle = MakeHandle();
FakeFrameTexture texture(handle);
EXPECT_EQ(texture.handle(), handle);
}
TEST(DesktopFrameTest, DefaultTextureIsNull) {
auto frame = std::make_unique<BasicDesktopFrame>(DesktopSize(10, 10));
EXPECT_EQ(frame->texture(), nullptr);
}
TEST(DesktopFrameTest, TextureFrameHasValidTexture) {
const FrameTexture::Handle handle = MakeHandle();
auto texture = std::make_unique<FakeFrameTexture>(handle);
FrameTexture* raw_texture = texture.get();
auto frame = std::make_unique<TextureDesktopFrame>(DesktopSize(10, 10),
std::move(texture));
EXPECT_EQ(frame->data(), nullptr);
EXPECT_NE(frame->texture(), nullptr);
EXPECT_EQ(frame->texture(), raw_texture);
EXPECT_EQ(frame->texture()->handle(), handle);
}
TEST(DesktopFrameTest, TextureFrameHasNullData) {
// Verify that a texture-backed frame with nullptr data() still works for
// metadata access (size, texture handle, etc.).
const FrameTexture::Handle handle = MakeHandle();
auto texture = std::make_unique<FakeFrameTexture>(handle);
auto frame = std::make_unique<TextureDesktopFrame>(DesktopSize(10, 10),
std::move(texture));
EXPECT_EQ(frame->data(), nullptr);
EXPECT_NE(frame->texture(), nullptr);
EXPECT_EQ(frame->texture()->handle(), handle);
EXPECT_EQ(frame->size().width(), 10);
EXPECT_EQ(frame->size().height(), 10);
// Metadata operations should work on texture-only frames.
frame->set_dpi(DesktopVector(96, 96));
EXPECT_EQ(frame->dpi().x(), 96);
frame->set_capture_time_ms(123);
EXPECT_EQ(frame->capture_time_ms(), 123);
frame->mutable_updated_region()->SetRect(DesktopRect::MakeWH(10, 10));
EXPECT_FALSE(frame->updated_region().is_empty());
}
TEST(SharedDesktopFrameTest, TexturePropagatedToSharedFrame) {
const FrameTexture::Handle handle = MakeHandle();
auto texture = std::make_unique<FakeFrameTexture>(handle);
FrameTexture* raw_texture = texture.get();
auto frame = std::make_unique<TextureDesktopFrame>(DesktopSize(10, 10),
std::move(texture));
auto shared_frame = SharedDesktopFrame::Wrap(std::move(frame));
ASSERT_NE(shared_frame, nullptr);
EXPECT_EQ(shared_frame->texture(), raw_texture);
EXPECT_EQ(shared_frame->texture()->handle(), handle);
}
TEST(SharedDesktopFrameTest, TexturePropagatedToClone) {
const FrameTexture::Handle handle = MakeHandle();
auto texture = std::make_unique<FakeFrameTexture>(handle);
FrameTexture* raw_texture = texture.get();
auto frame = std::make_unique<TextureDesktopFrame>(DesktopSize(10, 10),
std::move(texture));
auto shared_frame = SharedDesktopFrame::Wrap(std::move(frame));
auto clone = shared_frame->Share();
ASSERT_NE(clone, nullptr);
EXPECT_EQ(clone->texture(), raw_texture);
EXPECT_EQ(clone->texture()->handle(), handle);
EXPECT_TRUE(shared_frame->ShareFrameWith(*clone));
}
TEST(SharedDesktopFrameTest, NullTextureForNormalFrame) {
auto frame = std::make_unique<BasicDesktopFrame>(DesktopSize(10, 10));
auto shared_frame = SharedDesktopFrame::Wrap(std::move(frame));
ASSERT_NE(shared_frame, nullptr);
EXPECT_EQ(shared_frame->texture(), nullptr);
}
} // namespace webrtc