Reland "Begin implementing WGC CaptureFrame"

This reverts commit 61709a3233174618d5ab46e1ee5847e4b150c7ef.

Reason for revert: Some downstream projects have issues building this
change due to the inclusion of the <windows.graphics.capture.h> header
which is newly available in the Win 10 SDK v10.0.19041.

To get around this issue for now, this change adds an off-by-default
build flag for these files. However, in the future we will want to
toggle this flag on, and the downstream projects will either need to
update their SDK versions or toggle this flag in their WebRTC clone.

Original change's description:
> Revert "Begin implementing WGC CaptureFrame"
>
> This reverts commit e820cef5340610b9beebbcb63868743b95b97fcd.
>
> Reason for revert: Breaks downstream client. I will investigate and
> get back with a suggestion to fix.
>
> Original change's description:
> > Begin implementing WGC CaptureFrame
> >
> > This change introduces the design that will allow us to deliver frames
> > synchronously to callers despite the Windows.Graphics.Capture APIs being
> > inherently asynchronous.
> >
> > We achieve this by having WindowCapturerWinWgc create and maintain a
> > WgcCaptureSession object for each window that it is asked to capture a
> > frame for. The capture session object will be the class that actually
> > uses the WGC APIs, and it will store the frames it receives in a frame
> > pool and deliver them via GetMostRecentFrame.
> >
> > The next CL will add the necessary functionality to the
> > WgcCaptureSession class.
> >
> > Bug: webrtc:9273
> > Change-Id: I44e164f4874503d8ccc8e6a210e74f9c8458f6c4
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/184220
> > Commit-Queue: Austin Orion <auorion@microsoft.com>
> > Reviewed-by: Tommi <tommi@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#32240}
>
> TBR=mbonadei@webrtc.org,jamiewalch@chromium.org,tommi@webrtc.org,auorion@microsoft.com
>
> Change-Id: I114944357ce5be7d1e2da817703dc95d544aa99a
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: webrtc:9273
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186045
> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#32248}

Bug: webrtc:9273
Change-Id: I9644fbf8f1fd1a84cb716176b8f14e3683a3f7cb
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186423
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32286}
This commit is contained in:
Austin Orion 2020-10-01 13:47:54 -07:00 committed by Commit Bot
parent 5b5abd7910
commit 25b0dee820
11 changed files with 237 additions and 20 deletions

View File

