mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-03-22 07:37:29 +08:00
[fix] resolve failures in the WGC→DXGI→GDI fallback chain
This commit is contained in:
@@ -56,8 +56,6 @@ BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, [[maybe_unused]] HDC hdc,
|
||||
}
|
||||
}
|
||||
|
||||
if (monitor_info_.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER) return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -165,6 +163,8 @@ int ScreenCapturerWgc::Start(bool show_cursor) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
bool any_started = false;
|
||||
int last_error = 0;
|
||||
for (int i = 0; i < sessions_.size(); i++) {
|
||||
if (sessions_[i].inited_ == false) {
|
||||
LOG_ERROR("Session {} not inited", i);
|
||||
@@ -174,17 +174,27 @@ int ScreenCapturerWgc::Start(bool show_cursor) {
|
||||
if (sessions_[i].running_) {
|
||||
LOG_ERROR("Session {} is already running", i);
|
||||
} else {
|
||||
sessions_[i].session_->Start(show_cursor);
|
||||
int ret = sessions_[i].session_->Start(show_cursor);
|
||||
if (ret != 0) {
|
||||
LOG_ERROR("Session {} start failed, ret={}", i, ret);
|
||||
last_error = ret;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
sessions_[i].session_->Pause();
|
||||
sessions_[i].paused_ = true;
|
||||
}
|
||||
sessions_[i].running_ = true;
|
||||
any_started = true;
|
||||
}
|
||||
running_ = true;
|
||||
running_ = running_ || any_started;
|
||||
}
|
||||
|
||||
if (!any_started) {
|
||||
LOG_ERROR("WGC: no session started successfully");
|
||||
return last_error != 0 ? last_error : -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ class ScreenCapturerWgc : public ScreenCapturer,
|
||||
|
||||
std::vector<WgcSessionInfo> sessions_;
|
||||
|
||||
std::atomic_bool running_;
|
||||
std::atomic_bool inited_;
|
||||
std::atomic_bool running_{false};
|
||||
std::atomic_bool inited_{false};
|
||||
|
||||
int fps_ = 60;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "screen_capturer_win.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rd_log.h"
|
||||
#include "screen_capturer_dxgi.h"
|
||||
@@ -14,7 +17,26 @@ ScreenCapturerWin::~ScreenCapturerWin() { Destroy(); }
|
||||
|
||||
int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
|
||||
fps_ = fps;
|
||||
cb_ = cb;
|
||||
cb_orig_ = cb;
|
||||
cb_ = [this](unsigned char* data, int size, int w, int h,
|
||||
const char* display_name) {
|
||||
std::string mapped_name;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||
auto it = label_alias_.find(display_name);
|
||||
if (it != label_alias_.end())
|
||||
mapped_name = it->second;
|
||||
else
|
||||
mapped_name = display_name;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||
if (canonical_labels_.find(mapped_name) == canonical_labels_.end()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cb_orig_) cb_orig_(data, size, w, h, mapped_name.c_str());
|
||||
};
|
||||
|
||||
int ret = -1;
|
||||
|
||||
@@ -22,6 +44,7 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
|
||||
ret = impl_->Init(fps_, cb_);
|
||||
if (ret == 0) {
|
||||
LOG_INFO("Windows capturer: using WGC");
|
||||
BuildCanonicalFromImpl();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,6 +55,7 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
|
||||
ret = impl_->Init(fps_, cb_);
|
||||
if (ret == 0) {
|
||||
LOG_INFO("Windows capturer: using DXGI Desktop Duplication");
|
||||
BuildCanonicalFromImpl();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -42,6 +66,7 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
|
||||
ret = impl_->Init(fps_, cb_);
|
||||
if (ret == 0) {
|
||||
LOG_INFO("Windows capturer: using GDI BitBlt");
|
||||
BuildCanonicalFromImpl();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -55,12 +80,52 @@ int ScreenCapturerWin::Destroy() {
|
||||
impl_->Destroy();
|
||||
impl_.reset();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||
label_alias_.clear();
|
||||
handle_to_canonical_.clear();
|
||||
canonical_labels_.clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCapturerWin::Start(bool show_cursor) {
|
||||
if (!impl_) return -1;
|
||||
return impl_->Start(show_cursor);
|
||||
int ret = impl_->Start(show_cursor);
|
||||
if (ret == 0) return 0;
|
||||
|
||||
LOG_WARN("Windows capturer: Start failed (ret={}), trying fallback", ret);
|
||||
|
||||
auto try_init_start = [&](std::unique_ptr<ScreenCapturer> cand) -> bool {
|
||||
int r = cand->Init(fps_, cb_);
|
||||
if (r != 0) return false;
|
||||
int s = cand->Start(show_cursor);
|
||||
if (s == 0) {
|
||||
impl_ = std::move(cand);
|
||||
RebuildAliasesFromImpl();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (dynamic_cast<ScreenCapturerWgc*>(impl_.get())) {
|
||||
if (try_init_start(std::make_unique<ScreenCapturerDxgi>())) {
|
||||
LOG_INFO("Windows capturer: fallback to DXGI");
|
||||
return 0;
|
||||
}
|
||||
if (try_init_start(std::make_unique<ScreenCapturerGdi>())) {
|
||||
LOG_INFO("Windows capturer: fallback to GDI");
|
||||
return 0;
|
||||
}
|
||||
} else if (dynamic_cast<ScreenCapturerDxgi*>(impl_.get())) {
|
||||
if (try_init_start(std::make_unique<ScreenCapturerGdi>())) {
|
||||
LOG_INFO("Windows capturer: fallback to GDI");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR("Windows capturer: all fallbacks failed to start");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ScreenCapturerWin::Stop() {
|
||||
@@ -88,4 +153,46 @@ std::vector<DisplayInfo> ScreenCapturerWin::GetDisplayInfoList() {
|
||||
return impl_->GetDisplayInfoList();
|
||||
}
|
||||
|
||||
void ScreenCapturerWin::BuildCanonicalFromImpl() {
|
||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||
handle_to_canonical_.clear();
|
||||
label_alias_.clear();
|
||||
canonical_displays_ = impl_->GetDisplayInfoList();
|
||||
canonical_labels_.clear();
|
||||
for (const auto& di : canonical_displays_) {
|
||||
handle_to_canonical_[di.handle] = di.name;
|
||||
canonical_labels_.insert(di.name);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenCapturerWin::RebuildAliasesFromImpl() {
|
||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||
label_alias_.clear();
|
||||
auto current = impl_->GetDisplayInfoList();
|
||||
auto similar = [&](const DisplayInfo& a, const DisplayInfo& b) {
|
||||
int dl = std::abs(a.left - b.left);
|
||||
int dt = std::abs(a.top - b.top);
|
||||
int dw = std::abs(a.width - b.width);
|
||||
int dh = std::abs(a.height - b.height);
|
||||
return dl <= 10 && dt <= 10 && dw <= 20 && dh <= 20;
|
||||
};
|
||||
for (const auto& di : current) {
|
||||
std::string canonical;
|
||||
auto it = handle_to_canonical_.find(di.handle);
|
||||
if (it != handle_to_canonical_.end()) {
|
||||
canonical = it->second;
|
||||
} else {
|
||||
for (const auto& c : canonical_displays_) {
|
||||
if (similar(di, c) || (di.is_primary && c.is_primary)) {
|
||||
canonical = c.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!canonical.empty() && canonical != di.name) {
|
||||
label_alias_[di.name] = canonical;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crossdesk
|
||||
@@ -8,6 +8,9 @@
|
||||
#define _SCREEN_CAPTURER_WIN_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "screen_capturer.h"
|
||||
@@ -36,7 +39,16 @@ class ScreenCapturerWin : public ScreenCapturer {
|
||||
std::unique_ptr<ScreenCapturer> impl_;
|
||||
int fps_ = 60;
|
||||
cb_desktop_data cb_;
|
||||
cb_desktop_data cb_orig_;
|
||||
|
||||
std::unordered_map<void*, std::string> handle_to_canonical_;
|
||||
std::unordered_map<std::string, std::string> label_alias_;
|
||||
std::mutex alias_mutex_;
|
||||
std::vector<DisplayInfo> canonical_displays_;
|
||||
std::unordered_set<std::string> canonical_labels_;
|
||||
|
||||
void BuildCanonicalFromImpl();
|
||||
void RebuildAliasesFromImpl();
|
||||
};
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "rd_log.h"
|
||||
|
||||
#define CHECK_INIT \
|
||||
if (!is_initialized_) { \
|
||||
std::cout << "AE_NEED_INIT" << std::endl; \
|
||||
@@ -64,6 +66,7 @@ int WgcSessionImpl::Start(bool show_cursor) {
|
||||
|
||||
CHECK_INIT;
|
||||
try {
|
||||
last_show_cursor_ = show_cursor;
|
||||
if (!capture_session_) {
|
||||
auto current_size = capture_item_.Size();
|
||||
capture_framepool_ =
|
||||
@@ -89,13 +92,12 @@ int WgcSessionImpl::Start(bool show_cursor) {
|
||||
// we need to test the performance later
|
||||
// loop_ = std::thread(std::bind(&WgcSessionImpl::message_func, this));
|
||||
|
||||
capture_session_.StartCapture();
|
||||
|
||||
capture_session_.IsCursorCaptureEnabled(show_cursor);
|
||||
capture_session_.StartCapture();
|
||||
|
||||
error = 0;
|
||||
} catch (winrt::hresult_error) {
|
||||
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
|
||||
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
|
||||
return 86;
|
||||
} catch (...) {
|
||||
return 86;
|
||||
@@ -246,8 +248,15 @@ void WgcSessionImpl::OnFrame(
|
||||
auto frame_captured =
|
||||
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||
|
||||
if (!d3d11_texture_mapped_ || is_new_size)
|
||||
CreateMappedTexture(frame_captured);
|
||||
if (!d3d11_texture_mapped_ || is_new_size) {
|
||||
HRESULT tex_hr = CreateMappedTexture(frame_captured);
|
||||
if (FAILED(tex_hr)) {
|
||||
OutputDebugStringW(
|
||||
(L"CreateMappedTexture failed: " + std::to_wstring(tex_hr))
|
||||
.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
|
||||
frame_captured.get());
|
||||
@@ -262,6 +271,7 @@ void WgcSessionImpl::OnFrame(
|
||||
if (FAILED(hr)) {
|
||||
OutputDebugStringW(
|
||||
(L"map resource failed: " + std::to_wstring(hr)).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// copy data from map_result.pData
|
||||
@@ -290,7 +300,24 @@ void WgcSessionImpl::OnFrame(
|
||||
void WgcSessionImpl::OnClosed(
|
||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
|
||||
winrt::Windows::Foundation::IInspectable const&) {
|
||||
OutputDebugStringW(L"WgcSessionImpl::OnClosed");
|
||||
std::lock_guard locker(lock_);
|
||||
try {
|
||||
CleanUp();
|
||||
is_initialized_ = false;
|
||||
if (Initialize() == 0) {
|
||||
int ret = Start(last_show_cursor_);
|
||||
if (ret == 0) {
|
||||
OutputDebugStringW(L"WgcSessionImpl::OnClosed: auto recovered");
|
||||
} else {
|
||||
OutputDebugStringW(L"WgcSessionImpl::OnClosed: recover Start failed");
|
||||
}
|
||||
} else {
|
||||
OutputDebugStringW(
|
||||
L"WgcSessionImpl::OnClosed: recover Initialize failed");
|
||||
}
|
||||
} catch (...) {
|
||||
OutputDebugStringW(L"WgcSessionImpl::OnClosed: exception during recover");
|
||||
}
|
||||
}
|
||||
|
||||
int WgcSessionImpl::Initialize() {
|
||||
@@ -313,7 +340,7 @@ int WgcSessionImpl::Initialize() {
|
||||
d3d11_device->GetImmediateContext(d3d11_device_context_.put());
|
||||
|
||||
} catch (winrt::hresult_error) {
|
||||
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
|
||||
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
|
||||
return 86;
|
||||
} catch (...) {
|
||||
return 86;
|
||||
|
||||
@@ -79,6 +79,7 @@ class WgcSessionImpl : public WgcSession {
|
||||
bool is_initialized_ = false;
|
||||
bool is_running_ = false;
|
||||
bool is_paused_ = false;
|
||||
bool last_show_cursor_ = false;
|
||||
|
||||
wgc_session_observer* observer_ = nullptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user