* Copyright (c) 2016 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/desktop_capture/desktop_capturer_differ_wrapper.h"
#include <initializer_list>
#include <memory>
#include <utility>
#include <vector>
#include "modules/desktop_capture/desktop_geometry.h"
#include "modules/desktop_capture/desktop_region.h"
#include "modules/desktop_capture/differ_block.h"
#include "modules/desktop_capture/fake_desktop_capturer.h"
#include "modules/desktop_capture/mock_desktop_capturer_callback.h"
#include "rtc_base/random.h"
#include "rtc_base/time_utils.h"
#include "system_wrappers/include/cpu_features_wrapper.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
template <template <typename, typename...> class T = std::initializer_list,
typename... Rect>
void AssertUpdatedRegionIs(const DesktopFrame& frame,
const T<DesktopRect, Rect...>& rects) {
DesktopRegion region;
for (const auto& rect : rects) {
region.AddRect(rect);
}
ASSERT_TRUE(frame.updated_region().Equals(region));
}
template <template <typename, typename...> class T = std::initializer_list,
typename... Rect>
void AssertUpdatedRegionCovers(const DesktopFrame& frame,
const T<DesktopRect, Rect...>& rects) {
DesktopRegion region;
for (const auto& rect : rects) {
region.AddRect(rect);
}
DesktopRegion intersect(region);
intersect.IntersectWith(frame.updated_region());
ASSERT_TRUE(region.Equals(intersect));
DesktopRegion differ(frame.updated_region());
differ.Subtract(region);
for (DesktopRegion::Iterator it(differ); !it.IsAtEnd(); it.Advance()) {
ASSERT_TRUE(it.rect().width() <= kBlockSize * 2 - 2 ||
it.rect().height() <= kBlockSize * 2 - 2);
}
}
template <template <typename, typename...> class T = std::initializer_list,
typename... Rect>
void ExecuteDifferWrapperCase(BlackWhiteDesktopFramePainter* frame_painter,
DesktopCapturerDifferWrapper* capturer,
MockDesktopCapturerCallback* callback,
const T<DesktopRect, Rect...>& updated_region,
bool check_result,
bool exactly_match) {
EXPECT_CALL(*callback, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS,
::testing::_))
.Times(1)
.WillOnce(
::testing::Invoke([&updated_region, check_result, exactly_match](
DesktopCapturer::Result result,
std::unique_ptr<DesktopFrame>* frame) {
ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS);
if (check_result) {
if (exactly_match) {
AssertUpdatedRegionIs(**frame, updated_region);
} else {
AssertUpdatedRegionCovers(**frame, updated_region);
}
}
}));
for (const auto& rect : updated_region) {
frame_painter->updated_region()->AddRect(rect);
}
capturer->CaptureFrame();
}
void ExecuteCapturer(DesktopCapturerDifferWrapper* capturer,
MockDesktopCapturerCallback* callback) {
EXPECT_CALL(*callback, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS,
::testing::_))
.Times(1);
capturer->CaptureFrame();
}
void ExecuteDifferWrapperTest(bool with_hints,
bool enlarge_updated_region,
bool random_updated_region,
bool check_result) {
const bool updated_region_should_exactly_match =
with_hints && !enlarge_updated_region && !random_updated_region;
BlackWhiteDesktopFramePainter frame_painter;
PainterDesktopFrameGenerator frame_generator;
frame_generator.set_desktop_frame_painter(&frame_painter);
std::unique_ptr<FakeDesktopCapturer> fake(new FakeDesktopCapturer());
fake->set_frame_generator(&frame_generator);
DesktopCapturerDifferWrapper capturer(std::move(fake));
MockDesktopCapturerCallback callback;
frame_generator.set_provide_updated_region_hints(with_hints);
frame_generator.set_enlarge_updated_region(enlarge_updated_region);
frame_generator.set_add_random_updated_region(random_updated_region);
capturer.Start(&callback);
EXPECT_CALL(callback, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS,
::testing::_))
.Times(1)
.WillOnce(::testing::Invoke([](DesktopCapturer::Result result,
std::unique_ptr<DesktopFrame>* frame) {
ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS);
AssertUpdatedRegionIs(**frame,
{DesktopRect::MakeSize((*frame)->size())});
}));
capturer.CaptureFrame();
ExecuteDifferWrapperCase(&frame_painter, &capturer, &callback,
{DesktopRect::MakeLTRB(100, 100, 200, 200),
DesktopRect::MakeLTRB(300, 300, 400, 400)},
check_result, updated_region_should_exactly_match);
ExecuteCapturer(&capturer, &callback);
ExecuteDifferWrapperCase(
&frame_painter, &capturer, &callback,
{DesktopRect::MakeLTRB(0, 0, 40, 40),
DesktopRect::MakeLTRB(0, frame_generator.size()->height() - 40, 40,
frame_generator.size()->height()),
DesktopRect::MakeLTRB(frame_generator.size()->width() - 40, 0,
frame_generator.size()->width(), 40),
DesktopRect::MakeLTRB(frame_generator.size()->width() - 40,
frame_generator.size()->height() - 40,
frame_generator.size()->width(),
frame_generator.size()->height())},
check_result, updated_region_should_exactly_match);
Random random(rtc::TimeMillis());
for (int i = 0; i < 1000; i++) {
if (enlarge_updated_region) {
frame_generator.set_enlarge_range(random.Rand(1, 50));
}
frame_generator.size()->set(random.Rand(500, 2000), random.Rand(500, 2000));
ExecuteCapturer(&capturer, &callback);
std::vector<DesktopRect> updated_region;
for (int j = random.Rand(50); j >= 0; j--) {
const int left = random.Rand(0, frame_generator.size()->width() - 2);
const int top = random.Rand(0, frame_generator.size()->height() - 2);
const int right = random.Rand(left + 1, frame_generator.size()->width());
const int bottom = random.Rand(top + 1, frame_generator.size()->height());
updated_region.push_back(DesktopRect::MakeLTRB(left, top, right, bottom));
}
ExecuteDifferWrapperCase(&frame_painter, &capturer, &callback,
updated_region, check_result,
updated_region_should_exactly_match);
}
}
}
TEST(DesktopCapturerDifferWrapperTest, CaptureWithoutHints) {
ExecuteDifferWrapperTest(false, false, false, true);
}
TEST(DesktopCapturerDifferWrapperTest, CaptureWithHints) {
ExecuteDifferWrapperTest(true, false, false, true);
}
TEST(DesktopCapturerDifferWrapperTest, CaptureWithEnlargedHints) {
ExecuteDifferWrapperTest(true, true, false, true);
}
TEST(DesktopCapturerDifferWrapperTest, CaptureWithRandomHints) {
ExecuteDifferWrapperTest(true, false, true, true);
}
TEST(DesktopCapturerDifferWrapperTest, CaptureWithEnlargedAndRandomHints) {
ExecuteDifferWrapperTest(true, true, true, true);
}
TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithoutHintsPerf) {
int64_t started = rtc::TimeMillis();
ExecuteDifferWrapperTest(false, false, false, false);
ASSERT_LE(rtc::TimeMillis() - started, 15000);
}
TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithHintsPerf) {
int64_t started = rtc::TimeMillis();
ExecuteDifferWrapperTest(true, false, false, false);
ASSERT_LE(rtc::TimeMillis() - started, 15000);
}
TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithEnlargedHintsPerf) {
int64_t started = rtc::TimeMillis();
ExecuteDifferWrapperTest(true, true, false, false);
ASSERT_LE(rtc::TimeMillis() - started, 15000);
}
TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithRandomHintsPerf) {
int64_t started = rtc::TimeMillis();
ExecuteDifferWrapperTest(true, false, true, false);
ASSERT_LE(rtc::TimeMillis() - started, 15000);
}
TEST(DesktopCapturerDifferWrapperTest,
DISABLED_CaptureWithEnlargedAndRandomHintsPerf) {
int64_t started = rtc::TimeMillis();
ExecuteDifferWrapperTest(true, true, true, false);
ASSERT_LE(rtc::TimeMillis() - started, 15000);
}
}