Query the system for WGC support instead of relying on version checks.
The Windows 2019 Enterprise SKU is based on RS5 but is missing support for WGC. This changes adds a function IsWgcSupported which will check that the API is actually present, which should be more robust than just performing a version check. Bug: webrtc:13932 Change-Id: Ib6a2278f316b9b86671df77fd37468c79564d655 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/258163 Reviewed-by: Alexander Cooper <alcooper@chromium.org> Commit-Queue: Austin Orion <auorion@microsoft.com> Cr-Commit-Position: refs/heads/main@{#36506}
This commit is contained in:
parent
385b6c5460
commit
2e1ac58631
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
enum class CaptureType { kWindow, kScreen };
|
||||||
|
|
||||||
// Type used to identify windows on the desktop. Values are platform-specific:
|
// Type used to identify windows on the desktop. Values are platform-specific:
|
||||||
// - On Windows: HWND cast to intptr_t.
|
// - On Windows: HWND cast to intptr_t.
|
||||||
// - On Linux (with X11): X11 Window (unsigned long) type cast to intptr_t.
|
// - On Linux (with X11): X11 Window (unsigned long) type cast to intptr_t.
|
||||||
|
|||||||
@ -54,8 +54,7 @@ bool DesktopCapturer::IsOccluded(const DesktopVector& pos) {
|
|||||||
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
|
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
|
||||||
const DesktopCaptureOptions& options) {
|
const DesktopCaptureOptions& options) {
|
||||||
#if defined(RTC_ENABLE_WIN_WGC)
|
#if defined(RTC_ENABLE_WIN_WGC)
|
||||||
if (options.allow_wgc_capturer() &&
|
if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kWindow)) {
|
||||||
rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_RS5) {
|
|
||||||
return WgcCapturerWin::CreateRawWindowCapturer(options);
|
return WgcCapturerWin::CreateRawWindowCapturer(options);
|
||||||
}
|
}
|
||||||
#endif // defined(RTC_ENABLE_WIN_WGC)
|
#endif // defined(RTC_ENABLE_WIN_WGC)
|
||||||
@ -78,8 +77,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
|
|||||||
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
|
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
|
||||||
const DesktopCaptureOptions& options) {
|
const DesktopCaptureOptions& options) {
|
||||||
#if defined(RTC_ENABLE_WIN_WGC)
|
#if defined(RTC_ENABLE_WIN_WGC)
|
||||||
if (options.allow_wgc_capturer() &&
|
if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kScreen)) {
|
||||||
rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_20H1) {
|
|
||||||
return WgcCapturerWin::CreateRawScreenCapturer(options);
|
return WgcCapturerWin::CreateRawScreenCapturer(options);
|
||||||
}
|
}
|
||||||
#endif // defined(RTC_ENABLE_WIN_WGC)
|
#endif // defined(RTC_ENABLE_WIN_WGC)
|
||||||
|
|||||||
@ -144,7 +144,7 @@ HRESULT WgcCaptureSession::StartCapture() {
|
|||||||
|
|
||||||
ComPtr<WGC::IDirect3D11CaptureFramePoolStatics> frame_pool_statics;
|
ComPtr<WGC::IDirect3D11CaptureFramePoolStatics> frame_pool_statics;
|
||||||
hr = GetActivationFactory<
|
hr = GetActivationFactory<
|
||||||
ABI::Windows::Graphics::Capture::IDirect3D11CaptureFramePoolStatics,
|
WGC::IDirect3D11CaptureFramePoolStatics,
|
||||||
RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool>(
|
RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool>(
|
||||||
&frame_pool_statics);
|
&frame_pool_statics);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
|
|||||||
@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
#include "modules/desktop_capture/win/wgc_capturer_win.h"
|
#include "modules/desktop_capture/win/wgc_capturer_win.h"
|
||||||
|
|
||||||
|
#include <windows.foundation.metadata.h>
|
||||||
|
#include <windows.graphics.capture.h>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
|
#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
|
||||||
@ -17,6 +20,9 @@
|
|||||||
#include "modules/desktop_capture/win/wgc_desktop_frame.h"
|
#include "modules/desktop_capture/win/wgc_desktop_frame.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
#include "rtc_base/time_utils.h"
|
#include "rtc_base/time_utils.h"
|
||||||
|
#include "rtc_base/win/get_activation_factory.h"
|
||||||
|
#include "rtc_base/win/hstring.h"
|
||||||
|
#include "rtc_base/win/windows_version.h"
|
||||||
#include "system_wrappers/include/metrics.h"
|
#include "system_wrappers/include/metrics.h"
|
||||||
|
|
||||||
namespace WGC = ABI::Windows::Graphics::Capture;
|
namespace WGC = ABI::Windows::Graphics::Capture;
|
||||||
@ -26,6 +32,11 @@ namespace webrtc {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const wchar_t kWgcSessionType[] =
|
||||||
|
L"Windows.Graphics.Capture.GraphicsCaptureSession";
|
||||||
|
const wchar_t kApiContract[] = L"Windows.Foundation.UniversalApiContract";
|
||||||
|
const UINT16 kRequiredApiContractVersion = 8;
|
||||||
|
|
||||||
enum class WgcCapturerResult {
|
enum class WgcCapturerResult {
|
||||||
kSuccess = 0,
|
kSuccess = 0,
|
||||||
kNoDirect3dDevice = 1,
|
kNoDirect3dDevice = 1,
|
||||||
@ -45,6 +56,65 @@ void RecordWgcCapturerResult(WgcCapturerResult error) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
bool IsWgcSupported(CaptureType capture_type) {
|
||||||
|
// A bug in the WGC API `CreateForMonitor` was fixed in 20H1.
|
||||||
|
if (capture_type == CaptureType::kScreen &&
|
||||||
|
rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_WIN10_20H1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ResolveCoreWinRTDelayload())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ComPtr<ABI::Windows::Foundation::Metadata::IApiInformationStatics>
|
||||||
|
api_info_statics;
|
||||||
|
HRESULT hr = GetActivationFactory<
|
||||||
|
ABI::Windows::Foundation::Metadata::IApiInformationStatics,
|
||||||
|
RuntimeClass_Windows_Foundation_Metadata_ApiInformation>(
|
||||||
|
&api_info_statics);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HSTRING api_contract;
|
||||||
|
hr = webrtc::CreateHstring(kApiContract, wcslen(kApiContract), &api_contract);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boolean is_api_present;
|
||||||
|
hr = api_info_statics->IsApiContractPresentByMajor(
|
||||||
|
api_contract, kRequiredApiContractVersion, &is_api_present);
|
||||||
|
webrtc::DeleteHstring(api_contract);
|
||||||
|
if (FAILED(hr) || !is_api_present)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HSTRING wgc_session_type;
|
||||||
|
hr = webrtc::CreateHstring(kWgcSessionType, wcslen(kWgcSessionType),
|
||||||
|
&wgc_session_type);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boolean is_type_present;
|
||||||
|
hr = api_info_statics->IsTypePresent(wgc_session_type, &is_type_present);
|
||||||
|
webrtc::DeleteHstring(wgc_session_type);
|
||||||
|
if (FAILED(hr) || !is_type_present)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ComPtr<WGC::IGraphicsCaptureSessionStatics> capture_session_statics;
|
||||||
|
hr = GetActivationFactory<
|
||||||
|
WGC::IGraphicsCaptureSessionStatics,
|
||||||
|
RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureSession>(
|
||||||
|
&capture_session_statics);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boolean is_supported;
|
||||||
|
hr = capture_session_statics->IsSupported(&is_supported);
|
||||||
|
if (FAILED(hr) || !is_supported)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
WgcCapturerWin::WgcCapturerWin(
|
WgcCapturerWin::WgcCapturerWin(
|
||||||
std::unique_ptr<WgcCaptureSourceFactory> source_factory,
|
std::unique_ptr<WgcCaptureSourceFactory> source_factory,
|
||||||
std::unique_ptr<SourceEnumerator> source_enumerator,
|
std::unique_ptr<SourceEnumerator> source_enumerator,
|
||||||
|
|||||||
@ -26,6 +26,9 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
// Checks if the WGC API is present and supported on the system.
|
||||||
|
bool IsWgcSupported(CaptureType capture_type);
|
||||||
|
|
||||||
// WgcCapturerWin is initialized with an implementation of this base class,
|
// WgcCapturerWin is initialized with an implementation of this base class,
|
||||||
// which it uses to find capturable sources of a particular type. This way,
|
// which it uses to find capturable sources of a particular type. This way,
|
||||||
// WgcCapturerWin can remain source-agnostic.
|
// WgcCapturerWin can remain source-agnostic.
|
||||||
|
|||||||
@ -67,23 +67,24 @@ const UINT kNoOp = WM_APP;
|
|||||||
const UINT kDestroyWindow = WM_APP + 1;
|
const UINT kDestroyWindow = WM_APP + 1;
|
||||||
const UINT kQuitRunning = WM_APP + 2;
|
const UINT kQuitRunning = WM_APP + 2;
|
||||||
|
|
||||||
enum CaptureType { kWindowCapture = 0, kScreenCapture = 1 };
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class WgcCapturerWinTest : public ::testing::TestWithParam<CaptureType>,
|
class WgcCapturerWinTest : public ::testing::TestWithParam<CaptureType>,
|
||||||
public DesktopCapturer::Callback {
|
public DesktopCapturer::Callback {
|
||||||
public:
|
public:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
if (rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_WIN10_RS5) {
|
|
||||||
RTC_LOG(LS_INFO)
|
|
||||||
<< "Skipping WgcCapturerWinTests on Windows versions < RS5.";
|
|
||||||
GTEST_SKIP();
|
|
||||||
}
|
|
||||||
|
|
||||||
com_initializer_ =
|
com_initializer_ =
|
||||||
std::make_unique<ScopedCOMInitializer>(ScopedCOMInitializer::kMTA);
|
std::make_unique<ScopedCOMInitializer>(ScopedCOMInitializer::kMTA);
|
||||||
EXPECT_TRUE(com_initializer_->Succeeded());
|
EXPECT_TRUE(com_initializer_->Succeeded());
|
||||||
|
|
||||||
|
// Most tests (except `CaptureAllMonitors`) avoid the bug in screen capture,
|
||||||
|
// so we check support for window capture so these tests can run on more
|
||||||
|
// systems.
|
||||||
|
if (!IsWgcSupported(CaptureType::kWindow)) {
|
||||||
|
RTC_LOG(LS_INFO)
|
||||||
|
<< "Skipping WgcCapturerWinTests on unsupported platforms.";
|
||||||
|
GTEST_SKIP();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetUpForWindowCapture(int window_width = kMediumWindowWidth,
|
void SetUpForWindowCapture(int window_width = kMediumWindowWidth,
|
||||||
@ -260,7 +261,7 @@ class WgcCapturerWinTest : public ::testing::TestWithParam<CaptureType>,
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(WgcCapturerWinTest, SelectValidSource) {
|
TEST_P(WgcCapturerWinTest, SelectValidSource) {
|
||||||
if (GetParam() == CaptureType::kWindowCapture) {
|
if (GetParam() == CaptureType::kWindow) {
|
||||||
SetUpForWindowCapture();
|
SetUpForWindowCapture();
|
||||||
} else {
|
} else {
|
||||||
SetUpForScreenCapture();
|
SetUpForScreenCapture();
|
||||||
@ -270,7 +271,7 @@ TEST_P(WgcCapturerWinTest, SelectValidSource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WgcCapturerWinTest, SelectInvalidSource) {
|
TEST_P(WgcCapturerWinTest, SelectInvalidSource) {
|
||||||
if (GetParam() == CaptureType::kWindowCapture) {
|
if (GetParam() == CaptureType::kWindow) {
|
||||||
capturer_ = WgcCapturerWin::CreateRawWindowCapturer(
|
capturer_ = WgcCapturerWin::CreateRawWindowCapturer(
|
||||||
DesktopCaptureOptions::CreateDefault());
|
DesktopCaptureOptions::CreateDefault());
|
||||||
source_id_ = kNullWindowId;
|
source_id_ = kNullWindowId;
|
||||||
@ -284,7 +285,7 @@ TEST_P(WgcCapturerWinTest, SelectInvalidSource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WgcCapturerWinTest, Capture) {
|
TEST_P(WgcCapturerWinTest, Capture) {
|
||||||
if (GetParam() == CaptureType::kWindowCapture) {
|
if (GetParam() == CaptureType::kWindow) {
|
||||||
SetUpForWindowCapture();
|
SetUpForWindowCapture();
|
||||||
} else {
|
} else {
|
||||||
SetUpForScreenCapture();
|
SetUpForScreenCapture();
|
||||||
@ -303,7 +304,7 @@ TEST_P(WgcCapturerWinTest, Capture) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WgcCapturerWinTest, CaptureTime) {
|
TEST_P(WgcCapturerWinTest, CaptureTime) {
|
||||||
if (GetParam() == CaptureType::kWindowCapture) {
|
if (GetParam() == CaptureType::kWindow) {
|
||||||
SetUpForWindowCapture();
|
SetUpForWindowCapture();
|
||||||
} else {
|
} else {
|
||||||
SetUpForScreenCapture();
|
SetUpForScreenCapture();
|
||||||
@ -331,8 +332,8 @@ TEST_P(WgcCapturerWinTest, CaptureTime) {
|
|||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(SourceAgnostic,
|
INSTANTIATE_TEST_SUITE_P(SourceAgnostic,
|
||||||
WgcCapturerWinTest,
|
WgcCapturerWinTest,
|
||||||
::testing::Values(CaptureType::kWindowCapture,
|
::testing::Values(CaptureType::kWindow,
|
||||||
CaptureType::kScreenCapture));
|
CaptureType::kScreen));
|
||||||
|
|
||||||
// Monitor specific tests.
|
// Monitor specific tests.
|
||||||
TEST_F(WgcCapturerWinTest, FocusOnMonitor) {
|
TEST_F(WgcCapturerWinTest, FocusOnMonitor) {
|
||||||
@ -344,6 +345,13 @@ TEST_F(WgcCapturerWinTest, FocusOnMonitor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgcCapturerWinTest, CaptureAllMonitors) {
|
TEST_F(WgcCapturerWinTest, CaptureAllMonitors) {
|
||||||
|
// Trying to capture all monitors causes a crash on Windows versions <20H1.
|
||||||
|
if (!IsWgcSupported(CaptureType::kScreen)) {
|
||||||
|
RTC_LOG(LS_INFO)
|
||||||
|
<< "Skipping CaptureAllMonitors test on unsupported platforms.";
|
||||||
|
GTEST_SKIP();
|
||||||
|
}
|
||||||
|
|
||||||
SetUpForScreenCapture();
|
SetUpForScreenCapture();
|
||||||
EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId));
|
EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId));
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user