[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
Review-Url: https://codereview.webrtc.org/2268093002
Cr-Commit-Position: refs/heads/master@{#14058}
diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn
index 367c8ee..c3e24a1 100644
--- a/webrtc/modules/BUILD.gn
+++ b/webrtc/modules/BUILD.gn
@@ -508,6 +508,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_helper_unittest.cc",
"desktop_capture/screen_capturer_mac_unittest.cc",
"desktop_capture/screen_capturer_mock_objects.h",
diff --git a/webrtc/modules/desktop_capture/rgba_color.cc b/webrtc/modules/desktop_capture/rgba_color.cc
new file mode 100644
index 0000000..2342b46
--- /dev/null
+++ b/webrtc/modules/desktop_capture/rgba_color.cc
@@ -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
diff --git a/webrtc/modules/desktop_capture/rgba_color.h b/webrtc/modules/desktop_capture/rgba_color.h
new file mode 100644
index 0000000..ff4a258
--- /dev/null
+++ b/webrtc/modules/desktop_capture/rgba_color.h
@@ -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_
diff --git a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc
index 6d2c0eb..a2ef7f9 100644
--- a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc
+++ b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc
@@ -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,48 @@
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;
+}
+
+// Expects color in |rect| of |frame| is |color|.
+void ExpectPixelsAreColoredBy(const DesktopFrame& frame,
+ DesktopRect rect,
+ RgbaColor color) {
+ // updated_region() should cover the painted area.
+ DesktopRegion updated_region(frame.updated_region());
+ updated_region.IntersectWith(rect);
+ ASSERT_TRUE(updated_region.Equals(DesktopRegion(rect)));
+
+ // 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++) {
+ ASSERT_EQ(color, RgbaColor(column));
+ column += DesktopFrame::kBytesPerPixel;
+ }
+ row += frame.stride();
+ }
+}
+
+} // namespace
+
class ScreenCapturerTest : public testing::Test {
public:
void SetUp() override {
@@ -42,6 +92,84 @@
}
protected:
+ void TestCaptureUpdatedRegion(
+ std::initializer_list<ScreenCapturer*> capturers) {
+ // 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_);
+ }
+
+#if defined(WEBRTC_LINUX)
+ // TODO(zijiehe): ScreenCapturerX11 won't be able to capture correct images
+ // in the first several capture attempts.
+ for (int i = 0; i < 10; i++) {
+ for (ScreenCapturer* capturer : capturers) {
+ std::unique_ptr<DesktopFrame> frame =
+ CaptureFrame(capturer, &callback_);
+ if (!frame) {
+ return;
+ }
+ }
+ }
+#endif
+
+ 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);
+ drawer->WaitForPendingDraws();
+
+ for (ScreenCapturer* capturer : capturers) {
+ std::unique_ptr<DesktopFrame> frame =
+ CaptureFrame(capturer, &callback_);
+ if (!frame) {
+ return;
+ }
+
+ ExpectPixelsAreColoredBy(*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 +202,6 @@
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 +241,10 @@
EXPECT_TRUE(it.IsAtEnd());
}
+TEST_F(ScreenCapturerTest, CaptureUpdatedRegion) {
+ TestCaptureUpdatedRegion();
+}
+
#if defined(WEBRTC_WIN)
TEST_F(ScreenCapturerTest, UseSharedBuffers) {
@@ -151,15 +279,10 @@
}
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 +294,10 @@
}
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 +312,25 @@
EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId);
}
+TEST_F(ScreenCapturerTest, CaptureUpdatedRegionWithDirectxCapturer) {
+ if (!SetDirectxCapturerMode()) {
+ return;
+ }
+
+ TestCaptureUpdatedRegion();
+}
+
+// TODO(zijiehe): Enable this test after CL 2299663003 has been submitted.
+TEST_F(ScreenCapturerTest, DISABLED_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
diff --git a/webrtc/modules/desktop_capture/screen_drawer.h b/webrtc/modules/desktop_capture/screen_drawer.h
index 899fc0f..d7ec5d1 100644
--- a/webrtc/modules/desktop_capture/screen_drawer.h
+++ b/webrtc/modules/desktop_capture/screen_drawer.h
@@ -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
diff --git a/webrtc/modules/desktop_capture/screen_drawer_linux.cc b/webrtc/modules/desktop_capture/screen_drawer_linux.cc
index 2aff80b..08d8195 100644
--- a/webrtc/modules/desktop_capture/screen_drawer_linux.cc
+++ b/webrtc/modules/desktop_capture/screen_drawer_linux.cc
@@ -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 @@
// 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 @@
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 @@
}
}
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 @@
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
diff --git a/webrtc/modules/desktop_capture/screen_drawer_unittest.cc b/webrtc/modules/desktop_capture/screen_drawer_unittest.cc
index 345a962..b5f6ba5 100644
--- a/webrtc/modules/desktop_capture/screen_drawer_unittest.cc
+++ b/webrtc/modules/desktop_capture/screen_drawer_unittest.cc
@@ -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 @@
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;
}
- drawer->Clear();
+ if (drawer->DrawableRegion().is_empty()) {
+ LOG(LS_WARNING) << "ScreenDrawer of current platform does not provide a "
+ "non-empty DrawableRegion().";
+ return;
+ }
+
DesktopRect rect = drawer->DrawableRegion();
Random random(rtc::TimeMicros());
for (int i = 0; i < 100; i++) {
@@ -40,16 +46,15 @@
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
diff --git a/webrtc/modules/desktop_capture/screen_drawer_win.cc b/webrtc/modules/desktop_capture/screen_drawer_win.cc
index 061a405..6ef414d 100644
--- a/webrtc/modules/desktop_capture/screen_drawer_win.cc
+++ b/webrtc/modules/desktop_capture/screen_drawer_win.cc
@@ -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 @@
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 @@
// 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 @@
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,51 @@
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() {
+ // DirectX capturer reads data from GPU, so there is a certain delay before
+ // Windows sends the data to GPU.
+ SleepMs(100);
+}
+
+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
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 16e21a2..1a139a0 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -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_helper_unittest.cc',
'desktop_capture/screen_capturer_mac_unittest.cc',
'desktop_capture/screen_capturer_mock_objects.h',