blob: 8d6b12f7a268b42b4eb934f510e690b4bbef60ee [file] [log] [blame]
/*
* Copyright (c) 2013 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 "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "modules/desktop_capture/desktop_frame.h"
#include "modules/desktop_capture/desktop_region.h"
#include "modules/desktop_capture/mock_desktop_capturer_callback.h"
#include "rtc_base/logging.h"
#include "test/gmock.h"
#include "test/gtest.h"
#if defined(WEBRTC_WIN)
#include "modules/desktop_capture/win/screen_capturer_win_directx.h"
#endif // defined(WEBRTC_WIN)
using ::testing::_;
const int kTestSharedMemoryId = 123;
namespace webrtc {
class ScreenCapturerTest : public ::testing::Test {
public:
void SetUp() override {
capturer_ = DesktopCapturer::CreateScreenCapturer(
DesktopCaptureOptions::CreateDefault());
ASSERT_TRUE(capturer_);
}
protected:
#if defined(WEBRTC_WIN)
// Enable allow_directx_capturer in DesktopCaptureOptions, but let
// DesktopCapturer::CreateScreenCapturer decide whether a DirectX capturer
// should be used.
void MaybeCreateDirectxCapturer() {
DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
options.set_allow_directx_capturer(true);
capturer_ = DesktopCapturer::CreateScreenCapturer(options);
}
bool CreateDirectxCapturer() {
if (!ScreenCapturerWinDirectx::IsSupported()) {
RTC_LOG(LS_WARNING) << "Directx capturer is not supported";
return false;
}
MaybeCreateDirectxCapturer();
return true;
}
void CreateMagnifierCapturer() {
DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
options.set_allow_use_magnification_api(true);
capturer_ = DesktopCapturer::CreateScreenCapturer(options);
}
#endif // defined(WEBRTC_WIN)
std::unique_ptr<DesktopCapturer> capturer_;
MockDesktopCapturerCallback callback_;
};
class FakeSharedMemory : public SharedMemory {
public:
FakeSharedMemory(char* buffer, size_t size)
: SharedMemory(buffer, size, 0, kTestSharedMemoryId), buffer_(buffer) {}
~FakeSharedMemory() override { delete[] buffer_; }
FakeSharedMemory(const FakeSharedMemory&) = delete;
FakeSharedMemory& operator=(const FakeSharedMemory&) = delete;
private:
char* buffer_;
};
class FakeSharedMemoryFactory : public SharedMemoryFactory {
public:
FakeSharedMemoryFactory() {}
~FakeSharedMemoryFactory() override {}
FakeSharedMemoryFactory(const FakeSharedMemoryFactory&) = delete;
FakeSharedMemoryFactory& operator=(const FakeSharedMemoryFactory&) = delete;
std::unique_ptr<SharedMemory> CreateSharedMemory(size_t size) override {
return std::unique_ptr<SharedMemory>(
new FakeSharedMemory(new char[size], size));
}
};
ACTION_P(SaveUniquePtrArg, dest) {
*dest = std::move(*arg1);
}
// TODO(bugs.webrtc.org/12950): Re-enable when libc++ issue is fixed.
#if defined(WEBRTC_LINUX) && defined(MEMORY_SANITIZER)
#define MAYBE_GetScreenListAndSelectScreen DISABLED_GetScreenListAndSelectScreen
#else
#define MAYBE_GetScreenListAndSelectScreen GetScreenListAndSelectScreen
#endif
TEST_F(ScreenCapturerTest, MAYBE_GetScreenListAndSelectScreen) {
webrtc::DesktopCapturer::SourceList screens;
EXPECT_TRUE(capturer_->GetSourceList(&screens));
for (const auto& screen : screens) {
EXPECT_TRUE(capturer_->SelectSource(screen.id));
}
}
// Flaky on Linux. See: crbug.com/webrtc/7830
#if defined(WEBRTC_LINUX)
#define MAYBE_StartCapturer DISABLED_StartCaptuerer
#else
#define MAYBE_StartCapturer StartCapturer
#endif
TEST_F(ScreenCapturerTest, MAYBE_StartCapturer) {
capturer_->Start(&callback_);
}
#if defined(WEBRTC_LINUX)
#define MAYBE_Capture DISABLED_Capture
#else
#define MAYBE_Capture Capture
#endif
TEST_F(ScreenCapturerTest, MAYBE_Capture) {
// Assume that Start() treats the screen as invalid initially.
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
EXPECT_GT(frame->size().width(), 0);
EXPECT_GT(frame->size().height(), 0);
EXPECT_GE(frame->stride(),
frame->size().width() * DesktopFrame::kBytesPerPixel);
EXPECT_TRUE(frame->shared_memory() == NULL);
// Verify that the region contains whole screen.
EXPECT_FALSE(frame->updated_region().is_empty());
DesktopRegion::Iterator it(frame->updated_region());
ASSERT_TRUE(!it.IsAtEnd());
EXPECT_TRUE(it.rect().equals(DesktopRect::MakeSize(frame->size())));
it.Advance();
EXPECT_TRUE(it.IsAtEnd());
}
#if defined(WEBRTC_WIN)
TEST_F(ScreenCapturerTest, UseSharedBuffers) {
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->SetSharedMemoryFactory(
std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory()));
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
ASSERT_TRUE(frame->shared_memory());
EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId);
}
TEST_F(ScreenCapturerTest, GdiIsDefault) {
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
EXPECT_EQ(frame->capturer_id(), DesktopCapturerId::kScreenCapturerWinGdi);
}
TEST_F(ScreenCapturerTest, UseMagnifier) {
CreateMagnifierCapturer();
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
// Verify Magnifier API or GDI has fallback since the Magnifier API can fail
// to capture a frame on some bots.
EXPECT_TRUE(frame->capturer_id() ==
DesktopCapturerId::kScreenCapturerWinMagnifier ||
frame->capturer_id() == DesktopCapturerId::kScreenCapturerWinGdi);
}
TEST_F(ScreenCapturerTest, UseDirectxCapturer) {
if (!CreateDirectxCapturer()) {
return;
}
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
EXPECT_EQ(frame->capturer_id(), DesktopCapturerId::kScreenCapturerWinDirectx);
}
TEST_F(ScreenCapturerTest, DirectxPrecedesMagnifier) {
// Ensure that both DirecX and Magnifier API are supported.
if (!CreateDirectxCapturer()) {
return;
}
CreateMagnifierCapturer();
EXPECT_TRUE(capturer_);
// Enable both DirectX and the Magnifier API and ensure that DirectX is
// selected.
DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
options.set_allow_directx_capturer(true);
options.set_allow_use_magnification_api(true);
capturer_ = DesktopCapturer::CreateScreenCapturer(options);
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
EXPECT_EQ(frame->capturer_id(), DesktopCapturerId::kScreenCapturerWinDirectx);
}
TEST_F(ScreenCapturerTest, UseDirectxCapturerWithSharedBuffers) {
if (!CreateDirectxCapturer()) {
return;
}
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer_->Start(&callback_);
capturer_->SetSharedMemoryFactory(
std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory()));
capturer_->CaptureFrame();
ASSERT_TRUE(frame);
ASSERT_TRUE(frame->shared_memory());
EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId);
EXPECT_EQ(frame->capturer_id(), DesktopCapturerId::kScreenCapturerWinDirectx);
}
#endif // defined(WEBRTC_WIN)
} // namespace webrtc