@ -482,8 +482,6 @@ rtc_library("desktop_capture_generic") {
"win/window_capture_utils.h",
"win/window_capturer_win_gdi.cc",
"win/window_capturer_win_gdi.h",
"win/window_capturer_win_wgc.cc",
"win/window_capturer_win_wgc.h",
"window_capturer_win.cc",
"window_finder_win.cc",
"window_finder_win.h",
@ -535,6 +533,17 @@ rtc_library("desktop_capture_generic") {
deps += [ ":pipewire_stubs" ]
}
}
if (rtc_enable_win_wgc) {
sources += [
"win/wgc_capture_session.cc",
"win/wgc_capture_session.h",
"win/window_capturer_win_wgc.cc",
"win/window_capturer_win_wgc.h",
]
defines += [ "RTC_ENABLE_WIN_WGC" ]
}
}
if (use_desktop_capture_differ_sse2) {

View File

@ -20,6 +20,13 @@
#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer_differ_wrapper.h"
#if defined(RTC_ENABLE_WIN_WGC)
#include "modules/desktop_capture/win/window_capturer_win_wgc.h"
#include "rtc_base/win/windows_version.h"
const bool kUseWinWgcCapturer = false;
#endif // defined(RTC_ENABLE_WIN_WGC)
namespace webrtc {
DesktopCapturer::~DesktopCapturer() = default;
@ -48,6 +55,16 @@ bool DesktopCapturer::IsOccluded(const DesktopVector& pos) {
// static
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
const DesktopCaptureOptions& options) {
#if defined(RTC_ENABLE_WIN_WGC)
// TODO(bugs.webrtc.org/11760): Add a WebRTC field trial (or similar
// mechanism) check here that leads to use of the WGC capturer once it is
// fully implemented.
if (kUseWinWgcCapturer &&
rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_RS5) {
return WindowCapturerWinWgc::CreateRawWindowCapturer(options);
}
#endif // defined(RTC_ENABLE_WIN_WGC)
#if defined(WEBRTC_WIN)
if (options.allow_cropping_window_capturer()) {
return CroppingWindowCapturer::CreateCapturer(options);

View File

@ -29,7 +29,7 @@ const float kStandardDPI = 96.0f;
// DesktopFrame represents a video frame captured from the screen.
class RTC_EXPORT DesktopFrame {
public:
// DesktopFrame objects always hold RGBA data.
// DesktopFrame objects always hold BGRA data.
static const int kBytesPerPixel = 4;
virtual ~DesktopFrame();

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 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 "modules/desktop_capture/win/wgc_capture_session.h"
#include <utility>
#include "rtc_base/checks.h"
using Microsoft::WRL::ComPtr;
namespace webrtc {
WgcCaptureSession::WgcCaptureSession(ComPtr<ID3D11Device> d3d11_device,
HWND window)
: d3d11_device_(std::move(d3d11_device)), window_(window) {}
WgcCaptureSession::~WgcCaptureSession() = default;
HRESULT WgcCaptureSession::StartCapture() {
RTC_DCHECK(!is_capture_started_);
RTC_DCHECK(d3d11_device_);
RTC_DCHECK(window_);
return E_NOTIMPL;
}
HRESULT WgcCaptureSession::GetMostRecentFrame(
std::unique_ptr<DesktopFrame>* output_frame) {
RTC_DCHECK(is_capture_started_);
return E_NOTIMPL;
}
} // namespace webrtc

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020 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 MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SESSION_H_
#define MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SESSION_H_
#include <Windows.Graphics.Capture.h>
#include <d3d11.h>
#include <wrl/client.h>
#include <memory>
#include "modules/desktop_capture/desktop_frame.h"
namespace webrtc {
class WgcCaptureSession final {
public:
WgcCaptureSession(Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
HWND window);
// Disallow copy and assign
WgcCaptureSession(const WgcCaptureSession&) = delete;
WgcCaptureSession& operator=(const WgcCaptureSession&) = delete;
~WgcCaptureSession();
HRESULT StartCapture();
HRESULT GetMostRecentFrame(std::unique_ptr<DesktopFrame>* output_frame);
bool IsCaptureStarted() const { return is_capture_started_; }
private:
// A Direct3D11 Device provided by the caller. We use this to create an
// IDirect3DDevice, and also to create textures that will hold the image data.
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
HWND window_;
bool is_capture_started_ = false;
};
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SESSION_H_

View File

@ -10,9 +10,9 @@
#include "modules/desktop_capture/win/window_capturer_win_wgc.h"
#include <memory>
#include <utility>
#include "modules/desktop_capture/desktop_capturer.h"
#include "rtc_base/logging.h"
namespace webrtc {
@ -37,12 +37,95 @@ void WindowCapturerWinWgc::Start(Callback* callback) {
RTC_DCHECK(callback);
callback_ = callback;
// Create a Direct3D11 device to share amongst the WgcCaptureSessions. Many
// parameters are nullptr as the implemention uses defaults that work well for
// us.
HRESULT hr = D3D11CreateDevice(
/*adapter=*/nullptr, D3D_DRIVER_TYPE_HARDWARE,
/*software_rasterizer=*/nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
/*feature_levels=*/nullptr, /*feature_levels_size=*/0, D3D11_SDK_VERSION,
&d3d11_device_, /*feature_level=*/nullptr, /*device_context=*/nullptr);
if (hr == DXGI_ERROR_UNSUPPORTED) {
// If a hardware device could not be created, use WARP which is a high speed
// software device.
hr = D3D11CreateDevice(
/*adapter=*/nullptr, D3D_DRIVER_TYPE_WARP,
/*software_rasterizer=*/nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
/*feature_levels=*/nullptr, /*feature_levels_size=*/0,
D3D11_SDK_VERSION, &d3d11_device_, /*feature_level=*/nullptr,
/*device_context=*/nullptr);
}
if (FAILED(hr)) {
RTC_LOG(LS_ERROR) << "Failed to create D3D11Device: " << hr;
}
}
void WindowCapturerWinWgc::CaptureFrame() {
RTC_DCHECK(callback_);
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
if (!window_) {
RTC_LOG(LS_ERROR) << "Window hasn't been selected";
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,
/*frame=*/nullptr);
return;
}
if (!d3d11_device_) {
RTC_LOG(LS_ERROR) << "No D3D11D3evice, cannot capture.";
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,
/*frame=*/nullptr);
return;
}
WgcCaptureSession* capture_session = nullptr;
auto iter = ongoing_captures_.find(window_);
if (iter == ongoing_captures_.end()) {
auto iter_success_pair = ongoing_captures_.emplace(
std::piecewise_construct, std::forward_as_tuple(window_),
std::forward_as_tuple(d3d11_device_, window_));
if (iter_success_pair.second) {
capture_session = &iter_success_pair.first->second;
} else {
RTC_LOG(LS_ERROR) << "Failed to create new WgcCaptureSession.";
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,
/*frame=*/nullptr);
return;
}
} else {
capture_session = &iter->second;
}
HRESULT hr;
if (!capture_session->IsCaptureStarted()) {
hr = capture_session->StartCapture();
if (FAILED(hr)) {
RTC_LOG(LS_ERROR) << "Failed to start capture: " << hr;
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,
/*frame=*/nullptr);
return;
}
}
std::unique_ptr<DesktopFrame> frame;
hr = capture_session->GetMostRecentFrame(&frame);
if (FAILED(hr)) {
RTC_LOG(LS_ERROR) << "GetMostRecentFrame failed: " << hr;
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,
/*frame=*/nullptr);
return;
}
if (!frame) {
RTC_LOG(LS_WARNING) << "GetMostRecentFrame returned an empty frame.";
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_TEMPORARY,
/*frame=*/nullptr);
return;
}
callback_->OnCaptureResult(DesktopCapturer::Result::SUCCESS,
std::move(frame));
}
// static

View File

@ -11,19 +11,22 @@
#ifndef MODULES_DESKTOP_CAPTURE_WIN_WINDOW_CAPTURER_WIN_WGC_H_
#define MODULES_DESKTOP_CAPTURE_WIN_WINDOW_CAPTURER_WIN_WGC_H_
#include <d3d11.h>
#include <wrl/client.h>
#include <map>
#include <memory>
#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "modules/desktop_capture/win/wgc_capture_session.h"
#include "modules/desktop_capture/win/window_capture_utils.h"
namespace webrtc {
class WindowCapturerWinWgc : public DesktopCapturer {
class WindowCapturerWinWgc final : public DesktopCapturer {
public:
WindowCapturerWinWgc();
// Disallow copy and assign
WindowCapturerWinWgc(const WindowCapturerWinWgc&) = delete;
WindowCapturerWinWgc& operator=(const WindowCapturerWinWgc&) = delete;
@ -39,12 +42,26 @@ class WindowCapturerWinWgc : public DesktopCapturer {
bool SelectSource(SourceId id) override;
private:
// The callback that we deliver frames to, synchronously, before CaptureFrame
// returns.
Callback* callback_ = nullptr;
// HWND for the currently selected window or nullptr if window is not
// selected.
// HWND for the currently selected window or nullptr if a window is not
// selected. We may be capturing many other windows, but this is the window
// that we will return a frame for when CaptureFrame is called.
HWND window_ = nullptr;
// This helps us enumerate the list of windows that we can capture.
WindowCaptureHelperWin window_capture_helper_;
// A Direct3D11 device that is shared amongst the WgcCaptureSessions, who
// require one to perform the capture.
Microsoft::WRL::ComPtr<::ID3D11Device> d3d11_device_;
// A map of all the windows we are capturing and the associated
// WgcCaptureSession. This is where we will get the frames for the window
// from, when requested.
std::map<HWND, WgcCaptureSession> ongoing_captures_;
};
} // namespace webrtc

View File

@ -11,21 +11,13 @@
#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "modules/desktop_capture/win/window_capturer_win_gdi.h"
#include "modules/desktop_capture/win/window_capturer_win_wgc.h"
namespace webrtc {
// static
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
const DesktopCaptureOptions& options) {
// TODO(bugs.webrtc.org/11760): Add a WebRTC field trial (or similar
// mechanism) and Windows version check here that leads to use of the WGC
// capturer once it is fully implemented.
if (true) {
return WindowCapturerWinGdi::CreateRawWindowCapturer(options);
} else {
return WindowCapturerWinWgc::CreateRawWindowCapturer(options);
}
return WindowCapturerWinGdi::CreateRawWindowCapturer(options);
}
} // namespace webrtc

View File

@ -203,8 +203,12 @@ Version MajorMinorBuildToVersion(int major, int minor, int build) {
return VERSION_WIN10_RS2;
} else if (build < 17134) {
return VERSION_WIN10_RS3;
} else {
} else if (build < 17763) {
return VERSION_WIN10_RS4;
} else if (build < 18362) {
return VERSION_WIN10_RS5;
} else {
return VERSION_WIN10_19H1;
}
} else if (major > 6) {
RTC_NOTREACHED();

View File

@ -43,6 +43,8 @@ enum Version {
VERSION_WIN10_RS2 = 10, // Redstone 2: Version 1703, Build 15063.
VERSION_WIN10_RS3 = 11, // Redstone 3: Version 1709, Build 16299.
VERSION_WIN10_RS4 = 12, // Redstone 4: Version 1803, Build 17134.
VERSION_WIN10_RS5 = 13, // Redstone 5: Version 1809, Build 17763.
VERSION_WIN10_19H1 = 14, // 19H1: Version 1903, Build 18362.
// On edit, update tools\metrics\histograms\enums.xml "WindowsVersion" and
// "GpuBlacklistFeatureTestResultsWindows2".
VERSION_WIN_LAST, // Indicates error condition.

View File

@ -195,6 +195,11 @@ declare_args() {
# doesn't assume /DUNICODE and /D_UNICODE but that it explicitly uses
# wide character functions.
rtc_win_undef_unicode = false
# When set to true, a capturer implementation that uses the
# Windows.Graphics.Capture APIs will be available for use. These APIs are
# available in the Win 10 SDK v10.0.19041.
rtc_enable_win_wgc = false
}
if (!build_with_mozilla) {