From 3e45cb577ef750209b169c2d68c32246bbb52ef8 Mon Sep 17 00:00:00 2001 From: Zijie He Date: Mon, 17 Jul 2017 20:33:47 -0700 Subject: [PATCH] Mapping screen id from DirectX capturer to GDI capturer This change ensures DirectX capturer to return the same ScreenId as GDI capturer for each monitor. So MouseCursoeMonitor can work correctly with the DirectX capturer. This is a temporary fix of webrtc:7950. Bug: webrtc:7950 Change-Id: Icd3f40556701811c21c773a39260a74db43979f3 Reviewed-on: https://chromium-review.googlesource.com/571101 Commit-Queue: Zijie He Reviewed-by: Sergey Ulanov Cr-Commit-Position: refs/heads/master@{#19079} --- webrtc/modules/desktop_capture/BUILD.gn | 1 + .../win/screen_capture_utils.cc | 4 + .../win/screen_capture_utils.h | 2 +- .../win/screen_capture_utils_unittest.cc | 4 +- .../win/screen_capturer_win_directx.cc | 87 ++++++++++++++++--- .../win/screen_capturer_win_directx.h | 17 ++++ .../screen_capturer_win_directx_unittest.cc | 41 +++++++++ 7 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 webrtc/modules/desktop_capture/win/screen_capturer_win_directx_unittest.cc diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn index 4682ce8c50..889f0fad4b 100644 --- a/webrtc/modules/desktop_capture/BUILD.gn +++ b/webrtc/modules/desktop_capture/BUILD.gn @@ -89,6 +89,7 @@ if (rtc_include_tests) { "win/cursor_unittest_resources.h", "win/cursor_unittest_resources.rc", "win/screen_capture_utils_unittest.cc", + "win/screen_capturer_win_directx_unittest.cc", ] deps = [ ":desktop_capture", diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc index d06c869567..e640bde277 100644 --- a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc +++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc @@ -12,6 +12,10 @@ #include +#include +#include + +#include "webrtc/modules/desktop_capture/desktop_capturer.h" #include "webrtc/rtc_base/checks.h" #include "webrtc/rtc_base/win32.h" diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.h b/webrtc/modules/desktop_capture/win/screen_capture_utils.h index 90dd38ff22..73754b2eea 100644 --- a/webrtc/modules/desktop_capture/win/screen_capture_utils.h +++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.h @@ -21,7 +21,7 @@ namespace webrtc { // Output the list of active screens into |screens|. Returns true if succeeded, // or false if it fails to enumerate the display devices. If the |device_names| // is provided, it will be filled with the DISPLAY_DEVICE.DeviceName in UTF-8 -// encoding. Once this function returns true, consumers can always assume that +// encoding. If this function returns true, consumers can always assume that // |screens|[i] and |device_names|[i] indicate the same monitor on the system. bool GetScreenList(DesktopCapturer::SourceList* screens, std::vector* device_names = nullptr); diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils_unittest.cc b/webrtc/modules/desktop_capture/win/screen_capture_utils_unittest.cc index 9c852534b4..47f02e4551 100644 --- a/webrtc/modules/desktop_capture/win/screen_capture_utils_unittest.cc +++ b/webrtc/modules/desktop_capture/win/screen_capture_utils_unittest.cc @@ -22,9 +22,9 @@ TEST(ScreenCaptureUtilsTest, GetScreenList) { DesktopCapturer::SourceList screens; std::vector device_names; - GetScreenList(&screens); + ASSERT_TRUE(GetScreenList(&screens)); screens.clear(); - GetScreenList(&screens, &device_names); + ASSERT_TRUE(GetScreenList(&screens, &device_names)); ASSERT_EQ(screens.size(), device_names.size()); } diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc index 722353e4f3..c4d778f8f8 100644 --- a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc +++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc @@ -10,10 +10,13 @@ #include "webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h" +#include #include #include +#include #include "webrtc/modules/desktop_capture/desktop_frame.h" +#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" #include "webrtc/rtc_base/checks.h" #include "webrtc/rtc_base/logging.h" #include "webrtc/rtc_base/ptr_util.h" @@ -41,6 +44,60 @@ bool ScreenCapturerWinDirectx::IsCurrentSessionSupported() { return DxgiDuplicatorController::IsCurrentSessionSupported(); } +// static +bool ScreenCapturerWinDirectx::GetScreenListFromDeviceNames( + const std::vector& device_names, + DesktopCapturer::SourceList* screens) { + RTC_DCHECK(screens->empty()); + + DesktopCapturer::SourceList gdi_screens; + std::vector gdi_names; + if (!GetScreenList(&gdi_screens, &gdi_names)) { + return false; + } + + RTC_DCHECK_EQ(gdi_screens.size(), gdi_names.size()); + + ScreenId max_screen_id = -1; + for (const DesktopCapturer::Source& screen : gdi_screens) { + max_screen_id = std::max(max_screen_id, screen.id); + } + + for (const auto& device_name : device_names) { + const auto it = std::find( + gdi_names.begin(), gdi_names.end(), device_name); + if (it == gdi_names.end()) { + // devices_names[i] has not been found in gdi_names, so use max_screen_id. + max_screen_id++; + screens->push_back({ max_screen_id }); + } else { + screens->push_back({ gdi_screens[it - gdi_names.begin()] }); + } + } + + return true; +} + +// static +int ScreenCapturerWinDirectx::GetIndexFromScreenId( + ScreenId id, + const std::vector& device_names) { + DesktopCapturer::SourceList screens; + if (!GetScreenListFromDeviceNames(device_names, &screens)) { + return -1; + } + + RTC_DCHECK_EQ(device_names.size(), screens.size()); + + for (size_t i = 0; i < screens.size(); i++) { + if (screens[i].id == id) { + return static_cast(i); + } + } + + return -1; +} + ScreenCapturerWinDirectx::ScreenCapturerWinDirectx() : controller_(DxgiDuplicatorController::Instance()) {} @@ -115,29 +172,33 @@ void ScreenCapturerWinDirectx::CaptureFrame() { } bool ScreenCapturerWinDirectx::GetSourceList(SourceList* sources) { - int screen_count = controller_->ScreenCount(); - for (int i = 0; i < screen_count; i++) { - sources->push_back({i}); + std::vector device_names; + if (!controller_->GetDeviceNames(&device_names)) { + return false; } - return true; + + return GetScreenListFromDeviceNames(device_names, sources); } bool ScreenCapturerWinDirectx::SelectSource(SourceId id) { - if (id == current_screen_id_) { - return true; - } - if (id == kFullDesktopScreenId) { current_screen_id_ = id; return true; } - int screen_count = controller_->ScreenCount(); - if (id >= 0 && id < screen_count) { - current_screen_id_ = id; - return true; + std::vector device_names; + if (!controller_->GetDeviceNames(&device_names)) { + return false; } - return false; + + int index; + index = GetIndexFromScreenId(id, device_names); + if (index == -1) { + return false; + } + + current_screen_id_ = index; + return true; } } // namespace webrtc diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h index f383303b5d..b91882c655 100644 --- a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h +++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h @@ -51,6 +51,23 @@ class ScreenCapturerWinDirectx : public DesktopCapturer { // always try IsSupported() function. static bool IsCurrentSessionSupported(); + // Maps |device_names| with the result from GetScreenList() and creates a new + // SourceList to include only the ones in |device_names|. If this function + // returns true, consumers can always assume |device_names|.size() equals to + // |screens|->size(), meanwhile |device_names|[i] and |screens|[i] indicate + // the same monitor on the system. + // Public for test only. + static bool GetScreenListFromDeviceNames( + const std::vector& device_names, + DesktopCapturer::SourceList* screens); + + // Maps |id| with the result from GetScreenListFromDeviceNames() and returns + // the index of the entity in |device_names|. This function returns -1 if |id| + // cannot be found. + // Public for test only. + static int GetIndexFromScreenId(ScreenId id, + const std::vector& device_names); + explicit ScreenCapturerWinDirectx(); ~ScreenCapturerWinDirectx() override; diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx_unittest.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx_unittest.cc new file mode 100644 index 0000000000..577be0aa97 --- /dev/null +++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx_unittest.cc @@ -0,0 +1,41 @@ +/* + * 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/screen_capturer_win_directx.h" + +#include +#include + +#include "webrtc/modules/desktop_capture/desktop_capturer.h" +#include "webrtc/test/gtest.h" + +namespace webrtc { + +// This test cannot ensure GetScreenListFromDeviceNames() won't reorder the +// devices in its output, since the device name is missing. +TEST(ScreenCaptureUtilsTest, GetScreenListFromDeviceNamesAndGetIndex) { + const std::vector device_names = { + "\\\\.\\DISPLAY0", + "\\\\.\\DISPLAY1", + "\\\\.\\DISPLAY2", + }; + DesktopCapturer::SourceList screens; + ASSERT_TRUE(ScreenCapturerWinDirectx::GetScreenListFromDeviceNames( + device_names, &screens)); + ASSERT_EQ(device_names.size(), screens.size()); + + for (size_t i = 0; i < screens.size(); i++) { + ASSERT_EQ(ScreenCapturerWinDirectx::GetIndexFromScreenId( + screens[i].id, device_names), + static_cast(i)); + } +} + +} // namespace webrtc