Reland of [WebRTC] A real ScreenCapturer test (patchset #1 id:1 of https://codereview.webrtc.org/2310953002/ )

Reason for revert:
Resubmit capturer tests

Original issue's description:
> Revert of [WebRTC] A real ScreenCapturer test (patchset #8 id:240001 of https://codereview.webrtc.org/2268093002/ )
>
> Reason for revert:
> ScreenCapturerTest.CaptureUpdatedRegion fails on Win DrMemory Full.
>
> Original issue's description:
> > [WebRTC] A real ScreenCapturer test
> >
> > We do not have a real ScreenCapturer test before. And after CL 2210443002, a new
> > ScreenDrawer interface is added to the code base to draw various shapes on the
> > screen. This change is to use ScreenDrawer to test ScreenCapturer. Besides test
> > cases, some other changes are included,
> >
> > 1. A WaitForPendingPaintings() function in ScreenDrawer, to wait for a
> > ScreenDrawer to finish all the pending draws. This function now only sleeps 50
> > milliseconds on X11 and 100 milliseconds on Windows.
> >
> > 2. A Color structure to help handle a big-endian or little-endian safe color and
> > provide functions to compare with DesktopFrame::data(). Both ScreenDrawer and
> > DesktopFrameGenerator (in change 2202443002) can use this class to create colors
> > and compare with or paint to a DesktopFrame.
> >
> > 3. ScreenDrawer now uses Color structure instead of uint32_t.
> >
> > BUG=314516
> >
> > TBR=kjellander@chromium.org
> >
> > Committed: https://crrev.com/9d1c54ace0dc9f68da0152aa1ded2a8dba0a43ae
> > Cr-Commit-Position: refs/heads/master@{#14058}
>
> TBR=sergeyu@chromium.org,jamiewalch@chromium.org,kjellander@chromium.org,zijiehe@chromium.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=314516
>
> Committed: https://crrev.com/4c44202dc348613695a4b529bbd7c9bdab6195ec
> Cr-Commit-Position: refs/heads/master@{#14071}

TBR=sergeyu@chromium.org,jamiewalch@chromium.org,kjellander@chromium.org,asapersson@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=644130

Review-Url: https://codereview.webrtc.org/2313653003
Cr-Commit-Position: refs/heads/master@{#14113}
This commit is contained in:
zijiehe 2016-09-07 11:52:25 -07:00 committed by Commit bot
parent f581eb76f4
commit 0f49daccbe
9 changed files with 411 additions and 66 deletions

View File

@ -510,6 +510,8 @@ if (rtc_include_tests) {
"desktop_capture/fake_screen_capturer.cc",
"desktop_capture/fake_screen_capturer.h",
"desktop_capture/mouse_cursor_monitor_unittest.cc",
"desktop_capture/rgba_color.cc",
"desktop_capture/rgba_color.h",
"desktop_capture/screen_capturer_differ_wrapper_unittest.cc",
"desktop_capture/screen_capturer_helper_unittest.cc",
"desktop_capture/screen_capturer_mac_unittest.cc",

View File

@ -0,0 +1,48 @@
/*
* 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 "webrtc/modules/desktop_capture/rgba_color.h"
namespace webrtc {
namespace {
bool AlphaEquals(uint8_t i, uint8_t j) {
// On Linux and Windows 8 or early version, '0' was returned for alpha channel
// from capturer APIs, on Windows 10, '255' was returned. So a workaround is
// to treat 0 as 255.
return i == j || ((i == 0 || i == 255) && (j == 0 || j == 255));
}
} // namespace
RgbaColor::RgbaColor(uint8_t blue, uint8_t green, uint8_t red, uint8_t alpha) {
this->blue = blue;
this->green = green;
this->red = red;
this->alpha = alpha;
}
RgbaColor::RgbaColor(uint8_t blue, uint8_t green, uint8_t red)
: RgbaColor(blue, green, red, 0xff) {}
RgbaColor::RgbaColor(const uint8_t* bgra)
: RgbaColor(bgra[0], bgra[1], bgra[2], bgra[3]) {}
bool RgbaColor::operator==(const RgbaColor& right) const {
return blue == right.blue && green == right.green && red == right.red &&
AlphaEquals(alpha, right.alpha);
}
bool RgbaColor::operator!=(const RgbaColor& right) const {
return !(*this == right);
}
} // namespace webrtc

View File

@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_RGBA_COLOR_H_
#define WEBRTC_MODULES_DESKTOP_CAPTURE_RGBA_COLOR_H_
#include <stdint.h>
#include "webrtc/modules/desktop_capture/desktop_frame.h"
namespace webrtc {
// A four-byte structure to store a color in BGRA format. This structure also
// provides functions to be created from uint8_t array, say,
// DesktopFrame::data(). It always uses BGRA order for internal storage to match
// DesktopFrame::data().
//
// This struct is for testing purpose only, and should not be used in production
// logic.
struct RgbaColor final {
// Creates a color with BGRA channels.
RgbaColor(uint8_t blue, uint8_t green, uint8_t red, uint8_t alpha);
// Creates a color with BGR channels, and set alpha channel to 255 (opaque).
RgbaColor(uint8_t blue, uint8_t green, uint8_t red);
// Creates a color from four-byte in BGRA order, i.e. DesktopFrame::data().
explicit RgbaColor(const uint8_t* bgra);
// Returns true if |this| and |right| is the same color.
bool operator==(const RgbaColor& right) const;
// Returns true if |this| and |right| are different colors.
bool operator!=(const RgbaColor& right) const;
uint8_t blue;
uint8_t green;
uint8_t red;
uint8_t alpha;
};
static_assert(
DesktopFrame::kBytesPerPixel == sizeof(RgbaColor),
"A pixel in DesktopFrame should be safe to be represented by a RgbaColor");
} // namespace webrtc
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_RGBA_COLOR_H_

View File

@ -8,6 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string.h>
#include <algorithm>
#include <initializer_list>
#include <memory>
#include <utility>
@ -15,12 +19,16 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/desktop_capture/rgba_color.h"
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/modules/desktop_capture/desktop_region.h"
#include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
#include "webrtc/modules/desktop_capture/screen_drawer.h"
#include "webrtc/system_wrappers/include/sleep.h"
#if defined(WEBRTC_WIN)
#include "webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h"
@ -34,6 +42,53 @@ const int kTestSharedMemoryId = 123;
namespace webrtc {
namespace {
ACTION_P(SaveUniquePtrArg, dest) {
*dest = std::move(*arg1);
}
// Expects |capturer| to successfully capture a frame, and returns it.
std::unique_ptr<DesktopFrame> CaptureFrame(
ScreenCapturer* capturer,
MockScreenCapturerCallback* callback) {
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(*callback,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
.WillOnce(SaveUniquePtrArg(&frame));
capturer->Capture(DesktopRegion());
EXPECT_TRUE(frame);
return frame;
}
// Returns true if color in |rect| of |frame| is |color|.
bool ArePixelsColoredBy(const DesktopFrame& frame,
DesktopRect rect,
RgbaColor color) {
// 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 ScreenCapturerTest : public testing::Test {
public:
void SetUp() override {
@ -42,6 +97,93 @@ class ScreenCapturerTest : public testing::Test {
}
protected:
void TestCaptureUpdatedRegion(
std::initializer_list<ScreenCapturer*> capturers) {
RTC_DCHECK(capturers.size() > 0);
// A large enough area for the tests, which should be able to fulfill by
// most of systems.
const int kTestArea = 512;
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 (ScreenCapturer* capturer : capturers) {
capturer->Start(&callback_);
}
for (int c = 0; c < 3; c++) {
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));
drawer->Clear();
drawer->DrawRectangle(rect, color);
const int wait_first_capture_round = 20;
for (int j = 0; j < wait_first_capture_round; j++) {
drawer->WaitForPendingDraws();
std::unique_ptr<DesktopFrame> frame =
CaptureFrame(*capturers.begin(), &callback_);
if (!frame) {
return;
}
if (ArePixelsColoredBy(*frame, rect, color)) {
// The first capturer successfully captured the frame we expected.
// So the others should also be able to capture it.
break;
} else {
ASSERT_LT(j, wait_first_capture_round);
}
}
for (ScreenCapturer* capturer : capturers) {
if (capturer == *capturers.begin()) {
// TODO(zijiehe): ScreenCapturerX11 and ScreenCapturerWinGdi cannot
// capture a correct frame again if screen does not update.
continue;
}
std::unique_ptr<DesktopFrame> frame =
CaptureFrame(capturer, &callback_);
if (!frame) {
return;
}
ASSERT_TRUE(ArePixelsColoredBy(*frame, rect, color));
}
}
}
}
void TestCaptureUpdatedRegion() {
TestCaptureUpdatedRegion({capturer_.get()});
}
#if defined(WEBRTC_WIN)
bool SetDirectxCapturerMode() {
if (!ScreenCapturerWinDirectx::IsSupported()) {
LOG(LS_WARNING) << "Directx capturer is not supported";
return false;
}
DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
options.set_allow_directx_capturer(true);
capturer_.reset(ScreenCapturer::Create(options));
return true;
}
#endif // defined(WEBRTC_WIN)
std::unique_ptr<ScreenCapturer> capturer_;
MockScreenCapturerCallback callback_;
};
@ -74,10 +216,6 @@ class FakeSharedMemoryFactory : public SharedMemoryFactory {
RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory);
};
ACTION_P(SaveUniquePtrArg, dest) {
*dest = std::move(*arg1);
}
TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) {
webrtc::ScreenCapturer::ScreenList screens;
EXPECT_TRUE(capturer_->GetScreenList(&screens));
@ -117,6 +255,10 @@ TEST_F(ScreenCapturerTest, Capture) {
EXPECT_TRUE(it.IsAtEnd());
}
TEST_F(ScreenCapturerTest, CaptureUpdatedRegion) {
TestCaptureUpdatedRegion();
}
#if defined(WEBRTC_WIN)
TEST_F(ScreenCapturerTest, UseSharedBuffers) {
@ -151,15 +293,10 @@ TEST_F(ScreenCapturerTest, UseMagnifier) {
}
TEST_F(ScreenCapturerTest, UseDirectxCapturer) {
if (!ScreenCapturerWinDirectx::IsSupported()) {
LOG(LS_WARNING) << "Directx capturer is not supported";
if (!SetDirectxCapturerMode()) {
return;
}
DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
options.set_allow_directx_capturer(true);
capturer_.reset(ScreenCapturer::Create(options));
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
@ -171,15 +308,10 @@ TEST_F(ScreenCapturerTest, UseDirectxCapturer) {
}
TEST_F(ScreenCapturerTest, UseDirectxCapturerWithSharedBuffers) {
if (!ScreenCapturerWinDirectx::IsSupported()) {
LOG(LS_WARNING) << "Directx capturer is not supported";
if (!SetDirectxCapturerMode()) {
return;
}
DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
options.set_allow_directx_capturer(true);
capturer_.reset(ScreenCapturer::Create(options));
std::unique_ptr<DesktopFrame> frame;
EXPECT_CALL(callback_,
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
@ -194,6 +326,24 @@ TEST_F(ScreenCapturerTest, UseDirectxCapturerWithSharedBuffers) {
EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId);
}
TEST_F(ScreenCapturerTest, CaptureUpdatedRegionWithDirectxCapturer) {
if (!SetDirectxCapturerMode()) {
return;
}
TestCaptureUpdatedRegion();
}
TEST_F(ScreenCapturerTest, TwoDirectxCapturers) {
if (!SetDirectxCapturerMode()) {
return;
}
std::unique_ptr<ScreenCapturer> capturer2(capturer_.release());
RTC_CHECK(SetDirectxCapturerMode());
TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()});
}
#endif // defined(WEBRTC_WIN)
} // namespace webrtc

View File

@ -15,30 +15,40 @@
#include <memory>
#include "webrtc/modules/desktop_capture/rgba_color.h"
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
namespace webrtc {
// A set of platform independent functions to draw various of shapes on the
// screen. This class is for testing ScreenCapturer* implementations only, and
// should not be used in production logic.
// A set of basic platform dependent functions to draw various shapes on the
// screen.
class ScreenDrawer {
public:
// Creates a ScreenDrawer for the current platform.
// Creates a ScreenDrawer for the current platform, returns nullptr if no
// ScreenDrawer implementation available.
static std::unique_ptr<ScreenDrawer> Create();
ScreenDrawer() {}
virtual ~ScreenDrawer() {}
// Returns a rect, on which this instance can draw.
// Returns the region inside which DrawRectangle() function are expected to
// work, in capturer coordinates (assuming ScreenCapturer::SelectScreen has
// not been called). This region may exclude regions of the screen reserved by
// the OS for things like menu bars or app launchers.
virtual DesktopRect DrawableRegion() = 0;
// Draws a rectangle to cover |rect| with color |rgba|. Note, rect.bottom()
// and rect.right() two lines are not included.
virtual void DrawRectangle(DesktopRect rect, uint32_t rgba) = 0;
// Draws a rectangle to cover |rect| with |color|. Note, rect.bottom() and
// rect.right() two lines are not included. The part of |rect| which is out of
// DrawableRegion() will be ignored.
virtual void DrawRectangle(DesktopRect rect, RgbaColor color) = 0;
// Clears all content on the screen.
// Clears all content on the screen by filling the area with black.
virtual void Clear() = 0;
// Blocks current thread until OS finishes previous DrawRectangle() actions.
// ScreenCapturer should be able to capture the changes after this function
// finish.
virtual void WaitForPendingDraws() = 0;
};
} // namespace webrtc

View File

@ -13,6 +13,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/modules/desktop_capture/screen_drawer.h"
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
#include "webrtc/system_wrappers/include/sleep.h"
namespace webrtc {
@ -26,12 +27,12 @@ class ScreenDrawerLinux : public ScreenDrawer {
// ScreenDrawer interface.
DesktopRect DrawableRegion() override;
void DrawRectangle(DesktopRect rect, uint32_t rgba) override;
void DrawRectangle(DesktopRect rect, RgbaColor color) override;
void Clear() override;
void WaitForPendingDraws() override;
private:
rtc::scoped_refptr<SharedXDisplay> display_;
Screen* screen_;
int screen_num_;
DesktopRect rect_;
Window window_;
@ -42,15 +43,18 @@ class ScreenDrawerLinux : public ScreenDrawer {
ScreenDrawerLinux::ScreenDrawerLinux() {
display_ = SharedXDisplay::CreateDefault();
RTC_CHECK(display_.get());
screen_ = DefaultScreenOfDisplay(display_->display());
RTC_CHECK(screen_);
screen_num_ = DefaultScreen(display_->display());
rect_ = DesktopRect::MakeWH(screen_->width, screen_->height);
window_ = XCreateSimpleWindow(display_->display(),
RootWindow(display_->display(), screen_num_), 0,
0, rect_.width(), rect_.height(), 0,
BlackPixel(display_->display(), screen_num_),
BlackPixel(display_->display(), screen_num_));
XWindowAttributes root_attributes;
if (!XGetWindowAttributes(display_->display(),
RootWindow(display_->display(), screen_num_),
&root_attributes)) {
RTC_DCHECK(false) << "Failed to get root window size.";
}
window_ = XCreateSimpleWindow(
display_->display(), RootWindow(display_->display(), screen_num_), 0, 0,
root_attributes.width, root_attributes.height, 0,
BlackPixel(display_->display(), screen_num_),
BlackPixel(display_->display(), screen_num_));
XSelectInput(display_->display(), window_, StructureNotifyMask);
XMapWindow(display_->display(), window_);
while (true) {
@ -61,8 +65,23 @@ ScreenDrawerLinux::ScreenDrawerLinux() {
}
}
XFlush(display_->display());
Window child;
int x, y;
if (!XTranslateCoordinates(display_->display(), window_,
RootWindow(display_->display(), screen_num_), 0, 0,
&x, &y, &child)) {
RTC_DCHECK(false) << "Failed to get window position.";
}
// Some window manager does not allow a window to cover two or more monitors.
// So if the window is on the first monitor of a two-monitor system, the
// second half won't be able to show up without changing configurations of WM,
// and its DrawableRegion() is not accurate.
rect_ = DesktopRect::MakeLTRB(x, y, root_attributes.width,
root_attributes.height);
context_ = DefaultGC(display_->display(), screen_num_);
colormap_ = DefaultColormap(display_->display(), screen_num_);
// Wait for window animations.
SleepMs(200);
}
ScreenDrawerLinux::~ScreenDrawerLinux() {
@ -74,33 +93,42 @@ DesktopRect ScreenDrawerLinux::DrawableRegion() {
return rect_;
}
void ScreenDrawerLinux::DrawRectangle(DesktopRect rect, uint32_t rgba) {
int r = (rgba & 0xff00) >> 8;
int g = (rgba & 0xff0000) >> 16;
int b = (rgba & 0xff000000) >> 24;
void ScreenDrawerLinux::DrawRectangle(DesktopRect rect, RgbaColor color) {
rect.Translate(-rect_.left(), -rect_.top());
XColor xcolor;
// X11 does not support Alpha.
XColor color;
// X11 uses 16 bits for each primary color.
color.red = r * 256;
color.green = g * 256;
color.blue = b * 256;
color.flags = DoRed | DoGreen | DoBlue;
XAllocColor(display_->display(), colormap_, &color);
XSetForeground(display_->display(), context_, color.pixel);
// X11 uses 16 bits for each primary color, so we need to slightly normalize
// a 8 bits channel to 16 bits channel, by setting the low 8 bits as its high
// 8 bits to avoid a mismatch of color returned by capturer.
xcolor.red = (color.red << 8) + color.red;
xcolor.green = (color.green << 8) + color.green;
xcolor.blue = (color.blue << 8) + color.blue;
xcolor.flags = DoRed | DoGreen | DoBlue;
XAllocColor(display_->display(), colormap_, &xcolor);
XSetForeground(display_->display(), context_, xcolor.pixel);
XFillRectangle(display_->display(), window_, context_, rect.left(),
rect.top(), rect.width(), rect.height());
XFlush(display_->display());
}
void ScreenDrawerLinux::Clear() {
DrawRectangle(DrawableRegion(), 0);
DrawRectangle(rect_, RgbaColor(0, 0, 0));
}
// TODO(zijiehe): Find the right signal from X11 to indicate the finish of all
// pending paintings.
void ScreenDrawerLinux::WaitForPendingDraws() {
SleepMs(50);
}
} // namespace
// static
std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() {
return std::unique_ptr<ScreenDrawer>(new ScreenDrawerLinux());
if (SharedXDisplay::CreateDefault().get()) {
return std::unique_ptr<ScreenDrawer>(new ScreenDrawerLinux());
}
return nullptr;
}
} // namespace webrtc

View File

@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/random.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/system_wrappers/include/logging.h"
#include "webrtc/system_wrappers/include/sleep.h"
namespace webrtc {
@ -26,11 +27,16 @@ namespace webrtc {
TEST(ScreenDrawerTest, DISABLED_DrawRectangles) {
std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create();
if (!drawer) {
// No ScreenDrawer implementation for current platform.
LOG(LS_WARNING) << "No ScreenDrawer implementation for current platform.";
return;
}
if (drawer->DrawableRegion().is_empty()) {
LOG(LS_WARNING) << "ScreenDrawer of current platform does not provide a "
"non-empty DrawableRegion().";
return;
}
drawer->Clear();
DesktopRect rect = drawer->DrawableRegion();
Random random(rtc::TimeMicros());
for (int i = 0; i < 100; i++) {
@ -40,16 +46,15 @@ TEST(ScreenDrawerTest, DISABLED_DrawRectangles) {
drawer->DrawRectangle(
DesktopRect::MakeLTRB(left, top, random.Rand(left + 1, rect.right()),
random.Rand(top + 1, rect.bottom())),
random.Rand<uint32_t>());
RgbaColor(random.Rand<uint8_t>(), random.Rand<uint8_t>(),
random.Rand<uint8_t>(), random.Rand<uint8_t>()));
if (i == 50) {
SleepMs(10000);
drawer->Clear();
}
}
SleepMs(10000);
drawer->Clear();
}
} // namespace webrtc

View File

@ -13,6 +13,7 @@
#include <memory>
#include "webrtc/modules/desktop_capture/screen_drawer.h"
#include "webrtc/system_wrappers/include/sleep.h"
namespace webrtc {
@ -34,6 +35,11 @@ HWND CreateDrawerWindow(DesktopRect rect) {
return hwnd;
}
COLORREF ColorToRef(RgbaColor color) {
// Windows device context does not support alpha.
return RGB(color.red, color.green, color.blue);
}
// A ScreenDrawer implementation for Windows.
class ScreenDrawerWin : public ScreenDrawer {
public:
@ -42,10 +48,17 @@ class ScreenDrawerWin : public ScreenDrawer {
// ScreenDrawer interface.
DesktopRect DrawableRegion() override;
void DrawRectangle(DesktopRect rect, uint32_t rgba) override;
void DrawRectangle(DesktopRect rect, RgbaColor color) override;
void Clear() override;
void WaitForPendingDraws() override;
private:
// Draw a line with |color|.
void DrawLine(DesktopVector start, DesktopVector end, RgbaColor color);
// Draw a dot with |color|.
void DrawDot(DesktopVector vect, RgbaColor color);
const DesktopRect rect_;
HWND window_;
HDC hdc_;
@ -57,8 +70,12 @@ ScreenDrawerWin::ScreenDrawerWin()
window_(CreateDrawerWindow(rect_)),
hdc_(GetWindowDC(window_)) {
// We do not need to handle any messages for the |window_|, so disable Windows
// process windows ghosting feature.
// from processing windows ghosting feature.
DisableProcessWindowsGhosting();
// Always use stock pen (DC_PEN) and brush (DC_BRUSH).
SelectObject(hdc_, GetStockObject(DC_PEN));
SelectObject(hdc_, GetStockObject(DC_BRUSH));
}
ScreenDrawerWin::~ScreenDrawerWin() {
@ -71,20 +88,49 @@ DesktopRect ScreenDrawerWin::DrawableRegion() {
return rect_;
}
void ScreenDrawerWin::DrawRectangle(DesktopRect rect, uint32_t rgba) {
int r = (rgba & 0xff00) >> 8;
int g = (rgba & 0xff0000) >> 16;
int b = (rgba & 0xff000000) >> 24;
// Windows device context does not support Alpha.
SelectObject(hdc_, GetStockObject(DC_PEN));
SelectObject(hdc_, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc_, RGB(r, g, b));
SetDCPenColor(hdc_, RGB(r, g, b));
void ScreenDrawerWin::DrawRectangle(DesktopRect rect, RgbaColor color) {
if (rect.width() == 1 && rect.height() == 1) {
// Rectangle function cannot draw a 1 pixel rectangle.
DrawDot(rect.top_left(), color);
return;
}
if (rect.width() == 1 || rect.height() == 1) {
// Rectangle function cannot draw a 1 pixel rectangle.
DrawLine(rect.top_left(), DesktopVector(rect.right(), rect.bottom()),
color);
return;
}
SetDCBrushColor(hdc_, ColorToRef(color));
SetDCPenColor(hdc_, ColorToRef(color));
Rectangle(hdc_, rect.left(), rect.top(), rect.right(), rect.bottom());
}
void ScreenDrawerWin::Clear() {
DrawRectangle(DrawableRegion(), 0);
DrawRectangle(rect_, RgbaColor(0, 0, 0));
}
// TODO(zijiehe): Find the right signal to indicate the finish of all pending
// paintings.
void ScreenDrawerWin::WaitForPendingDraws() {
SleepMs(50);
}
void ScreenDrawerWin::DrawLine(DesktopVector start,
DesktopVector end,
RgbaColor color) {
POINT points[2];
points[0].x = start.x();
points[0].y = start.y();
points[1].x = end.x();
points[1].y = end.y();
SetDCPenColor(hdc_, ColorToRef(color));
Polyline(hdc_, points, 2);
}
void ScreenDrawerWin::DrawDot(DesktopVector vect, RgbaColor color) {
SetPixel(hdc_, vect.x(), vect.y(), ColorToRef(color));
}
} // namespace

View File

@ -433,6 +433,8 @@
'sources': [
'desktop_capture/desktop_and_cursor_composer_unittest.cc',
'desktop_capture/mouse_cursor_monitor_unittest.cc',
'desktop_capture/rgba_color.cc',
'desktop_capture/rgba_color.h',
'desktop_capture/screen_capturer_differ_wrapper_unittest.cc',
'desktop_capture/screen_capturer_helper_unittest.cc',
'desktop_capture/screen_capturer_mac_unittest.cc',