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 {
|
||||
|
||||
enum class CaptureType { kWindow, kScreen };
|
||||
|
||||
// Type used to identify windows on the desktop. Values are platform-specific:
|
||||
// - On Windows: HWND 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(
|
||||
const DesktopCaptureOptions& options) {
|
||||
#if defined(RTC_ENABLE_WIN_WGC)
|
||||
if (options.allow_wgc_capturer() &&
|
||||
rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_RS5) {
|
||||
if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kWindow)) {
|
||||
return WgcCapturerWin::CreateRawWindowCapturer(options);
|
||||
}
|
||||
#endif // defined(RTC_ENABLE_WIN_WGC)
|
||||
@ -78,8 +77,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
|
||||
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
|
||||
const DesktopCaptureOptions& options) {
|
||||
#if defined(RTC_ENABLE_WIN_WGC)
|
||||
if (options.allow_wgc_capturer() &&
|
||||
rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_20H1) {
|
||||
if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kScreen)) {
|
||||
return WgcCapturerWin::CreateRawScreenCapturer(options);
|
||||
}
|
||||
#endif // defined(RTC_ENABLE_WIN_WGC)
|
||||
|
||||
@ -144,7 +144,7 @@ HRESULT WgcCaptureSession::StartCapture() {
|
||||
|
||||
ComPtr<WGC::IDirect3D11CaptureFramePoolStatics> frame_pool_statics;
|
||||
hr = GetActivationFactory<
|
||||
ABI::Windows::Graphics::Capture::IDirect3D11CaptureFramePoolStatics,
|
||||
WGC::IDirect3D11CaptureFramePoolStatics,
|
||||
RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool>(
|
||||
&frame_pool_statics);
|
||||
if (FAILED(hr)) {
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
#include "modules/desktop_capture/win/wgc_capturer_win.h"
|
||||
|
||||
#include <windows.foundation.metadata.h>
|
||||
#include <windows.graphics.capture.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "modules/desktop_capture/desktop_capture_metrics_helper.h"
|
||||
@ -17,6 +20,9 @@
|
||||
#include "modules/desktop_capture/win/wgc_desktop_frame.h"
|
||||
#include "rtc_base/logging.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"
|
||||
|
||||
namespace WGC = ABI::Windows::Graphics::Capture;
|
||||
@ -26,6 +32,11 @@ namespace webrtc {
|
||||
|
||||
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 {
|
||||
kSuccess = 0,
|
||||
kNoDirect3dDevice = 1,
|
||||
@ -45,6 +56,65 @@ void RecordWgcCapturerResult(WgcCapturerResult error) {
|
||||
|
||||
} // 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(
|
||||
std::unique_ptr<WgcCaptureSourceFactory> source_factory,
|
||||
std::unique_ptr<SourceEnumerator> source_enumerator,
|
||||
|
||||
@ -26,6 +26,9 @@
|
||||
|
||||
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,
|
||||
// which it uses to find capturable sources of a particular type. This way,
|
||||
// WgcCapturerWin can remain source-agnostic.
|
||||
|
||||
@ -67,23 +67,24 @@ const UINT kNoOp = WM_APP;
|
||||
const UINT kDestroyWindow = WM_APP + 1;
|
||||
const UINT kQuitRunning = WM_APP + 2;
|
||||
|
||||
enum CaptureType { kWindowCapture = 0, kScreenCapture = 1 };
|
||||
|
||||
} // namespace
|
||||
|
||||
class WgcCapturerWinTest : public ::testing::TestWithParam<CaptureType>,
|
||||
public DesktopCapturer::Callback {
|
||||
public:
|
||||
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_ =
|
||||
std::make_unique<ScopedCOMInitializer>(ScopedCOMInitializer::kMTA);
|
||||
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,
|
||||
@ -260,7 +261,7 @@ class WgcCapturerWinTest : public ::testing::TestWithParam<CaptureType>,
|
||||
};
|
||||
|
||||
TEST_P(WgcCapturerWinTest, SelectValidSource) {
|
||||
if (GetParam() == CaptureType::kWindowCapture) {
|
||||
if (GetParam() == CaptureType::kWindow) {
|
||||
SetUpForWindowCapture();
|
||||
} else {
|
||||
SetUpForScreenCapture();
|
||||
@ -270,7 +271,7 @@ TEST_P(WgcCapturerWinTest, SelectValidSource) {
|
||||
}
|
||||
|
||||
TEST_P(WgcCapturerWinTest, SelectInvalidSource) {
|
||||
if (GetParam() == CaptureType::kWindowCapture) {
|
||||
if (GetParam() == CaptureType::kWindow) {
|
||||
capturer_ = WgcCapturerWin::CreateRawWindowCapturer(
|
||||
DesktopCaptureOptions::CreateDefault());
|
||||
source_id_ = kNullWindowId;
|
||||
@ -284,7 +285,7 @@ TEST_P(WgcCapturerWinTest, SelectInvalidSource) {
|
||||
}
|
||||
|
||||
TEST_P(WgcCapturerWinTest, Capture) {
|
||||
if (GetParam() == CaptureType::kWindowCapture) {
|
||||
if (GetParam() == CaptureType::kWindow) {
|
||||
SetUpForWindowCapture();
|
||||
} else {
|
||||
SetUpForScreenCapture();
|
||||
@ -303,7 +304,7 @@ TEST_P(WgcCapturerWinTest, Capture) {
|
||||
}
|
||||
|
||||
TEST_P(WgcCapturerWinTest, CaptureTime) {
|
||||
if (GetParam() == CaptureType::kWindowCapture) {
|
||||
if (GetParam() == CaptureType::kWindow) {
|
||||
SetUpForWindowCapture();
|
||||
} else {
|
||||
SetUpForScreenCapture();
|
||||
@ -331,8 +332,8 @@ TEST_P(WgcCapturerWinTest, CaptureTime) {
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(SourceAgnostic,
|
||||
WgcCapturerWinTest,
|
||||
::testing::Values(CaptureType::kWindowCapture,
|
||||
CaptureType::kScreenCapture));
|
||||
::testing::Values(CaptureType::kWindow,
|
||||
CaptureType::kScreen));
|
||||
|
||||
// Monitor specific tests.
|
||||
TEST_F(WgcCapturerWinTest, FocusOnMonitor) {
|
||||
@ -344,6 +345,13 @@ TEST_F(WgcCapturerWinTest, FocusOnMonitor) {
|
||||
}
|
||||
|
||||
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();
|
||||
EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId));
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user