diff --git a/src/screen_capturer/windows/screen_capturer_wgc.cpp b/src/screen_capturer/windows/screen_capturer_wgc.cpp index 0b2ef72..c63f852 100644 --- a/src/screen_capturer/windows/screen_capturer_wgc.cpp +++ b/src/screen_capturer/windows/screen_capturer_wgc.cpp @@ -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; } @@ -327,4 +337,4 @@ void ScreenCapturerWgc::CleanUp() { sessions_.clear(); } } -} // namespace crossdesk \ No newline at end of file +} // namespace crossdesk diff --git a/src/screen_capturer/windows/screen_capturer_wgc.h b/src/screen_capturer/windows/screen_capturer_wgc.h index 3b4ee1c..1c8b721 100644 --- a/src/screen_capturer/windows/screen_capturer_wgc.h +++ b/src/screen_capturer/windows/screen_capturer_wgc.h @@ -57,8 +57,8 @@ class ScreenCapturerWgc : public ScreenCapturer, std::vector sessions_; - std::atomic_bool running_; - std::atomic_bool inited_; + std::atomic_bool running_{false}; + std::atomic_bool inited_{false}; int fps_ = 60; @@ -72,4 +72,4 @@ class ScreenCapturerWgc : public ScreenCapturer, std::mutex frame_mutex_; }; } // namespace crossdesk -#endif \ No newline at end of file +#endif diff --git a/src/screen_capturer/windows/screen_capturer_win.cpp b/src/screen_capturer/windows/screen_capturer_win.cpp index 70b3521..b0cf2e2 100644 --- a/src/screen_capturer/windows/screen_capturer_win.cpp +++ b/src/screen_capturer/windows/screen_capturer_win.cpp @@ -1,6 +1,9 @@ #include "screen_capturer_win.h" +#include #include +#include +#include #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 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 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 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 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(impl_.get())) { + if (try_init_start(std::make_unique())) { + LOG_INFO("Windows capturer: fallback to DXGI"); + return 0; + } + if (try_init_start(std::make_unique())) { + LOG_INFO("Windows capturer: fallback to GDI"); + return 0; + } + } else if (dynamic_cast(impl_.get())) { + if (try_init_start(std::make_unique())) { + 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 ScreenCapturerWin::GetDisplayInfoList() { return impl_->GetDisplayInfoList(); } -} // namespace crossdesk \ No newline at end of file +void ScreenCapturerWin::BuildCanonicalFromImpl() { + std::lock_guard 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 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 diff --git a/src/screen_capturer/windows/screen_capturer_win.h b/src/screen_capturer/windows/screen_capturer_win.h index 82903a3..2b03179 100644 --- a/src/screen_capturer/windows/screen_capturer_win.h +++ b/src/screen_capturer/windows/screen_capturer_win.h @@ -8,6 +8,9 @@ #define _SCREEN_CAPTURER_WIN_H_ #include +#include +#include +#include #include #include "screen_capturer.h" @@ -36,7 +39,16 @@ class ScreenCapturerWin : public ScreenCapturer { std::unique_ptr impl_; int fps_ = 60; cb_desktop_data cb_; + cb_desktop_data cb_orig_; + + std::unordered_map handle_to_canonical_; + std::unordered_map label_alias_; + std::mutex alias_mutex_; + std::vector canonical_displays_; + std::unordered_set canonical_labels_; + + void BuildCanonicalFromImpl(); + void RebuildAliasesFromImpl(); }; } // namespace crossdesk - -#endif \ No newline at end of file +#endif diff --git a/src/screen_capturer/windows/wgc_session_impl.cpp b/src/screen_capturer/windows/wgc_session_impl.cpp index 9014c0a..4b5cbd2 100644 --- a/src/screen_capturer/windows/wgc_session_impl.cpp +++ b/src/screen_capturer/windows/wgc_session_impl.cpp @@ -7,6 +7,8 @@ #include #include +#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(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; @@ -378,4 +405,4 @@ LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param, // ::CloseWindow(hwnd_); // ::DestroyWindow(hwnd_); // } -} // namespace crossdesk \ No newline at end of file +} // namespace crossdesk diff --git a/src/screen_capturer/windows/wgc_session_impl.h b/src/screen_capturer/windows/wgc_session_impl.h index cf0e4ff..f27edda 100644 --- a/src/screen_capturer/windows/wgc_session_impl.h +++ b/src/screen_capturer/windows/wgc_session_impl.h @@ -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; @@ -116,4 +117,4 @@ class WgcSessionImpl : public WgcSession { // return result; // } } // namespace crossdesk -#endif \ No newline at end of file +#endif