mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-08-02 23:41:52 +08:00
[fix] recover Windows capture backends after secure desktop exit
This commit is contained in:
@@ -244,6 +244,31 @@ bool ScreenCapturerDxgi::CreateDuplicationForMonitor(int monitor_index) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScreenCapturerDxgi::RecreateDuplicationForCurrentMonitor() {
|
||||||
|
ReleaseDuplication();
|
||||||
|
int current_monitor = monitor_index_.load();
|
||||||
|
if (CreateDuplicationForMonitor(current_monitor)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumerateDisplays();
|
||||||
|
if (display_info_list_.empty()) {
|
||||||
|
LOG_ERROR("DXGI: no displays found while recreating duplication");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (current_monitor < 0 ||
|
||||||
|
current_monitor >= static_cast<int>(display_info_list_.size())) {
|
||||||
|
current_monitor = 0;
|
||||||
|
monitor_index_ = 0;
|
||||||
|
}
|
||||||
|
if (CreateDuplicationForMonitor(current_monitor)) {
|
||||||
|
LOG_INFO("DXGI: recreated duplication for monitor {}",
|
||||||
|
monitor_index_.load());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenCapturerDxgi::ReleaseDuplication() {
|
void ScreenCapturerDxgi::ReleaseDuplication() {
|
||||||
staging_.Reset();
|
staging_.Reset();
|
||||||
if (duplication_) {
|
if (duplication_) {
|
||||||
@@ -254,6 +279,8 @@ void ScreenCapturerDxgi::ReleaseDuplication() {
|
|||||||
|
|
||||||
void ScreenCapturerDxgi::CaptureLoop() {
|
void ScreenCapturerDxgi::CaptureLoop() {
|
||||||
const int timeout_ms = 33;
|
const int timeout_ms = 33;
|
||||||
|
auto last_duplication_retry =
|
||||||
|
std::chrono::steady_clock::now() - std::chrono::milliseconds(1000);
|
||||||
while (running_) {
|
while (running_) {
|
||||||
if (paused_) {
|
if (paused_) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
@@ -261,6 +288,11 @@ void ScreenCapturerDxgi::CaptureLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!duplication_) {
|
if (!duplication_) {
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
if (now - last_duplication_retry >= std::chrono::milliseconds(500)) {
|
||||||
|
last_duplication_retry = now;
|
||||||
|
RecreateDuplicationForCurrentMonitor();
|
||||||
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -274,9 +306,7 @@ void ScreenCapturerDxgi::CaptureLoop() {
|
|||||||
}
|
}
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
LOG_ERROR("DXGI: AcquireNextFrame failed, hr={}", (int)hr);
|
LOG_ERROR("DXGI: AcquireNextFrame failed, hr={}", (int)hr);
|
||||||
// attempt to recreate duplication
|
RecreateDuplicationForCurrentMonitor();
|
||||||
ReleaseDuplication();
|
|
||||||
CreateDuplicationForMonitor(monitor_index_);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,4 +383,4 @@ void ScreenCapturerDxgi::CaptureLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class ScreenCapturerDxgi : public ScreenCapturer {
|
|||||||
bool InitializeDxgi();
|
bool InitializeDxgi();
|
||||||
void EnumerateDisplays();
|
void EnumerateDisplays();
|
||||||
bool CreateDuplicationForMonitor(int monitor_index);
|
bool CreateDuplicationForMonitor(int monitor_index);
|
||||||
|
bool RecreateDuplicationForCurrentMonitor();
|
||||||
void CaptureLoop();
|
void CaptureLoop();
|
||||||
void ReleaseDuplication();
|
void ReleaseDuplication();
|
||||||
|
|
||||||
@@ -78,4 +79,4 @@ class ScreenCapturerDxgi : public ScreenCapturer {
|
|||||||
};
|
};
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -100,8 +100,7 @@ bool ScreenCapturerWgc::IsWgcSupported() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
|
int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
|
||||||
int error = 0;
|
if (inited_ == true) return 0;
|
||||||
if (inited_ == true) return error;
|
|
||||||
|
|
||||||
// nv12_frame_ = new unsigned char[rect.right * rect.bottom * 3 / 2];
|
// nv12_frame_ = new unsigned char[rect.right * rect.bottom * 3 / 2];
|
||||||
// nv12_frame_scaled_ = new unsigned char[1280 * 720 * 3 / 2];
|
// nv12_frame_scaled_ = new unsigned char[1280 * 720 * 3 / 2];
|
||||||
@@ -112,8 +111,18 @@ int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
|
|||||||
|
|
||||||
if (!IsWgcSupported()) {
|
if (!IsWgcSupported()) {
|
||||||
LOG_ERROR("WGC not supported");
|
LOG_ERROR("WGC not supported");
|
||||||
error = 2;
|
return 2;
|
||||||
return error;
|
}
|
||||||
|
|
||||||
|
return RebuildSessions(monitor_index_);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScreenCapturerWgc::RebuildSessions(int preferred_monitor_index) {
|
||||||
|
CleanUp();
|
||||||
|
|
||||||
|
if (!IsWgcSupported()) {
|
||||||
|
LOG_ERROR("WGC not supported");
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_ = GetPrimaryMonitor();
|
monitor_ = GetPrimaryMonitor();
|
||||||
@@ -125,6 +134,13 @@ int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preferred_monitor_index < 0 ||
|
||||||
|
preferred_monitor_index >= static_cast<int>(display_info_list_.size())) {
|
||||||
|
preferred_monitor_index = 0;
|
||||||
|
}
|
||||||
|
monitor_index_ = preferred_monitor_index;
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
for (int i = 0; i < display_info_list_.size(); i++) {
|
for (int i = 0; i < display_info_list_.size(); i++) {
|
||||||
const auto& display = display_info_list_[i];
|
const auto& display = display_info_list_[i];
|
||||||
LOG_INFO(
|
LOG_INFO(
|
||||||
@@ -138,20 +154,28 @@ int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
|
|||||||
sessions_.back().session_->RegisterObserver(this);
|
sessions_.back().session_->RegisterObserver(this);
|
||||||
error = sessions_.back().session_->Initialize((HMONITOR)display.handle);
|
error = sessions_.back().session_->Initialize((HMONITOR)display.handle);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
LOG_ERROR("WGC: initialize session {} failed, ret={}", i, error);
|
||||||
|
CleanUp();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
sessions_[i].inited_ = true;
|
sessions_[i].inited_ = true;
|
||||||
inited_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("Default on monitor {}:{}", monitor_index_,
|
LOG_INFO("Default on monitor {}:{}", monitor_index_,
|
||||||
display_info_list_[monitor_index_].name);
|
display_info_list_[monitor_index_].name);
|
||||||
|
|
||||||
initial_monitor_index_ = monitor_index_;
|
if (initial_monitor_index_ < 0 ||
|
||||||
|
initial_monitor_index_ >= static_cast<int>(display_info_list_.size())) {
|
||||||
|
initial_monitor_index_ = monitor_index_;
|
||||||
|
}
|
||||||
|
inited_ = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScreenCapturerWgc::Destroy() { return 0; }
|
int ScreenCapturerWgc::Destroy() {
|
||||||
|
CleanUp();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ScreenCapturerWgc::Start(bool show_cursor) {
|
int ScreenCapturerWgc::Start(bool show_cursor) {
|
||||||
if (running_ == true) {
|
if (running_ == true) {
|
||||||
@@ -160,13 +184,37 @@ int ScreenCapturerWgc::Start(bool show_cursor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inited_ == false) {
|
if (inited_ == false) {
|
||||||
LOG_ERROR("Screen capturer not inited");
|
const int ret = RebuildSessions(monitor_index_);
|
||||||
return 4;
|
if (ret != 0) {
|
||||||
|
LOG_ERROR("Screen capturer not inited");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ret = StartSessions(show_cursor);
|
||||||
|
if (ret == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARN("WGC: start failed, rebuilding sessions");
|
||||||
|
ret = RebuildSessions(monitor_index_);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return StartSessions(show_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScreenCapturerWgc::StartSessions(bool show_cursor) {
|
||||||
bool any_started = false;
|
bool any_started = false;
|
||||||
|
bool active_started = false;
|
||||||
int last_error = 0;
|
int last_error = 0;
|
||||||
for (int i = 0; i < sessions_.size(); i++) {
|
int active_monitor = monitor_index_;
|
||||||
|
if (active_monitor < 0 ||
|
||||||
|
active_monitor >= static_cast<int>(sessions_.size())) {
|
||||||
|
active_monitor = 0;
|
||||||
|
monitor_index_ = 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < static_cast<int>(sessions_.size()); i++) {
|
||||||
if (sessions_[i].inited_ == false) {
|
if (sessions_[i].inited_ == false) {
|
||||||
LOG_ERROR("Session {} not inited", i);
|
LOG_ERROR("Session {} not inited", i);
|
||||||
continue;
|
continue;
|
||||||
@@ -182,16 +230,27 @@ int ScreenCapturerWgc::Start(bool show_cursor) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != active_monitor) {
|
||||||
sessions_[i].session_->Pause();
|
sessions_[i].session_->Pause();
|
||||||
sessions_[i].paused_ = true;
|
sessions_[i].paused_ = true;
|
||||||
|
} else {
|
||||||
|
sessions_[i].session_->Resume();
|
||||||
|
sessions_[i].paused_ = false;
|
||||||
}
|
}
|
||||||
sessions_[i].running_ = true;
|
sessions_[i].running_ = true;
|
||||||
any_started = true;
|
any_started = true;
|
||||||
|
if (i == active_monitor) {
|
||||||
|
active_started = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
running_ = running_ || any_started;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
running_ = active_started;
|
||||||
|
if (!active_started) {
|
||||||
|
LOG_ERROR("WGC: active session did not start successfully");
|
||||||
|
Stop();
|
||||||
|
return last_error != 0 ? last_error : -1;
|
||||||
|
}
|
||||||
if (!any_started) {
|
if (!any_started) {
|
||||||
LOG_ERROR("WGC: no session started successfully");
|
LOG_ERROR("WGC: no session started successfully");
|
||||||
return last_error != 0 ? last_error : -1;
|
return last_error != 0 ? last_error : -1;
|
||||||
@@ -349,13 +408,16 @@ void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenCapturerWgc::CleanUp() {
|
void ScreenCapturerWgc::CleanUp() {
|
||||||
if (inited_) {
|
running_ = false;
|
||||||
for (auto& session : sessions_) {
|
for (auto& session : sessions_) {
|
||||||
if (session.session_) {
|
if (session.session_) {
|
||||||
session.session_->Stop();
|
session.session_->Stop();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sessions_.clear();
|
|
||||||
}
|
}
|
||||||
|
sessions_.clear();
|
||||||
|
display_info_list_.clear();
|
||||||
|
gs_display_list.clear();
|
||||||
|
monitor_ = nullptr;
|
||||||
|
inited_ = false;
|
||||||
}
|
}
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ class ScreenCapturerWgc : public ScreenCapturer,
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CleanUp();
|
void CleanUp();
|
||||||
|
int RebuildSessions(int preferred_monitor_index);
|
||||||
|
int StartSessions(bool show_cursor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HMONITOR monitor_;
|
HMONITOR monitor_;
|
||||||
@@ -74,4 +76,4 @@ class ScreenCapturerWgc : public ScreenCapturer,
|
|||||||
std::mutex frame_mutex_;
|
std::mutex frame_mutex_;
|
||||||
};
|
};
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ constexpr DWORD kSecureDesktopStatusPipeTimeoutMs = 500;
|
|||||||
constexpr DWORD kSecureDesktopHelperPipeTimeoutMs = 120;
|
constexpr DWORD kSecureDesktopHelperPipeTimeoutMs = 120;
|
||||||
constexpr DWORD kSecureDesktopTransientErrorGraceMs = 1500;
|
constexpr DWORD kSecureDesktopTransientErrorGraceMs = 1500;
|
||||||
constexpr DWORD kSecureDesktopTransientErrorLogIntervalMs = 5000;
|
constexpr DWORD kSecureDesktopTransientErrorLogIntervalMs = 5000;
|
||||||
|
constexpr DWORD kPostSecureDesktopRestartRetryMs = 500;
|
||||||
|
constexpr DWORD kPostSecureDesktopRestartTimeoutMs = 10000;
|
||||||
constexpr int kSecureDesktopCaptureMinFps = 30;
|
constexpr int kSecureDesktopCaptureMinFps = 30;
|
||||||
constexpr int kSecureDesktopCaptureMaxIntervalMs =
|
constexpr int kSecureDesktopCaptureMaxIntervalMs =
|
||||||
1000 / kSecureDesktopCaptureMinFps;
|
1000 / kSecureDesktopCaptureMinFps;
|
||||||
@@ -392,21 +394,46 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* raw_display_name = display_name ? display_name : "";
|
||||||
std::string mapped_name;
|
std::string mapped_name;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||||
auto it = label_alias_.find(display_name);
|
auto it = label_alias_.find(raw_display_name);
|
||||||
if (it != label_alias_.end())
|
if (it != label_alias_.end())
|
||||||
mapped_name = it->second;
|
mapped_name = it->second;
|
||||||
else
|
else
|
||||||
mapped_name = display_name;
|
mapped_name = raw_display_name;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(alias_mutex_);
|
std::lock_guard<std::mutex> lock(alias_mutex_);
|
||||||
if (canonical_labels_.find(mapped_name) == canonical_labels_.end()) {
|
if (canonical_labels_.find(mapped_name) == canonical_labels_.end()) {
|
||||||
|
if (post_secure_desktop_waiting_for_frame_.load(
|
||||||
|
std::memory_order_relaxed) &&
|
||||||
|
!post_secure_desktop_drop_logged_.exchange(
|
||||||
|
true, std::memory_order_relaxed)) {
|
||||||
|
LOG_WARN(
|
||||||
|
"Windows capturer dropping post-secure-desktop frame from "
|
||||||
|
"unknown display: display='{}', mapped='{}', size={}x{}, "
|
||||||
|
"bytes={}",
|
||||||
|
raw_display_name, mapped_name, w, h, size);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (post_secure_desktop_waiting_for_frame_.exchange(
|
||||||
|
false, std::memory_order_relaxed)) {
|
||||||
|
const ULONGLONG start_tick =
|
||||||
|
post_secure_desktop_started_tick_.exchange(
|
||||||
|
0, std::memory_order_relaxed);
|
||||||
|
const ULONGLONG elapsed_ms =
|
||||||
|
start_tick == 0 ? 0 : GetTickCount64() - start_tick;
|
||||||
|
post_secure_desktop_drop_logged_.store(false,
|
||||||
|
std::memory_order_relaxed);
|
||||||
|
LOG_INFO(
|
||||||
|
"Windows capturer first normal frame after secure desktop: "
|
||||||
|
"display='{}', mapped='{}', size={}x{}, bytes={}, elapsed_ms={}",
|
||||||
|
raw_display_name, mapped_name, w, h, size, elapsed_ms);
|
||||||
|
}
|
||||||
if (cb_orig_) cb_orig_(data, size, w, h, mapped_name.c_str());
|
if (cb_orig_) cb_orig_(data, size, w, h, mapped_name.c_str());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -524,6 +551,10 @@ int ScreenCapturerWin::Start(bool show_cursor) {
|
|||||||
|
|
||||||
running_.store(true, std::memory_order_relaxed);
|
running_.store(true, std::memory_order_relaxed);
|
||||||
secure_desktop_capture_active_.store(false, std::memory_order_relaxed);
|
secure_desktop_capture_active_.store(false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_waiting_for_frame_.store(false,
|
||||||
|
std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_drop_logged_.store(false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_started_tick_.store(0, std::memory_order_relaxed);
|
||||||
if (!secure_capture_thread_.joinable()) {
|
if (!secure_capture_thread_.joinable()) {
|
||||||
secure_capture_thread_ =
|
secure_capture_thread_ =
|
||||||
std::thread([this]() { SecureDesktopCaptureLoop(); });
|
std::thread([this]() { SecureDesktopCaptureLoop(); });
|
||||||
@@ -534,6 +565,10 @@ int ScreenCapturerWin::Start(bool show_cursor) {
|
|||||||
int ScreenCapturerWin::Stop() {
|
int ScreenCapturerWin::Stop() {
|
||||||
running_.store(false, std::memory_order_relaxed);
|
running_.store(false, std::memory_order_relaxed);
|
||||||
secure_desktop_capture_active_.store(false, std::memory_order_relaxed);
|
secure_desktop_capture_active_.store(false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_waiting_for_frame_.store(false,
|
||||||
|
std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_drop_logged_.store(false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_started_tick_.store(0, std::memory_order_relaxed);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (impl_) {
|
if (impl_) {
|
||||||
ret = impl_->Stop();
|
ret = impl_->Stop();
|
||||||
@@ -626,6 +661,93 @@ void ScreenCapturerWin::StopSecureCaptureThread() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScreenCapturerWin::RestartCaptureBackendAfterSecureDesktop() {
|
||||||
|
if (!impl_ || !running_.load(std::memory_order_relaxed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool show_cursor = show_cursor_.load(std::memory_order_relaxed);
|
||||||
|
const int current_monitor = monitor_index_.load(std::memory_order_relaxed);
|
||||||
|
auto restore_monitor = [&]() {
|
||||||
|
RebuildAliasesFromImpl();
|
||||||
|
if (current_monitor > 0 && impl_->SwitchTo(current_monitor) != 0) {
|
||||||
|
monitor_index_.store(0, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto try_started_backend = [&](std::unique_ptr<ScreenCapturer> cand,
|
||||||
|
const char* name,
|
||||||
|
bool is_wgc_plugin) -> bool {
|
||||||
|
if (!cand) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const int init_ret = cand->Init(fps_, cb_);
|
||||||
|
if (init_ret != 0) {
|
||||||
|
LOG_WARN("Windows capturer: {} init after secure desktop failed (ret={})",
|
||||||
|
name, init_ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const int start_ret = cand->Start(show_cursor);
|
||||||
|
if (start_ret != 0) {
|
||||||
|
LOG_WARN(
|
||||||
|
"Windows capturer: {} start after secure desktop failed (ret={})",
|
||||||
|
name, start_ret);
|
||||||
|
cand->Destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (impl_) {
|
||||||
|
impl_->Destroy();
|
||||||
|
}
|
||||||
|
impl_ = std::move(cand);
|
||||||
|
impl_is_wgc_plugin_ = is_wgc_plugin;
|
||||||
|
restore_monitor();
|
||||||
|
LOG_INFO("Windows capturer: restarted {} after secure desktop", name);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
LOG_INFO("Windows capturer: restarting capture backend after secure desktop");
|
||||||
|
impl_->Stop();
|
||||||
|
int ret = impl_->Start(show_cursor);
|
||||||
|
if (ret == 0) {
|
||||||
|
restore_monitor();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARN(
|
||||||
|
"Windows capturer: capture backend restart after secure desktop failed "
|
||||||
|
"(ret={}), rebuilding backend",
|
||||||
|
ret);
|
||||||
|
impl_->Destroy();
|
||||||
|
ret = impl_->Init(fps_, cb_);
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = impl_->Start(show_cursor);
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
restore_monitor();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (impl_is_wgc_plugin_ &&
|
||||||
|
try_started_backend(WgcPluginCapturer::Create(), "WGC plugin", true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (try_started_backend(std::make_unique<ScreenCapturerDxgi>(), "DXGI",
|
||||||
|
false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (try_started_backend(std::make_unique<ScreenCapturerGdi>(), "GDI",
|
||||||
|
false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (impl_) {
|
||||||
|
LOG_WARN(
|
||||||
|
"Windows capturer: all backend restart attempts after secure desktop "
|
||||||
|
"failed (last_ret={})",
|
||||||
|
ret);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ScreenCapturerWin::GetCurrentCaptureRegion(int* left, int* top, int* width,
|
bool ScreenCapturerWin::GetCurrentCaptureRegion(int* left, int* top, int* width,
|
||||||
int* height,
|
int* height,
|
||||||
std::string* display_name) {
|
std::string* display_name) {
|
||||||
@@ -900,6 +1022,9 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
std::string last_stage;
|
std::string last_stage;
|
||||||
std::string last_service_error;
|
std::string last_service_error;
|
||||||
ULONGLONG capture_stage_started_tick = 0;
|
ULONGLONG capture_stage_started_tick = 0;
|
||||||
|
bool post_secure_restart_pending = false;
|
||||||
|
ULONGLONG post_secure_restart_deadline_tick = 0;
|
||||||
|
ULONGLONG last_post_secure_restart_tick = 0;
|
||||||
SecureDesktopServiceStatus status;
|
SecureDesktopServiceStatus status;
|
||||||
std::vector<uint8_t> secure_frame;
|
std::vector<uint8_t> secure_frame;
|
||||||
|
|
||||||
@@ -951,6 +1076,10 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
std::memory_order_relaxed);
|
std::memory_order_relaxed);
|
||||||
if (status.capture_active != last_capture_active ||
|
if (status.capture_active != last_capture_active ||
|
||||||
status.interactive_stage != last_stage) {
|
status.interactive_stage != last_stage) {
|
||||||
|
const bool secure_capture_started =
|
||||||
|
!last_capture_active && status.capture_active;
|
||||||
|
const bool secure_capture_ended =
|
||||||
|
last_capture_active && !status.capture_active;
|
||||||
capture_stage_started_tick = now;
|
capture_stage_started_tick = now;
|
||||||
LOG_INFO(
|
LOG_INFO(
|
||||||
"Windows capturer secure desktop state: active={}, stage='{}', "
|
"Windows capturer secure desktop state: active={}, stage='{}', "
|
||||||
@@ -959,12 +1088,46 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
status.active_session_id);
|
status.active_session_id);
|
||||||
last_capture_active = status.capture_active;
|
last_capture_active = status.capture_active;
|
||||||
last_stage = status.interactive_stage;
|
last_stage = status.interactive_stage;
|
||||||
|
if (secure_capture_started) {
|
||||||
|
post_secure_restart_pending = false;
|
||||||
|
post_secure_desktop_waiting_for_frame_.store(
|
||||||
|
false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_drop_logged_.store(
|
||||||
|
false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_started_tick_.store(
|
||||||
|
0, std::memory_order_relaxed);
|
||||||
|
} else if (secure_capture_ended) {
|
||||||
|
post_secure_restart_pending = true;
|
||||||
|
post_secure_restart_deadline_tick =
|
||||||
|
now + kPostSecureDesktopRestartTimeoutMs;
|
||||||
|
last_post_secure_restart_tick = 0;
|
||||||
|
post_secure_desktop_waiting_for_frame_.store(
|
||||||
|
true, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_drop_logged_.store(
|
||||||
|
false, std::memory_order_relaxed);
|
||||||
|
post_secure_desktop_started_tick_.store(
|
||||||
|
now, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
last_status_tick = now;
|
last_status_tick = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!status.capture_active || status.active_session_id == 0xFFFFFFFF) {
|
if (!status.capture_active || status.active_session_id == 0xFFFFFFFF) {
|
||||||
StopSecureDesktopSharedCapture(secure_shared_session_id_);
|
StopSecureDesktopSharedCapture(secure_shared_session_id_);
|
||||||
|
if (post_secure_restart_pending) {
|
||||||
|
if (now >= post_secure_restart_deadline_tick) {
|
||||||
|
LOG_WARN(
|
||||||
|
"Windows capturer: capture backend restart after secure desktop "
|
||||||
|
"timed out");
|
||||||
|
post_secure_restart_pending = false;
|
||||||
|
} else if (last_post_secure_restart_tick == 0 ||
|
||||||
|
now - last_post_secure_restart_tick >=
|
||||||
|
kPostSecureDesktopRestartRetryMs) {
|
||||||
|
last_post_secure_restart_tick = now;
|
||||||
|
post_secure_restart_pending =
|
||||||
|
!RestartCaptureBackendAfterSecureDesktop();
|
||||||
|
}
|
||||||
|
}
|
||||||
std::this_thread::sleep_for(
|
std::this_thread::sleep_for(
|
||||||
std::chrono::milliseconds(status.service_available ? 50 : 200));
|
std::chrono::milliseconds(status.service_available ? 50 : 200));
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ class ScreenCapturerWin : public ScreenCapturer {
|
|||||||
std::atomic<int> monitor_index_{0};
|
std::atomic<int> monitor_index_{0};
|
||||||
int initial_monitor_index_ = 0;
|
int initial_monitor_index_ = 0;
|
||||||
std::atomic<bool> secure_desktop_capture_active_{false};
|
std::atomic<bool> secure_desktop_capture_active_{false};
|
||||||
|
std::atomic<bool> post_secure_desktop_waiting_for_frame_{false};
|
||||||
|
std::atomic<bool> post_secure_desktop_drop_logged_{false};
|
||||||
|
std::atomic<ULONGLONG> post_secure_desktop_started_tick_{0};
|
||||||
std::thread secure_capture_thread_;
|
std::thread secure_capture_thread_;
|
||||||
HANDLE secure_frame_mapping_ = nullptr;
|
HANDLE secure_frame_mapping_ = nullptr;
|
||||||
HANDLE secure_frame_ready_event_ = nullptr;
|
HANDLE secure_frame_ready_event_ = nullptr;
|
||||||
@@ -77,6 +80,7 @@ class ScreenCapturerWin : public ScreenCapturer {
|
|||||||
void BuildCanonicalFromImpl();
|
void BuildCanonicalFromImpl();
|
||||||
void RebuildAliasesFromImpl();
|
void RebuildAliasesFromImpl();
|
||||||
void StopSecureCaptureThread();
|
void StopSecureCaptureThread();
|
||||||
|
bool RestartCaptureBackendAfterSecureDesktop();
|
||||||
void SecureDesktopCaptureLoop();
|
void SecureDesktopCaptureLoop();
|
||||||
bool GetCurrentCaptureRegion(int* left, int* top, int* width, int* height,
|
bool GetCurrentCaptureRegion(int* left, int* top, int* width, int* height,
|
||||||
std::string* display_name);
|
std::string* display_name);
|
||||||
|
|||||||
@@ -2,23 +2,10 @@
|
|||||||
|
|
||||||
#include <Windows.Graphics.Capture.Interop.h>
|
#include <Windows.Graphics.Capture.Interop.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <string>
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
|
|
||||||
#define CHECK_INIT \
|
|
||||||
if (!is_initialized_) { \
|
|
||||||
LOG_ERROR("AE_NEED_INIT"); \
|
|
||||||
return 4; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK_CLOSED \
|
|
||||||
if (cleaned_.load() == true) { \
|
|
||||||
throw winrt::hresult_error(RO_E_CLOSED); \
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -40,7 +27,7 @@ int WgcSessionImpl::Initialize(HWND hwnd) {
|
|||||||
|
|
||||||
target_.hwnd = hwnd;
|
target_.hwnd = hwnd;
|
||||||
target_.is_window = true;
|
target_.is_window = true;
|
||||||
return Initialize();
|
return InitializeLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
|
int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
|
||||||
@@ -48,7 +35,7 @@ int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
|
|||||||
|
|
||||||
target_.hmonitor = hmonitor;
|
target_.hmonitor = hmonitor;
|
||||||
target_.is_window = false;
|
target_.is_window = false;
|
||||||
return Initialize();
|
return InitializeLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WgcSessionImpl::RegisterObserver(wgc_session_observer* observer) {
|
void WgcSessionImpl::RegisterObserver(wgc_session_observer* observer) {
|
||||||
@@ -59,68 +46,13 @@ void WgcSessionImpl::RegisterObserver(wgc_session_observer* observer) {
|
|||||||
int WgcSessionImpl::Start(bool show_cursor) {
|
int WgcSessionImpl::Start(bool show_cursor) {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
if (is_running_) return 0;
|
return StartLocked(show_cursor);
|
||||||
|
|
||||||
int error = 1;
|
|
||||||
|
|
||||||
CHECK_INIT;
|
|
||||||
try {
|
|
||||||
last_show_cursor_ = show_cursor;
|
|
||||||
if (!capture_session_) {
|
|
||||||
auto current_size = capture_item_.Size();
|
|
||||||
capture_framepool_ =
|
|
||||||
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
|
|
||||||
CreateFreeThreaded(d3d11_direct_device_,
|
|
||||||
winrt::Windows::Graphics::DirectX::
|
|
||||||
DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
|
||||||
2, current_size);
|
|
||||||
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
|
|
||||||
capture_frame_size_ = current_size;
|
|
||||||
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
|
|
||||||
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
|
|
||||||
capture_close_trigger_ = capture_item_.Closed(
|
|
||||||
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!capture_framepool_) throw std::exception();
|
|
||||||
|
|
||||||
is_running_ = true;
|
|
||||||
|
|
||||||
// we do not need to crate a thread to enter a message loop coz we use
|
|
||||||
// CreateFreeThreaded instead of Create to create a capture frame pool,
|
|
||||||
// we need to test the performance later
|
|
||||||
// loop_ = std::thread(std::bind(&WgcSessionImpl::message_func, this));
|
|
||||||
|
|
||||||
capture_session_.IsCursorCaptureEnabled(show_cursor);
|
|
||||||
capture_session_.StartCapture();
|
|
||||||
|
|
||||||
error = 0;
|
|
||||||
} catch (winrt::hresult_error) {
|
|
||||||
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
|
|
||||||
return 86;
|
|
||||||
} catch (...) {
|
|
||||||
return 86;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int WgcSessionImpl::Stop() {
|
int WgcSessionImpl::Stop() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
CHECK_INIT;
|
CleanUpLocked();
|
||||||
|
|
||||||
is_running_ = false;
|
|
||||||
|
|
||||||
// if (loop_.joinable()) loop_.join();
|
|
||||||
|
|
||||||
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
|
|
||||||
|
|
||||||
if (capture_session_) {
|
|
||||||
capture_session_.Close();
|
|
||||||
capture_session_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +61,10 @@ int WgcSessionImpl::Pause() {
|
|||||||
|
|
||||||
is_paused_ = true;
|
is_paused_ = true;
|
||||||
|
|
||||||
CHECK_INIT;
|
if (!is_initialized_) {
|
||||||
|
LOG_ERROR("AE_NEED_INIT");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +73,10 @@ int WgcSessionImpl::Resume() {
|
|||||||
|
|
||||||
is_paused_ = false;
|
is_paused_ = false;
|
||||||
|
|
||||||
CHECK_INIT;
|
if (!is_initialized_) {
|
||||||
|
LOG_ERROR("AE_NEED_INIT");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,10 +113,10 @@ auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) {
|
|||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||||
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
|
||||||
interop_factory->CreateForWindow(
|
winrt::check_hresult(interop_factory->CreateForWindow(
|
||||||
hwnd,
|
hwnd,
|
||||||
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
|
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
|
||||||
reinterpret_cast<void**>(winrt::put_abi(item)));
|
reinterpret_cast<void**>(winrt::put_abi(item))));
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,10 +125,10 @@ auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) {
|
|||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||||
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
|
||||||
interop_factory->CreateForMonitor(
|
winrt::check_hresult(interop_factory->CreateForMonitor(
|
||||||
hmonitor,
|
hmonitor,
|
||||||
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
|
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
|
||||||
reinterpret_cast<void**>(winrt::put_abi(item)));
|
reinterpret_cast<void**>(winrt::put_abi(item))));
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +156,104 @@ HRESULT WgcSessionImpl::CreateMappedTexture(
|
|||||||
d3d11_texture_mapped_.put());
|
d3d11_texture_mapped_.put());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WgcSessionImpl::StartCaptureLocked(bool show_cursor) {
|
||||||
|
if (!is_initialized_) {
|
||||||
|
LOG_ERROR("AE_NEED_INIT");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (!capture_item_) {
|
||||||
|
LOG_ERROR("WGC: capture item is null");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!capture_session_) {
|
||||||
|
auto current_size = capture_item_.Size();
|
||||||
|
capture_framepool_ =
|
||||||
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
|
||||||
|
CreateFreeThreaded(d3d11_direct_device_,
|
||||||
|
winrt::Windows::Graphics::DirectX::
|
||||||
|
DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
||||||
|
2, current_size);
|
||||||
|
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
|
||||||
|
capture_frame_size_ = current_size;
|
||||||
|
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
|
||||||
|
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
|
||||||
|
capture_close_trigger_ = capture_item_.Closed(
|
||||||
|
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!capture_framepool_ || !capture_session_) {
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
capture_session_.IsCursorCaptureEnabled(show_cursor);
|
||||||
|
capture_session_.StartCapture();
|
||||||
|
is_running_ = true;
|
||||||
|
return 0;
|
||||||
|
} catch (const winrt::hresult_error&) {
|
||||||
|
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
|
||||||
|
return 86;
|
||||||
|
} catch (...) {
|
||||||
|
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
|
||||||
|
return 86;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WgcSessionImpl::StartLocked(bool show_cursor) {
|
||||||
|
if (is_running_) return 0;
|
||||||
|
|
||||||
|
last_show_cursor_ = show_cursor;
|
||||||
|
if (!is_initialized_) {
|
||||||
|
const int init_ret = InitializeLocked();
|
||||||
|
if (init_ret != 0) {
|
||||||
|
return init_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = StartCaptureLocked(show_cursor);
|
||||||
|
if (ret == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARN("WGC: start capture failed, rebuilding capture item");
|
||||||
|
CleanUpLocked();
|
||||||
|
ret = InitializeLocked();
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return StartCaptureLocked(show_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgcSessionImpl::StopLocked() {
|
||||||
|
is_running_ = false;
|
||||||
|
|
||||||
|
// if (loop_.joinable()) loop_.join();
|
||||||
|
|
||||||
|
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
|
||||||
|
if (capture_close_trigger_) capture_close_trigger_.revoke();
|
||||||
|
|
||||||
|
if (capture_session_) {
|
||||||
|
try {
|
||||||
|
capture_session_.Close();
|
||||||
|
} catch (...) {
|
||||||
|
LOG_WARN("WGC: capture session close failed");
|
||||||
|
}
|
||||||
|
capture_session_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capture_framepool_) {
|
||||||
|
try {
|
||||||
|
capture_framepool_.Close();
|
||||||
|
} catch (...) {
|
||||||
|
LOG_WARN("WGC: frame pool close failed");
|
||||||
|
}
|
||||||
|
capture_framepool_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
d3d11_texture_mapped_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void WgcSessionImpl::OnFrame(
|
void WgcSessionImpl::OnFrame(
|
||||||
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& sender,
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& sender,
|
||||||
[[maybe_unused]] winrt::Windows::Foundation::IInspectable const& args) {
|
[[maybe_unused]] winrt::Windows::Foundation::IInspectable const& args) {
|
||||||
@@ -225,7 +261,7 @@ void WgcSessionImpl::OnFrame(
|
|||||||
|
|
||||||
auto is_new_size = false;
|
auto is_new_size = false;
|
||||||
|
|
||||||
{
|
try {
|
||||||
auto frame = sender.TryGetNextFrame();
|
auto frame = sender.TryGetNextFrame();
|
||||||
auto frame_size = frame.ContentSize();
|
auto frame_size = frame.ContentSize();
|
||||||
|
|
||||||
@@ -239,60 +275,63 @@ void WgcSessionImpl::OnFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copy to mapped texture
|
// copy to mapped texture
|
||||||
{
|
if (is_paused_) {
|
||||||
if (is_paused_) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto frame_captured =
|
|
||||||
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map_result;
|
|
||||||
HRESULT hr = d3d11_device_context_->Map(
|
|
||||||
d3d11_texture_mapped_.get(), 0, D3D11_MAP_READ,
|
|
||||||
0 /*coz we use CreateFreeThreaded, so we cant use flags
|
|
||||||
D3D11_MAP_FLAG_DO_NOT_WAIT*/
|
|
||||||
,
|
|
||||||
&map_result);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
OutputDebugStringW(
|
|
||||||
(L"map resource failed: " + std::to_wstring(hr)).c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy data from map_result.pData
|
|
||||||
if (map_result.pData && observer_) {
|
|
||||||
observer_->OnFrame(
|
|
||||||
wgc_session_frame{static_cast<unsigned int>(frame_size.Width),
|
|
||||||
static_cast<unsigned int>(frame_size.Height),
|
|
||||||
map_result.RowPitch,
|
|
||||||
const_cast<const unsigned char*>(
|
|
||||||
(unsigned char*)map_result.pData)},
|
|
||||||
id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (is_new_size) {
|
auto frame_captured =
|
||||||
capture_framepool_.Recreate(d3d11_direct_device_,
|
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||||
winrt::Windows::Graphics::DirectX::
|
|
||||||
DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
if (!d3d11_texture_mapped_ || is_new_size) {
|
||||||
2, capture_frame_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());
|
||||||
|
|
||||||
|
D3D11_MAPPED_SUBRESOURCE map_result;
|
||||||
|
HRESULT hr = d3d11_device_context_->Map(
|
||||||
|
d3d11_texture_mapped_.get(), 0, D3D11_MAP_READ,
|
||||||
|
0 /*coz we use CreateFreeThreaded, so we cant use flags
|
||||||
|
D3D11_MAP_FLAG_DO_NOT_WAIT*/
|
||||||
|
,
|
||||||
|
&map_result);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
OutputDebugStringW(
|
||||||
|
(L"map resource failed: " + std::to_wstring(hr)).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy data from map_result.pData
|
||||||
|
if (map_result.pData && observer_) {
|
||||||
|
observer_->OnFrame(
|
||||||
|
wgc_session_frame{static_cast<unsigned int>(frame_size.Width),
|
||||||
|
static_cast<unsigned int>(frame_size.Height),
|
||||||
|
map_result.RowPitch,
|
||||||
|
const_cast<const unsigned char*>(
|
||||||
|
(unsigned char*)map_result.pData)},
|
||||||
|
id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
|
||||||
|
|
||||||
|
if (is_new_size) {
|
||||||
|
capture_framepool_.Recreate(
|
||||||
|
d3d11_direct_device_,
|
||||||
|
winrt::Windows::Graphics::DirectX::
|
||||||
|
DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
||||||
|
2, capture_frame_size_);
|
||||||
|
}
|
||||||
|
} catch (const winrt::hresult_error&) {
|
||||||
|
LOG_WARN("WGC: frame processing failed");
|
||||||
|
} catch (...) {
|
||||||
|
LOG_WARN("WGC: frame processing failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,11 +339,13 @@ void WgcSessionImpl::OnClosed(
|
|||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
|
||||||
winrt::Windows::Foundation::IInspectable const&) {
|
winrt::Windows::Foundation::IInspectable const&) {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
const bool was_running = is_running_;
|
||||||
|
const bool was_paused = is_paused_;
|
||||||
try {
|
try {
|
||||||
CleanUp();
|
CleanUpLocked();
|
||||||
is_initialized_ = false;
|
is_paused_ = was_paused;
|
||||||
if (Initialize() == 0) {
|
if (InitializeLocked() == 0) {
|
||||||
int ret = Start(last_show_cursor_);
|
int ret = was_running ? StartCaptureLocked(last_show_cursor_) : 0;
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
OutputDebugStringW(L"WgcSessionImpl::OnClosed: auto recovered");
|
OutputDebugStringW(L"WgcSessionImpl::OnClosed: auto recovered");
|
||||||
} else {
|
} else {
|
||||||
@@ -319,9 +360,14 @@ void WgcSessionImpl::OnClosed(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int WgcSessionImpl::Initialize() {
|
int WgcSessionImpl::InitializeLocked() {
|
||||||
if (is_initialized_) return 0;
|
if (is_initialized_) return 0;
|
||||||
|
|
||||||
|
d3d11_texture_mapped_ = nullptr;
|
||||||
|
d3d11_device_context_ = nullptr;
|
||||||
|
d3d11_direct_device_ = nullptr;
|
||||||
|
capture_frame_size_ = {};
|
||||||
|
|
||||||
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
|
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
|
||||||
LOG_ERROR("AE_D3D_CREATE_DEVICE_FAILED");
|
LOG_ERROR("AE_D3D_CREATE_DEVICE_FAILED");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -332,6 +378,10 @@ int WgcSessionImpl::Initialize() {
|
|||||||
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
|
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
|
||||||
else
|
else
|
||||||
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
|
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
|
||||||
|
if (!capture_item_) {
|
||||||
|
LOG_ERROR("WGC: create capture item returned null");
|
||||||
|
return 86;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up
|
// Set up
|
||||||
auto d3d11_device =
|
auto d3d11_device =
|
||||||
@@ -353,21 +403,18 @@ int WgcSessionImpl::Initialize() {
|
|||||||
void WgcSessionImpl::CleanUp() {
|
void WgcSessionImpl::CleanUp() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
auto expected = false;
|
CleanUpLocked();
|
||||||
if (cleaned_.compare_exchange_strong(expected, true)) {
|
}
|
||||||
capture_close_trigger_.revoke();
|
|
||||||
capture_framepool_trigger_.revoke();
|
|
||||||
|
|
||||||
if (capture_framepool_) capture_framepool_.Close();
|
void WgcSessionImpl::CleanUpLocked() {
|
||||||
|
StopLocked();
|
||||||
|
|
||||||
if (capture_session_) capture_session_.Close();
|
capture_item_ = nullptr;
|
||||||
|
d3d11_device_context_ = nullptr;
|
||||||
capture_framepool_ = nullptr;
|
d3d11_direct_device_ = nullptr;
|
||||||
capture_session_ = nullptr;
|
capture_frame_size_ = {};
|
||||||
capture_item_ = nullptr;
|
is_initialized_ = false;
|
||||||
|
is_paused_ = false;
|
||||||
is_initialized_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
|
LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
|
||||||
|
|||||||
@@ -68,8 +68,12 @@ class WgcSessionImpl : public WgcSession {
|
|||||||
void OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
|
void OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
|
||||||
winrt::Windows::Foundation::IInspectable const&);
|
winrt::Windows::Foundation::IInspectable const&);
|
||||||
|
|
||||||
int Initialize();
|
int InitializeLocked();
|
||||||
|
int StartLocked(bool show_cursor);
|
||||||
|
int StartCaptureLocked(bool show_cursor);
|
||||||
|
void StopLocked();
|
||||||
void CleanUp();
|
void CleanUp();
|
||||||
|
void CleanUpLocked();
|
||||||
|
|
||||||
// void message_func();
|
// void message_func();
|
||||||
|
|
||||||
@@ -94,7 +98,6 @@ class WgcSessionImpl : public WgcSession {
|
|||||||
winrt::com_ptr<ID3D11DeviceContext> d3d11_device_context_{nullptr};
|
winrt::com_ptr<ID3D11DeviceContext> d3d11_device_context_{nullptr};
|
||||||
winrt::com_ptr<ID3D11Texture2D> d3d11_texture_mapped_{nullptr};
|
winrt::com_ptr<ID3D11Texture2D> d3d11_texture_mapped_{nullptr};
|
||||||
|
|
||||||
std::atomic<bool> cleaned_ = false;
|
|
||||||
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool
|
||||||
capture_framepool_{nullptr};
|
capture_framepool_{nullptr};
|
||||||
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
|
||||||
|
|||||||
Reference in New Issue
Block a user