[DesktopCapture] Detect screen resolution changes in DirectX capturer
This change adds a ResolutionChangeDetector to help dxgi components, say DxgiDuplicatorController and DxgiTexture to detect resolution changes. BUG=684162 Review-Url: https://codereview.webrtc.org/2682913002 Cr-Commit-Position: refs/heads/master@{#16654}
This commit is contained in:
parent
94b9600e2e
commit
5fea5fb183
@ -200,6 +200,8 @@ rtc_static_library("desktop_capture") {
|
||||
"mouse_cursor_monitor.h",
|
||||
"mouse_cursor_monitor_mac.mm",
|
||||
"mouse_cursor_monitor_win.cc",
|
||||
"resolution_change_detector.cc",
|
||||
"resolution_change_detector.h",
|
||||
"screen_capture_frame_queue.h",
|
||||
"screen_capturer_helper.cc",
|
||||
"screen_capturer_helper.h",
|
||||
|
||||
29
webrtc/modules/desktop_capture/resolution_change_detector.cc
Normal file
29
webrtc/modules/desktop_capture/resolution_change_detector.cc
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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/resolution_change_detector.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
bool ResolutionChangeDetector::IsChanged(DesktopSize size) {
|
||||
if (!initialized_) {
|
||||
initialized_ = true;
|
||||
last_size_ = size;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !last_size_.equals(size);
|
||||
}
|
||||
|
||||
void ResolutionChangeDetector::Reset() {
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
30
webrtc/modules/desktop_capture/resolution_change_detector.h
Normal file
30
webrtc/modules/desktop_capture/resolution_change_detector.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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_RESOLUTION_CHANGE_DETECTOR_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_RESOLUTION_CHANGE_DETECTOR_H_
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class ResolutionChangeDetector {
|
||||
public:
|
||||
bool IsChanged(DesktopSize size);
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
DesktopSize last_size_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_RESOLUTION_CHANGE_DETECTOR_H_
|
||||
@ -13,17 +13,24 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
|
||||
#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
DxgiDuplicatorController::Context::Context() {}
|
||||
DxgiDuplicatorController::Context::Context() = default;
|
||||
|
||||
DxgiDuplicatorController::Context::~Context() {
|
||||
DxgiDuplicatorController::Instance()->Unregister(this);
|
||||
}
|
||||
|
||||
void DxgiDuplicatorController::Context::Reset() {
|
||||
identity_ = 0;
|
||||
}
|
||||
|
||||
// static
|
||||
DxgiDuplicatorController* DxgiDuplicatorController::Instance() {
|
||||
// The static instance won't be deleted to ensure it can be used by other
|
||||
@ -44,6 +51,11 @@ bool DxgiDuplicatorController::IsSupported() {
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
void DxgiDuplicatorController::Reset() {
|
||||
rtc::CritScope lock(&lock_);
|
||||
Deinitialize();
|
||||
}
|
||||
|
||||
bool DxgiDuplicatorController::RetrieveD3dInfo(D3dInfo* info) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
if (!Initialize()) {
|
||||
@ -182,6 +194,7 @@ bool DxgiDuplicatorController::DoInitialize() {
|
||||
void DxgiDuplicatorController::Deinitialize() {
|
||||
desktop_rect_ = DesktopRect();
|
||||
duplicators_.clear();
|
||||
resolution_change_detector_.Reset();
|
||||
}
|
||||
|
||||
bool DxgiDuplicatorController::ContextExpired(
|
||||
@ -219,17 +232,34 @@ bool DxgiDuplicatorController::DoDuplicate(Context* context,
|
||||
RTC_DCHECK(target);
|
||||
target->mutable_updated_region()->Clear();
|
||||
rtc::CritScope lock(&lock_);
|
||||
if (DoDuplicateUnlocked(context, monitor_id, target)) {
|
||||
return true;
|
||||
}
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
|
||||
int monitor_id,
|
||||
SharedDesktopFrame* target) {
|
||||
if (!Initialize()) {
|
||||
// Cannot initialize COM components now, display mode may be changing.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resolution_change_detector_.IsChanged(
|
||||
GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) {
|
||||
// Resolution of entire screen has been changed, which usually means a new
|
||||
// monitor has been attached or one has been removed. The simplest way is to
|
||||
// Deinitialize() and returns false to indicate downstream components.
|
||||
return false;
|
||||
}
|
||||
|
||||
Setup(context);
|
||||
if (monitor_id < 0) {
|
||||
// Capture entire screen.
|
||||
for (size_t i = 0; i < duplicators_.size(); i++) {
|
||||
if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) {
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -248,7 +278,6 @@ bool DxgiDuplicatorController::DoDuplicate(Context* context,
|
||||
target->set_dpi(dpi());
|
||||
return true;
|
||||
}
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.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/dxgi_adapter_duplicator.h"
|
||||
@ -47,6 +48,9 @@ class DxgiDuplicatorController {
|
||||
// destructing.
|
||||
~Context();
|
||||
|
||||
// Reset current Context, so it will be reinitialized next time.
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
friend class DxgiDuplicatorController;
|
||||
|
||||
@ -87,6 +91,11 @@ class DxgiDuplicatorController {
|
||||
// Detects whether the system supports DXGI based capturer.
|
||||
bool IsSupported();
|
||||
|
||||
// Calls Deinitialize() function with lock. Consumers can call this function
|
||||
// to force the DxgiDuplicatorController to be reinitialized to avoid an
|
||||
// expected failure in next Duplicate() call.
|
||||
void Reset();
|
||||
|
||||
// Returns a copy of D3dInfo composed by last Initialize() function call.
|
||||
bool RetrieveD3dInfo(D3dInfo* info);
|
||||
|
||||
@ -167,6 +176,10 @@ class DxgiDuplicatorController {
|
||||
int monitor_id,
|
||||
SharedDesktopFrame* target);
|
||||
|
||||
bool DoDuplicateUnlocked(Context* context,
|
||||
int monitor_id,
|
||||
SharedDesktopFrame* target);
|
||||
|
||||
// This lock must be locked whenever accessing any of the following objects.
|
||||
rtc::CriticalSection lock_;
|
||||
|
||||
@ -177,6 +190,7 @@ class DxgiDuplicatorController {
|
||||
DesktopVector dpi_;
|
||||
std::vector<DxgiAdapterDuplicator> duplicators_;
|
||||
D3dInfo d3d_info_;
|
||||
ResolutionChangeDetector resolution_change_detector_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -85,13 +85,10 @@ DxgiOutputDuplicator::~DxgiOutputDuplicator() {
|
||||
|
||||
bool DxgiOutputDuplicator::Initialize() {
|
||||
if (DuplicateOutput()) {
|
||||
DesktopSize unrotated_size =
|
||||
RotateSize(desktop_rect().size(), ReverseRotation(rotation_));
|
||||
if (desc_.DesktopImageInSystemMemory) {
|
||||
texture_.reset(
|
||||
new DxgiTextureMapping(unrotated_size, duplication_.Get()));
|
||||
texture_.reset(new DxgiTextureMapping(duplication_.Get()));
|
||||
} else {
|
||||
texture_.reset(new DxgiTextureStaging(unrotated_size, device_));
|
||||
texture_.reset(new DxgiTextureStaging(device_));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@ -10,7 +10,15 @@
|
||||
|
||||
#include "webrtc/modules/desktop_capture/win/dxgi_texture.h"
|
||||
|
||||
#include <comdef.h>
|
||||
#include <wrl/client.h>
|
||||
#include <D3D11.h>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
#include "webrtc/system_wrappers/include/logging.h"
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -29,10 +37,33 @@ class DxgiDesktopFrame : public DesktopFrame {
|
||||
|
||||
} // namespace
|
||||
|
||||
DxgiTexture::DxgiTexture(const DesktopSize& desktop_size)
|
||||
: desktop_size_(desktop_size) {}
|
||||
DxgiTexture::DxgiTexture() = default;
|
||||
DxgiTexture::~DxgiTexture() = default;
|
||||
|
||||
DxgiTexture::~DxgiTexture() {}
|
||||
bool DxgiTexture::CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource) {
|
||||
RTC_DCHECK(resource && frame_info.AccumulatedFrames > 0);
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
_com_error error = resource->QueryInterface(
|
||||
__uuidof(ID3D11Texture2D),
|
||||
reinterpret_cast<void**>(texture.GetAddressOf()));
|
||||
if (error.Error() != S_OK || !texture) {
|
||||
LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, "
|
||||
"error "
|
||||
<< error.ErrorMessage() << ", code " << error.Error();
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {0};
|
||||
texture->GetDesc(&desc);
|
||||
desktop_size_.set(desc.Width, desc.Height);
|
||||
if (resolution_change_detector_.IsChanged(desktop_size_)) {
|
||||
LOG(LS_ERROR) << "Texture size is not consistent with current DxgiTexture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return CopyFromTexture(frame_info, texture.Get());
|
||||
}
|
||||
|
||||
const DesktopFrame& DxgiTexture::AsDesktopFrame() {
|
||||
if (!frame_) {
|
||||
@ -46,4 +77,8 @@ bool DxgiTexture::Release() {
|
||||
return DoRelease();
|
||||
}
|
||||
|
||||
DXGI_MAPPED_RECT* DxgiTexture::rect() {
|
||||
return &rect_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -11,12 +11,14 @@
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_TEXTURE_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_TEXTURE_H_
|
||||
|
||||
#include <D3D11.h>
|
||||
#include <DXGI1_2.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
#include "webrtc/modules/desktop_capture/resolution_change_detector.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -27,14 +29,14 @@ class DxgiTexture {
|
||||
public:
|
||||
// Creates a DxgiTexture instance, which represents the |desktop_size| area of
|
||||
// entire screen -- usually a monitor on the system.
|
||||
explicit DxgiTexture(const DesktopSize& desktop_size);
|
||||
DxgiTexture();
|
||||
|
||||
virtual ~DxgiTexture();
|
||||
|
||||
// Copies selected regions of a frame represented by frame_info and resource.
|
||||
// Returns false if anything wrong.
|
||||
virtual bool CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource) = 0;
|
||||
bool CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource);
|
||||
|
||||
const DesktopSize& desktop_size() const { return desktop_size_; }
|
||||
|
||||
@ -54,13 +56,18 @@ class DxgiTexture {
|
||||
const DesktopFrame& AsDesktopFrame();
|
||||
|
||||
protected:
|
||||
DXGI_MAPPED_RECT rect_ = {0};
|
||||
DXGI_MAPPED_RECT* rect();
|
||||
|
||||
virtual bool CopyFromTexture(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
ID3D11Texture2D* texture) = 0;
|
||||
|
||||
private:
|
||||
virtual bool DoRelease() = 0;
|
||||
|
||||
const DesktopSize desktop_size_;
|
||||
private:
|
||||
DXGI_MAPPED_RECT rect_ = {0};
|
||||
DesktopSize desktop_size_;
|
||||
std::unique_ptr<DesktopFrame> frame_;
|
||||
ResolutionChangeDetector resolution_change_detector_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -19,21 +19,21 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
DxgiTextureMapping::DxgiTextureMapping(const DesktopSize& desktop_size,
|
||||
IDXGIOutputDuplication* duplication)
|
||||
: DxgiTexture(desktop_size), duplication_(duplication) {
|
||||
DxgiTextureMapping::DxgiTextureMapping(IDXGIOutputDuplication* duplication)
|
||||
: duplication_(duplication) {
|
||||
RTC_DCHECK(duplication_);
|
||||
}
|
||||
|
||||
DxgiTextureMapping::~DxgiTextureMapping() = default;
|
||||
|
||||
bool DxgiTextureMapping::CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource) {
|
||||
RTC_DCHECK(resource && frame_info.AccumulatedFrames > 0);
|
||||
rect_ = {0};
|
||||
_com_error error = duplication_->MapDesktopSurface(&rect_);
|
||||
bool DxgiTextureMapping::CopyFromTexture(
|
||||
const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
ID3D11Texture2D* texture) {
|
||||
RTC_DCHECK(texture && frame_info.AccumulatedFrames > 0);
|
||||
*rect() = {0};
|
||||
_com_error error = duplication_->MapDesktopSurface(rect());
|
||||
if (error.Error() != S_OK) {
|
||||
rect_ = {0};
|
||||
*rect() = {0};
|
||||
LOG(LS_ERROR) << "Failed to map the IDXGIOutputDuplication to a bitmap, "
|
||||
"error "
|
||||
<< error.ErrorMessage() << ", code " << error.Error();
|
||||
|
||||
@ -27,14 +27,14 @@ namespace webrtc {
|
||||
class DxgiTextureMapping : public DxgiTexture {
|
||||
public:
|
||||
// Creates a DxgiTextureMapping instance. Caller must maintain the lifetime
|
||||
// of input duplication to make sure it outlives this instance.
|
||||
DxgiTextureMapping(const DesktopSize& desktop_size,
|
||||
IDXGIOutputDuplication* duplication);
|
||||
// of input |duplication| to make sure it outlives this instance.
|
||||
explicit DxgiTextureMapping(IDXGIOutputDuplication* duplication);
|
||||
|
||||
~DxgiTextureMapping() override;
|
||||
|
||||
bool CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource) override;
|
||||
protected:
|
||||
bool CopyFromTexture(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
ID3D11Texture2D* texture) override;
|
||||
|
||||
bool DoRelease() override;
|
||||
|
||||
|
||||
@ -22,9 +22,8 @@ using Microsoft::WRL::ComPtr;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
DxgiTextureStaging::DxgiTextureStaging(const DesktopSize& desktop_size,
|
||||
const D3dDevice& device)
|
||||
: DxgiTexture(desktop_size), device_(device) {}
|
||||
DxgiTextureStaging::DxgiTextureStaging(const D3dDevice& device)
|
||||
: device_(device) {}
|
||||
|
||||
DxgiTextureStaging::~DxgiTextureStaging() = default;
|
||||
|
||||
@ -32,11 +31,6 @@ bool DxgiTextureStaging::InitializeStage(ID3D11Texture2D* texture) {
|
||||
RTC_DCHECK(texture);
|
||||
D3D11_TEXTURE2D_DESC desc = {0};
|
||||
texture->GetDesc(&desc);
|
||||
if (static_cast<int>(desc.Width) != desktop_size().width() ||
|
||||
static_cast<int>(desc.Height) != desktop_size().height()) {
|
||||
LOG(LS_ERROR) << "Texture size is not consistent with current DxgiTexture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
desc.ArraySize = 1;
|
||||
desc.BindFlags = 0;
|
||||
@ -90,33 +84,24 @@ void DxgiTextureStaging::AssertStageAndSurfaceAreSameObject() {
|
||||
RTC_DCHECK(left.Get() == right.Get());
|
||||
}
|
||||
|
||||
bool DxgiTextureStaging::CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource) {
|
||||
RTC_DCHECK(resource && frame_info.AccumulatedFrames > 0);
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
_com_error error = resource->QueryInterface(
|
||||
__uuidof(ID3D11Texture2D),
|
||||
reinterpret_cast<void**>(texture.GetAddressOf()));
|
||||
if (error.Error() != S_OK || !texture) {
|
||||
LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, "
|
||||
"error "
|
||||
<< error.ErrorMessage() << ", code " << error.Error();
|
||||
return false;
|
||||
}
|
||||
bool DxgiTextureStaging::CopyFromTexture(
|
||||
const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
ID3D11Texture2D* texture) {
|
||||
RTC_DCHECK(texture && frame_info.AccumulatedFrames > 0);
|
||||
|
||||
// AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to
|
||||
// copy it to a CPU accessible staging ID3D11Texture2D.
|
||||
if (!InitializeStage(texture.Get())) {
|
||||
if (!InitializeStage(texture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
device_.context()->CopyResource(static_cast<ID3D11Resource*>(stage_.Get()),
|
||||
static_cast<ID3D11Resource*>(texture.Get()));
|
||||
static_cast<ID3D11Resource*>(texture));
|
||||
|
||||
rect_ = {0};
|
||||
error = surface_->Map(&rect_, DXGI_MAP_READ);
|
||||
*rect() = {0};
|
||||
_com_error error = surface_->Map(rect(), DXGI_MAP_READ);
|
||||
if (error.Error() != S_OK) {
|
||||
rect_ = {0};
|
||||
*rect() = {0};
|
||||
LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error "
|
||||
<< error.ErrorMessage() << ", code " << error.Error();
|
||||
return false;
|
||||
|
||||
@ -33,14 +33,15 @@ class DxgiTextureStaging : public DxgiTexture {
|
||||
public:
|
||||
// Creates a DxgiTextureStaging instance. Caller must maintain the lifetime
|
||||
// of input device to make sure it outlives this instance.
|
||||
DxgiTextureStaging(const DesktopSize& desktop_size, const D3dDevice& device);
|
||||
explicit DxgiTextureStaging(const D3dDevice& device);
|
||||
|
||||
~DxgiTextureStaging() override;
|
||||
|
||||
// Copies selected regions of a frame represented by frame_info and resource.
|
||||
protected:
|
||||
// Copies selected regions of a frame represented by frame_info and texture.
|
||||
// Returns false if anything wrong.
|
||||
bool CopyFrom(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
IDXGIResource* resource) override;
|
||||
bool CopyFromTexture(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||
ID3D11Texture2D* texture) override;
|
||||
|
||||
bool DoRelease() override;
|
||||
|
||||
|
||||
@ -10,12 +10,14 @@
|
||||
|
||||
#include "webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -66,6 +68,26 @@ void ScreenCapturerWinDirectx::CaptureFrame() {
|
||||
|
||||
int64_t capture_start_time_nanos = rtc::TimeNanos();
|
||||
|
||||
// The dxgi components and APIs do not update the screen resolution without
|
||||
// a reinitialization. So we use the GetDC() function to retrieve the screen
|
||||
// resolution to decide whether dxgi components need to be reinitialized.
|
||||
// If the screen resolution changed, it's very likely the next Duplicate()
|
||||
// function call will fail because of a missing monitor or the frame size is
|
||||
// not enough to store the output. So we reinitialize dxgi components in-place
|
||||
// to avoid a capture failure.
|
||||
// But there is no guarantee GetDC() function returns the same resolution as
|
||||
// dxgi APIs, we still rely on dxgi components to return the output frame
|
||||
// size.
|
||||
// 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())) {
|
||||
frames_.Reset();
|
||||
DxgiDuplicatorController::Instance()->Reset();
|
||||
resolution_change_detector_.Reset();
|
||||
}
|
||||
|
||||
frames_.MoveToNextFrame();
|
||||
if (!frames_.current_frame()) {
|
||||
std::unique_ptr<DesktopFrame> new_frame;
|
||||
@ -90,6 +112,7 @@ void ScreenCapturerWinDirectx::CaptureFrame() {
|
||||
&context_, frames_.current_frame())) {
|
||||
// Screen size may be changed, so we need to reset the frames.
|
||||
frames_.Reset();
|
||||
resolution_change_detector_.Reset();
|
||||
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||
return;
|
||||
}
|
||||
@ -98,6 +121,7 @@ void ScreenCapturerWinDirectx::CaptureFrame() {
|
||||
&context_, current_screen_id_, frames_.current_frame())) {
|
||||
// Screen size may be changed, so we need to reset the frames.
|
||||
frames_.Reset();
|
||||
resolution_change_detector_.Reset();
|
||||
if (current_screen_id_ >=
|
||||
DxgiDuplicatorController::Instance()->ScreenCount()) {
|
||||
// Current monitor has been removed from the system.
|
||||
@ -133,12 +157,14 @@ bool ScreenCapturerWinDirectx::SelectSource(SourceId id) {
|
||||
// frames only when a Duplicate() function call returns false.
|
||||
if (id == kFullDesktopScreenId) {
|
||||
current_screen_id_ = id;
|
||||
context_.Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
int screen_count = DxgiDuplicatorController::Instance()->ScreenCount();
|
||||
if (id >= 0 && id < screen_count) {
|
||||
current_screen_id_ = id;
|
||||
context_.Reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
#include "webrtc/modules/desktop_capture/resolution_change_detector.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/dxgi_duplicator_controller.h"
|
||||
@ -61,10 +62,9 @@ class ScreenCapturerWinDirectx : public DesktopCapturer {
|
||||
ScreenCaptureFrameQueue<SharedDesktopFrame> frames_;
|
||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
|
||||
Callback* callback_ = nullptr;
|
||||
|
||||
DxgiDuplicatorController::Context context_;
|
||||
|
||||
SourceId current_screen_id_ = kFullDesktopScreenId;
|
||||
ResolutionChangeDetector resolution_change_detector_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinDirectx);
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user