diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index 367c8eed09..c3e24a1de7 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -508,6 +508,8 @@ if (rtc_include_tests) { 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 0000000000..2342b46915 --- /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 0000000000..ff4a258415 --- /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 + +#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 6d2c0eb065..a2ef7f9d73 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 + +#include +#include #include #include @@ -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 @@ 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 CaptureFrame( + ScreenCapturer* capturer, + MockScreenCapturerCallback* callback) { + std::unique_ptr 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 @@ class ScreenCapturerTest : public testing::Test { } protected: + void TestCaptureUpdatedRegion( + std::initializer_list 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 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 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 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 capturer_; MockScreenCapturerCallback callback_; }; @@ -74,10 +202,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 +241,10 @@ TEST_F(ScreenCapturerTest, Capture) { EXPECT_TRUE(it.IsAtEnd()); } +TEST_F(ScreenCapturerTest, CaptureUpdatedRegion) { + TestCaptureUpdatedRegion(); +} + #if defined(WEBRTC_WIN) TEST_F(ScreenCapturerTest, UseSharedBuffers) { @@ -151,15 +279,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 frame; EXPECT_CALL(callback_, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) @@ -171,15 +294,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 frame; EXPECT_CALL(callback_, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) @@ -194,6 +312,25 @@ TEST_F(ScreenCapturerTest, UseDirectxCapturerWithSharedBuffers) { 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 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 899fc0f043..d7ec5d186c 100644 --- a/webrtc/modules/desktop_capture/screen_drawer.h +++ b/webrtc/modules/desktop_capture/screen_drawer.h @@ -15,30 +15,40 @@ #include +#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 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 2aff80b6c7..08d8195b42 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 @@ 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 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::Create() { - return std::unique_ptr(new ScreenDrawerLinux()); + if (SharedXDisplay::CreateDefault().get()) { + return std::unique_ptr(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 345a962223..b5f6ba5c1b 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 @@ namespace webrtc { TEST(ScreenDrawerTest, DISABLED_DrawRectangles) { std::unique_ptr 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()); + RgbaColor(random.Rand(), random.Rand(), + random.Rand(), random.Rand())); 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 061a40539e..6ef414dda9 100644 --- a/webrtc/modules/desktop_capture/screen_drawer_win.cc +++ b/webrtc/modules/desktop_capture/screen_drawer_win.cc @@ -13,6 +13,7 @@ #include #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,51 @@ 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() { + // 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 16e21a2ae1..1a139a02f5 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',