mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-17 15:47:53 +01:00

In https://webrtc-review.googlesource.com/c/src/+/1560 we moved WebRTC from src/webrtc to src/ (in order to preserve an healthy git history). This CL takes care of fixing header guards, #include paths, etc... NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iea91618212bee0af16aa3f05071eab8f93706578 Reviewed-on: https://webrtc-review.googlesource.com/1561 Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19846}
381 lines
14 KiB
C++
381 lines
14 KiB
C++
/*
|
|
* 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 <string.h>
|
|
|
|
#include <algorithm>
|
|
#include <initializer_list>
|
|
#include <iostream> // TODO(zijiehe): Remove once flaky has been resolved.
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
// TODO(zijiehe): Remove once flaky has been resolved.
|
|
#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 "modules/desktop_capture/rgba_color.h"
|
|
#include "modules/desktop_capture/screen_drawer.h"
|
|
#include "rtc_base/base64.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/constructormagic.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"
|
|
#include "rtc_base/win32.h"
|
|
#endif // defined(WEBRTC_WIN)
|
|
|
|
using ::testing::_;
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
ACTION_P2(SaveCaptureResult, result, dest) {
|
|
*result = arg0;
|
|
*dest = std::move(*arg1);
|
|
}
|
|
|
|
// Returns true if color in |rect| of |frame| is |color|.
|
|
bool ArePixelsColoredBy(const DesktopFrame& frame,
|
|
DesktopRect rect,
|
|
RgbaColor color,
|
|
bool may_partially_draw) {
|
|
if (!may_partially_draw) {
|
|
// updated_region() should cover the painted area.
|
|
DesktopRegion updated_region(frame.updated_region());
|
|
updated_region.IntersectWith(rect);
|
|
if (!updated_region.Equals(DesktopRegion(rect))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Color in the |rect| should be |color|.
|
|
uint8_t* row = frame.GetFrameDataAtPos(rect.top_left());
|
|
for (int i = 0; i < rect.height(); i++) {
|
|
uint8_t* column = row;
|
|
for (int j = 0; j < rect.width(); j++) {
|
|
if (color != RgbaColor(column)) {
|
|
return false;
|
|
}
|
|
column += DesktopFrame::kBytesPerPixel;
|
|
}
|
|
row += frame.stride();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class ScreenCapturerIntegrationTest : public testing::Test {
|
|
public:
|
|
void SetUp() override {
|
|
capturer_ = DesktopCapturer::CreateScreenCapturer(
|
|
DesktopCaptureOptions::CreateDefault());
|
|
}
|
|
|
|
protected:
|
|
void TestCaptureUpdatedRegion(
|
|
std::initializer_list<DesktopCapturer*> capturers) {
|
|
RTC_DCHECK(capturers.size() > 0);
|
|
// A large enough area for the tests, which should be able to be fulfilled
|
|
// by most systems.
|
|
#if defined(WEBRTC_WIN)
|
|
// On Windows, an interesting warning window may pop up randomly. The root
|
|
// cause is still under investigation, so reduce the test area to work
|
|
// around. Bug https://bugs.chromium.org/p/webrtc/issues/detail?id=6666.
|
|
const int kTestArea = 416;
|
|
#else
|
|
const int kTestArea = 512;
|
|
#endif
|
|
const int kRectSize = 32;
|
|
std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create();
|
|
if (!drawer || drawer->DrawableRegion().is_empty()) {
|
|
LOG(LS_WARNING) << "No ScreenDrawer implementation for current platform.";
|
|
return;
|
|
}
|
|
if (drawer->DrawableRegion().width() < kTestArea ||
|
|
drawer->DrawableRegion().height() < kTestArea) {
|
|
LOG(LS_WARNING) << "ScreenDrawer::DrawableRegion() is too small for the "
|
|
"CaptureUpdatedRegion tests.";
|
|
return;
|
|
}
|
|
|
|
for (DesktopCapturer* capturer : capturers) {
|
|
capturer->Start(&callback_);
|
|
}
|
|
|
|
// Draw a set of |kRectSize| by |kRectSize| rectangles at (|i|, |i|), or
|
|
// |i| by |i| rectangles at (|kRectSize|, |kRectSize|). One of (controlled
|
|
// by |c|) its primary colors is |i|, and the other two are 0x7f. So we
|
|
// won't draw a black or white rectangle.
|
|
for (int c = 0; c < 3; c++) {
|
|
// A fixed size rectangle.
|
|
for (int i = 0; i < kTestArea - kRectSize; i += 16) {
|
|
DesktopRect rect = DesktopRect::MakeXYWH(i, i, kRectSize, kRectSize);
|
|
rect.Translate(drawer->DrawableRegion().top_left());
|
|
RgbaColor color((c == 0 ? (i & 0xff) : 0x7f),
|
|
(c == 1 ? (i & 0xff) : 0x7f),
|
|
(c == 2 ? (i & 0xff) : 0x7f));
|
|
// Fail fast.
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
TestCaptureOneFrame(capturers, drawer.get(), rect, color));
|
|
}
|
|
|
|
// A variable-size rectangle.
|
|
for (int i = 0; i < kTestArea - kRectSize; i += 16) {
|
|
DesktopRect rect = DesktopRect::MakeXYWH(kRectSize, kRectSize, i, i);
|
|
rect.Translate(drawer->DrawableRegion().top_left());
|
|
RgbaColor color((c == 0 ? (i & 0xff) : 0x7f),
|
|
(c == 1 ? (i & 0xff) : 0x7f),
|
|
(c == 2 ? (i & 0xff) : 0x7f));
|
|
// Fail fast.
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
TestCaptureOneFrame(capturers, drawer.get(), rect, color));
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestCaptureUpdatedRegion() {
|
|
TestCaptureUpdatedRegion({capturer_.get()});
|
|
}
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
// Enable allow_directx_capturer in DesktopCaptureOptions, but let
|
|
// DesktopCapturer::CreateScreenCapturer() to 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()) {
|
|
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_;
|
|
|
|
private:
|
|
// Repeats capturing the frame by using |capturers| one-by-one for 600 times,
|
|
// typically 30 seconds, until they succeeded captured a |color| rectangle at
|
|
// |rect|. This function uses |drawer|->WaitForPendingDraws() between two
|
|
// attempts to wait for the screen to update.
|
|
void TestCaptureOneFrame(std::vector<DesktopCapturer*> capturers,
|
|
ScreenDrawer* drawer,
|
|
DesktopRect rect,
|
|
RgbaColor color) {
|
|
const int wait_capture_round = 600;
|
|
drawer->Clear();
|
|
size_t succeeded_capturers = 0;
|
|
for (int i = 0; i < wait_capture_round; i++) {
|
|
drawer->DrawRectangle(rect, color);
|
|
drawer->WaitForPendingDraws();
|
|
for (size_t j = 0; j < capturers.size(); j++) {
|
|
if (capturers[j] == nullptr) {
|
|
// DesktopCapturer should return an empty updated_region() if no
|
|
// update detected. So we won't test it again if it has captured the
|
|
// rectangle we drew.
|
|
continue;
|
|
}
|
|
std::unique_ptr<DesktopFrame> frame = CaptureFrame(capturers[j]);
|
|
if (!frame) {
|
|
// CaptureFrame() has triggered an assertion failure already, we only
|
|
// need to return here.
|
|
return;
|
|
}
|
|
|
|
if (ArePixelsColoredBy(
|
|
*frame, rect, color, drawer->MayDrawIncompleteShapes())) {
|
|
capturers[j] = nullptr;
|
|
succeeded_capturers++;
|
|
}
|
|
// The following else if statement is for debugging purpose only, which
|
|
// should be removed after flaky of ScreenCapturerIntegrationTest has
|
|
// been resolved.
|
|
else if (i == wait_capture_round - 1) {
|
|
std::string result;
|
|
rtc::Base64::EncodeFromArray(frame->data(),
|
|
frame->size().height() * frame->stride(),
|
|
&result);
|
|
std::cout << frame->size().width() << " x " << frame->size().height()
|
|
<< std::endl;
|
|
// Split the entire string (can be over 4M) into several lines to
|
|
// avoid browser from sticking.
|
|
static const size_t kLineLength = 32768;
|
|
const char* result_end = result.c_str() + result.length();
|
|
for (const char* it = result.c_str();
|
|
it < result_end;
|
|
it += kLineLength) {
|
|
const size_t max_length = result_end - it;
|
|
std::cout << std::string(it, std::min(kLineLength, max_length))
|
|
<< std::endl;
|
|
}
|
|
std::cout << "Failed to capture rectangle " << rect.left() << " x "
|
|
<< rect.top() << " - " << rect.right() << " x "
|
|
<< rect.bottom() << " with color ("
|
|
<< static_cast<int>(color.red) << ", "
|
|
<< static_cast<int>(color.green) << ", "
|
|
<< static_cast<int>(color.blue) << ", "
|
|
<< static_cast<int>(color.alpha) << ")" << std::endl;
|
|
ASSERT_TRUE(false) << "ScreenCapturerIntegrationTest may be flaky. "
|
|
"Please kindly FYI the broken link to "
|
|
"zijiehe@chromium.org for investigation. If "
|
|
"the failure continually happens, but I have "
|
|
"not responded as quick as expected, disable "
|
|
"*all* tests in "
|
|
"screen_capturer_integration_test.cc to "
|
|
"unblock other developers.";
|
|
}
|
|
}
|
|
|
|
if (succeeded_capturers == capturers.size()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT_EQ(succeeded_capturers, capturers.size());
|
|
}
|
|
|
|
// Expects |capturer| to successfully capture a frame, and returns it.
|
|
std::unique_ptr<DesktopFrame> CaptureFrame(DesktopCapturer* capturer) {
|
|
for (int i = 0; i < 10; i++) {
|
|
std::unique_ptr<DesktopFrame> frame;
|
|
DesktopCapturer::Result result;
|
|
EXPECT_CALL(callback_, OnCaptureResultPtr(_, _))
|
|
.WillOnce(SaveCaptureResult(&result, &frame));
|
|
capturer->CaptureFrame();
|
|
testing::Mock::VerifyAndClearExpectations(&callback_);
|
|
if (result == DesktopCapturer::Result::SUCCESS) {
|
|
EXPECT_TRUE(frame);
|
|
return frame;
|
|
} else {
|
|
EXPECT_FALSE(frame);
|
|
}
|
|
}
|
|
|
|
EXPECT_TRUE(false);
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
// ScreenCapturerWinGdi randomly returns blank screen, the root cause is still
|
|
// unknown. Bug, https://bugs.chromium.org/p/webrtc/issues/detail?id=6843.
|
|
#define MAYBE_CaptureUpdatedRegion DISABLED_CaptureUpdatedRegion
|
|
#else
|
|
#define MAYBE_CaptureUpdatedRegion CaptureUpdatedRegion
|
|
#endif
|
|
TEST_F(ScreenCapturerIntegrationTest, MAYBE_CaptureUpdatedRegion) {
|
|
TestCaptureUpdatedRegion();
|
|
}
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
// ScreenCapturerWinGdi randomly returns blank screen, the root cause is still
|
|
// unknown. Bug, https://bugs.chromium.org/p/webrtc/issues/detail?id=6843.
|
|
#define MAYBE_TwoCapturers DISABLED_TwoCapturers
|
|
#else
|
|
#define MAYBE_TwoCapturers TwoCapturers
|
|
#endif
|
|
TEST_F(ScreenCapturerIntegrationTest, MAYBE_TwoCapturers) {
|
|
std::unique_ptr<DesktopCapturer> capturer2 = std::move(capturer_);
|
|
SetUp();
|
|
TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()});
|
|
}
|
|
|
|
#if defined(WEBRTC_WIN)
|
|
|
|
// Windows cannot capture contents on VMs hosted in GCE. See bug
|
|
// https://bugs.chromium.org/p/webrtc/issues/detail?id=8153.
|
|
TEST_F(ScreenCapturerIntegrationTest,
|
|
DISABLED_CaptureUpdatedRegionWithDirectxCapturer) {
|
|
if (!CreateDirectxCapturer()) {
|
|
return;
|
|
}
|
|
|
|
TestCaptureUpdatedRegion();
|
|
}
|
|
|
|
TEST_F(ScreenCapturerIntegrationTest, DISABLED_TwoDirectxCapturers) {
|
|
if (!CreateDirectxCapturer()) {
|
|
return;
|
|
}
|
|
|
|
std::unique_ptr<DesktopCapturer> capturer2 = std::move(capturer_);
|
|
RTC_CHECK(CreateDirectxCapturer());
|
|
TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()});
|
|
}
|
|
|
|
TEST_F(ScreenCapturerIntegrationTest,
|
|
DISABLED_CaptureUpdatedRegionWithMagnifierCapturer) {
|
|
// On Windows 8 or later, magnifier APIs return a frame with a border on test
|
|
// environment, so disable these tests.
|
|
// Bug https://bugs.chromium.org/p/webrtc/issues/detail?id=6844
|
|
// TODO(zijiehe): Find the root cause of the border and failure, which cannot
|
|
// reproduce on my dev machine.
|
|
if (rtc::IsWindows8OrLater()) {
|
|
return;
|
|
}
|
|
CreateMagnifierCapturer();
|
|
TestCaptureUpdatedRegion();
|
|
}
|
|
|
|
TEST_F(ScreenCapturerIntegrationTest, DISABLED_TwoMagnifierCapturers) {
|
|
// On Windows 8 or later, magnifier APIs return a frame with a border on test
|
|
// environment, so disable these tests.
|
|
// Bug https://bugs.chromium.org/p/webrtc/issues/detail?id=6844
|
|
// TODO(zijiehe): Find the root cause of the border and failure, which cannot
|
|
// reproduce on my dev machine.
|
|
if (rtc::IsWindows8OrLater()) {
|
|
return;
|
|
}
|
|
CreateMagnifierCapturer();
|
|
std::unique_ptr<DesktopCapturer> capturer2 = std::move(capturer_);
|
|
CreateMagnifierCapturer();
|
|
TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()});
|
|
}
|
|
|
|
TEST_F(ScreenCapturerIntegrationTest,
|
|
DISABLED_MaybeCaptureUpdatedRegionWithDirectxCapturer) {
|
|
if (!rtc::IsWindows8OrLater()) {
|
|
// ScreenCapturerWinGdi randomly returns blank screen, the root cause is
|
|
// still unknown. Bug,
|
|
// https://bugs.chromium.org/p/webrtc/issues/detail?id=6843.
|
|
// On Windows 7 or early version, MaybeCreateDirectxCapturer() always
|
|
// creates GDI capturer.
|
|
return;
|
|
}
|
|
// Even DirectX capturer is not supported in current system, we should be able
|
|
// to select a usable capturer.
|
|
MaybeCreateDirectxCapturer();
|
|
TestCaptureUpdatedRegion();
|
|
}
|
|
|
|
#endif // defined(WEBRTC_WIN)
|
|
|
|
} // namespace webrtc
|