diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn index 24140fa254..59c317942d 100644 --- a/webrtc/modules/desktop_capture/BUILD.gn +++ b/webrtc/modules/desktop_capture/BUILD.gn @@ -218,6 +218,8 @@ rtc_static_library("desktop_capture") { "win/d3d_device.h", "win/desktop.cc", "win/desktop.h", + "win/display_configuration_monitor.cc", + "win/display_configuration_monitor.h", "win/dxgi_adapter_duplicator.cc", "win/dxgi_adapter_duplicator.h", "win/dxgi_context.cc", diff --git a/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc b/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc index 2d2dee2ab5..b7c71c835c 100644 --- a/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc +++ b/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc @@ -201,7 +201,7 @@ DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() { window_rect.IntersectWith(window_region_rect_); // Convert |window_rect| to be relative to the top-left of the virtual screen. - DesktopRect screen_rect(GetScreenRect(kFullDesktopScreenId, L"")); + DesktopRect screen_rect(GetFullscreenRect()); window_rect.IntersectWith(screen_rect); window_rect.Translate(-screen_rect.left(), -screen_rect.top()); return window_rect; diff --git a/webrtc/modules/desktop_capture/desktop_capture_types.h b/webrtc/modules/desktop_capture/desktop_capture_types.h index f816773bb7..46346b0077 100644 --- a/webrtc/modules/desktop_capture/desktop_capture_types.h +++ b/webrtc/modules/desktop_capture/desktop_capture_types.h @@ -29,6 +29,8 @@ const WindowId kNullWindowId = 0; // - On Windows: integer display device index. // - On OSX: CGDirectDisplayID cast to intptr_t. // - On Linux (with X11): TBD. +// On Windows, ScreenId is implementation dependent: sending a ScreenId from one +// implementation to another usually won't work correctly. typedef intptr_t ScreenId; // The screen id corresponds to all screen combined together. diff --git a/webrtc/modules/desktop_capture/mac/desktop_configuration.h b/webrtc/modules/desktop_capture/mac/desktop_configuration.h index d54d0fb745..73550ac37d 100644 --- a/webrtc/modules/desktop_capture/mac/desktop_configuration.h +++ b/webrtc/modules/desktop_capture/mac/desktop_configuration.h @@ -57,9 +57,11 @@ struct MacDesktopConfiguration { MacDesktopConfiguration& operator=(const MacDesktopConfiguration& other); MacDesktopConfiguration& operator=(MacDesktopConfiguration&& other); - // Returns the desktop & display configurations in Cocoa-style "bottom-up" + // Returns the desktop & display configurations. + // If BottomLeftOrigin is used, the output is in Cocoa-style "bottom-up" // (the origin is the bottom-left of the primary monitor, and coordinates - // increase as you move up the screen). + // increase as you move up the screen). Otherwise, the configuration will be + // converted to follow top-left coordinate system as Windows and X11. static MacDesktopConfiguration GetCurrent(Origin origin); // Returns true if the given desktop configuration equals this one. diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm index 7bb6b2ccf5..2bb06b7b4b 100644 --- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm +++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm @@ -241,15 +241,15 @@ void MouseCursorMonitorMac::Capture() { state = OUTSIDE; position.set(-1, -1); } - } else { - position.subtract(configuration.bounds.top_left()); } } // Convert Density Independent Pixel to physical pixel. position = DesktopVector(round(position.x() * scale), round(position.y() * scale)); + // TODO(zijiehe): Remove this overload. callback_->OnMouseCursorPosition(state, position); - callback_->OnMouseCursorPosition(position); + callback_->OnMouseCursorPosition( + position.subtract(configuration.bounds.top_left())); } void MouseCursorMonitorMac::CaptureImage(float scale) { diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc b/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc index ebf00ac6df..43174cb08b 100644 --- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc +++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc @@ -20,6 +20,7 @@ #include "webrtc/modules/desktop_capture/desktop_geometry.h" #include "webrtc/modules/desktop_capture/mouse_cursor.h" #include "webrtc/modules/desktop_capture/win/cursor.h" +#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" #include "webrtc/modules/desktop_capture/win/window_capture_utils.h" #include "webrtc/rtc_base/logging.h" @@ -162,8 +163,10 @@ void MouseCursorMonitorWin::Capture() { position = position.subtract(rect.top_left()); } + // TODO(zijiehe): Remove this overload. callback_->OnMouseCursorPosition(inside ? INSIDE : OUTSIDE, position); - callback_->OnMouseCursorPosition(position); + callback_->OnMouseCursorPosition( + position.subtract(GetFullscreenRect().top_left())); } DesktopRect MouseCursorMonitorWin::GetScreenRect() { diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc b/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc index 9b30c49831..edde01c7ba 100644 --- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc +++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc @@ -202,7 +202,10 @@ void MouseCursorMonitorX11::Capture() { } const DesktopVector position(win_x, win_y); + // TODO(zijiehe): Remove this overload. callback_->OnMouseCursorPosition(state, position); + // X11 always starts the coordinate from (0, 0), so we do not need to + // translate here. callback_->OnMouseCursorPosition(position); } } diff --git a/webrtc/modules/desktop_capture/resolution_change_detector.h b/webrtc/modules/desktop_capture/resolution_change_detector.h index 6ccf8a7a17..f82c3900a1 100644 --- a/webrtc/modules/desktop_capture/resolution_change_detector.h +++ b/webrtc/modules/desktop_capture/resolution_change_detector.h @@ -17,7 +17,12 @@ namespace webrtc { class ResolutionChangeDetector { public: + // Checks whether the |size| has been changed comparing to the |size| passed + // in during last IsChanged() call. This function won't return false for the + // first time after construction or Reset() call. bool IsChanged(DesktopSize size); + + // Resets to the initial state. void Reset(); private: diff --git a/webrtc/modules/desktop_capture/win/display_configuration_monitor.cc b/webrtc/modules/desktop_capture/win/display_configuration_monitor.cc new file mode 100644 index 0000000000..5685d9574d --- /dev/null +++ b/webrtc/modules/desktop_capture/win/display_configuration_monitor.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 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/win/display_configuration_monitor.h" + +#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" + +namespace webrtc { + +bool DisplayConfigurationMonitor::IsChanged() { + DesktopRect rect = GetFullscreenRect(); + if (!initialized_) { + initialized_ = true; + rect_ = rect; + return false; + } + + if (rect.equals(rect_)) { + return false; + } + + rect_ = rect; + return true; +} + +void DisplayConfigurationMonitor::Reset() { + initialized_ = false; +} + +} // namespace webrtc diff --git a/webrtc/modules/desktop_capture/win/display_configuration_monitor.h b/webrtc/modules/desktop_capture/win/display_configuration_monitor.h new file mode 100644 index 0000000000..d13b45ed35 --- /dev/null +++ b/webrtc/modules/desktop_capture/win/display_configuration_monitor.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 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_WIN_DISPLAY_CONFIGURATION_MONITOR_H_ +#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DISPLAY_CONFIGURATION_MONITOR_H_ + +#include "webrtc/modules/desktop_capture/desktop_geometry.h" + +namespace webrtc { + +// A passive monitor to detect the change of display configuration on a Windows +// system. +// TODO(zijiehe): Also check for pixel format changes. +class DisplayConfigurationMonitor { + public: + // Checks whether the change of display configuration has happened after last + // IsChanged() call. This function won't return false for the first time after + // constructor or Reset() call. + bool IsChanged(); + + // Resets to the initial state. + void Reset(); + + private: + DesktopRect rect_; + bool initialized_ = false; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DISPLAY_CONFIGURATION_MONITOR_H_ diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc index 0cefb86cdc..4a6ab8e829 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc +++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc @@ -137,8 +137,7 @@ DxgiDuplicatorController::DoDuplicate(DxgiFrame* frame, int monitor_id) { // TODO(zijiehe): Confirm whether IDXGIOutput::GetDesc() and // IDXGIOutputDuplication::GetDesc() can detect the resolution change without // reinitialization. - if (resolution_change_detector_.IsChanged( - GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) { + if (display_configuration_monitor_.IsChanged()) { Deinitialize(); } @@ -266,7 +265,7 @@ bool DxgiDuplicatorController::DoInitialize() { void DxgiDuplicatorController::Deinitialize() { desktop_rect_ = DesktopRect(); duplicators_.clear(); - resolution_change_detector_.Reset(); + display_configuration_monitor_.Reset(); } bool DxgiDuplicatorController::ContextExpired( diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h index 8ea7f183c2..ddf02a89d1 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h +++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h @@ -18,9 +18,9 @@ #include #include "webrtc/modules/desktop_capture/desktop_geometry.h" -#include "webrtc/modules/desktop_capture/resolution_change_detector.h" #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" #include "webrtc/modules/desktop_capture/win/d3d_device.h" +#include "webrtc/modules/desktop_capture/win/display_configuration_monitor.h" #include "webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.h" #include "webrtc/modules/desktop_capture/win/dxgi_context.h" #include "webrtc/modules/desktop_capture/win/dxgi_frame.h" @@ -224,7 +224,7 @@ class DxgiDuplicatorController { DesktopVector dpi_; std::vector duplicators_; D3dInfo d3d_info_; - ResolutionChangeDetector resolution_change_detector_; + DisplayConfigurationMonitor display_configuration_monitor_; // A number to indicate how many succeeded duplications have been performed. uint32_t succeeded_duplications_ = 0; }; diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc index e640bde277..a8718459b2 100644 --- a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc +++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc @@ -65,13 +65,17 @@ bool IsScreenValid(DesktopCapturer::SourceId screen, std::wstring* device_key) { return !!enum_result; } +DesktopRect GetFullscreenRect() { + return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN), + GetSystemMetrics(SM_YVIRTUALSCREEN), + GetSystemMetrics(SM_CXVIRTUALSCREEN), + GetSystemMetrics(SM_CYVIRTUALSCREEN)); +} + DesktopRect GetScreenRect(DesktopCapturer::SourceId screen, const std::wstring& device_key) { if (screen == kFullDesktopScreenId) { - return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN), - GetSystemMetrics(SM_YVIRTUALSCREEN), - GetSystemMetrics(SM_CXVIRTUALSCREEN), - GetSystemMetrics(SM_CYVIRTUALSCREEN)); + return GetFullscreenRect(); } DISPLAY_DEVICE device; diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.h b/webrtc/modules/desktop_capture/win/screen_capture_utils.h index 73754b2eea..fdbf633084 100644 --- a/webrtc/modules/desktop_capture/win/screen_capture_utils.h +++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.h @@ -32,6 +32,10 @@ bool GetScreenList(DesktopCapturer::SourceList* screens, // id. bool IsScreenValid(DesktopCapturer::SourceId screen, std::wstring* device_key); +// Get the rect of the entire system in system coordinate system. I.e. the +// primary monitor always starts from (0, 0). +DesktopRect GetFullscreenRect(); + // Get the rect of the screen identified by |screen|, relative to the primary // display's top-left. If the screen device key does not match |device_key|, or // the screen does not exist, or any error happens, an empty rect is returned. diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc index 44c81ff12c..427cb93eae 100644 --- a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc +++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc @@ -148,14 +148,8 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() { } } - // If the display bounds have changed then recreate GDI resources. - // TODO(wez): Also check for pixel format changes. - DesktopRect screen_rect(DesktopRect::MakeXYWH( - GetSystemMetrics(SM_XVIRTUALSCREEN), - GetSystemMetrics(SM_YVIRTUALSCREEN), - GetSystemMetrics(SM_CXVIRTUALSCREEN), - GetSystemMetrics(SM_CYVIRTUALSCREEN))); - if (!screen_rect.equals(desktop_dc_rect_)) { + // If the display configurations have changed then recreate GDI resources. + if (display_configuration_monitor_.IsChanged()) { if (desktop_dc_) { ReleaseDC(NULL, desktop_dc_); desktop_dc_ = nullptr; @@ -164,7 +158,6 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() { DeleteDC(memory_dc_); memory_dc_ = nullptr; } - desktop_dc_rect_ = DesktopRect(); } if (!desktop_dc_) { @@ -176,8 +169,6 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() { memory_dc_ = CreateCompatibleDC(desktop_dc_); RTC_CHECK(memory_dc_); - desktop_dc_rect_ = screen_rect; - // Make sure the frame buffers will be reallocated. queue_.Reset(); } diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h index 70a939d760..6822895c6d 100644 --- a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h +++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h @@ -18,6 +18,7 @@ #include "webrtc/modules/desktop_capture/desktop_capturer.h" #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" +#include "webrtc/modules/desktop_capture/win/display_configuration_monitor.h" #include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h" #include "webrtc/rtc_base/constructormagic.h" @@ -69,9 +70,7 @@ class ScreenCapturerWinGdi : public DesktopCapturer { // Queue of the frames buffers. ScreenCaptureFrameQueue queue_; - // Rectangle describing the bounds of the desktop device context, relative to - // the primary display's top-left. - DesktopRect desktop_dc_rect_; + DisplayConfigurationMonitor display_configuration_monitor_; HMODULE dwmapi_library_ = NULL; DwmEnableCompositionFunc composition_func_ = nullptr; diff --git a/webrtc/modules/desktop_capture/win/window_capture_utils.h b/webrtc/modules/desktop_capture/win/window_capture_utils.h index c13cad7bda..8f59c12d1b 100644 --- a/webrtc/modules/desktop_capture/win/window_capture_utils.h +++ b/webrtc/modules/desktop_capture/win/window_capture_utils.h @@ -18,7 +18,9 @@ namespace webrtc { // Output the window rect, with the left/right/bottom frame border cropped if // the window is maximized. |cropped_rect| is the cropped rect relative to the // desktop. |original_rect| is the original rect returned from GetWindowRect. -// Returns true if all API calls succeeded. +// Returns true if all API calls succeeded. The returned DesktopRect is in +// system coordinates, i.e. the primary monitor on the system always starts from +// (0, 0). bool GetCroppedWindowRect(HWND window, DesktopRect* cropped_rect, DesktopRect* original_rect);