[feat] add Windows screen capture method setting

This commit is contained in:
dijunkun
2026-09-11 16:41:16 +08:00
parent ceb0a1654a
commit 9af7417c46
11 changed files with 116 additions and 13 deletions
@@ -58,6 +58,14 @@ int ConfigCenter::Load() {
video_frame_rate_ = static_cast<VIDEO_FRAME_RATE>(ini_.GetLongValue(
section_, "video_frame_rate", static_cast<long>(video_frame_rate_)));
const long screen_capture_method_value = ini_.GetLongValue(
section_, "screen_capture_method",
static_cast<long>(ScreenCaptureMethod::Auto));
screen_capture_method_ = IsValidScreenCaptureMethod(screen_capture_method_value)
? static_cast<ScreenCaptureMethod>(
screen_capture_method_value)
: ScreenCaptureMethod::Auto;
const long video_adaptation_policy_value = ini_.GetLongValue(
section_, "video_adaptation_policy",
static_cast<long>(video_adaptation_policy_));
@@ -147,6 +155,8 @@ int ConfigCenter::Save() {
static_cast<long>(video_quality_));
ini_.SetLongValue(section_, "video_frame_rate",
static_cast<long>(video_frame_rate_));
ini_.SetLongValue(section_, "screen_capture_method",
static_cast<long>(screen_capture_method_));
ini_.SetLongValue(section_, "video_adaptation_policy",
static_cast<long>(video_adaptation_policy_));
ini_.SetLongValue(section_, "video_encode_format",
@@ -217,6 +227,20 @@ int ConfigCenter::SetVideoFrameRate(VIDEO_FRAME_RATE video_frame_rate) {
return 0;
}
int ConfigCenter::SetScreenCaptureMethod(ScreenCaptureMethod method) {
if (!IsValidScreenCaptureMethod(static_cast<long>(method))) {
return -1;
}
ini_.SetLongValue(section_, "screen_capture_method", static_cast<long>(method));
if (ini_.SaveFile(config_path_.c_str()) < 0) {
ini_.SetLongValue(section_, "screen_capture_method",
static_cast<long>(screen_capture_method_));
return -1;
}
screen_capture_method_ = method;
return 0;
}
int ConfigCenter::SetVideoAdaptationPolicy(
VIDEO_ADAPTATION_POLICY policy) {
video_adaptation_policy_ = policy;
@@ -413,6 +437,10 @@ ConfigCenter::VIDEO_FRAME_RATE ConfigCenter::GetVideoFrameRate() const {
return video_frame_rate_;
}
ScreenCaptureMethod ConfigCenter::GetScreenCaptureMethod() const {
return screen_capture_method_;
}
ConfigCenter::VIDEO_ADAPTATION_POLICY
ConfigCenter::GetVideoAdaptationPolicy() const {
return video_adaptation_policy_;
@@ -11,6 +11,7 @@
#include <string>
#include "SimpleIni.h"
#include "screen_capturer/screen_capture_method.h"
namespace crossdesk {
@@ -40,6 +41,7 @@ class ConfigCenter {
int SetLanguage(LANGUAGE language);
int SetVideoQuality(VIDEO_QUALITY video_quality);
int SetVideoFrameRate(VIDEO_FRAME_RATE video_frame_rate);
int SetScreenCaptureMethod(ScreenCaptureMethod method);
int SetVideoAdaptationPolicy(VIDEO_ADAPTATION_POLICY policy);
int SetVideoEncodeFormat(VIDEO_ENCODE_FORMAT video_encode_format);
int SetHardwareVideoCodec(bool hardware_video_codec);
@@ -60,6 +62,7 @@ class ConfigCenter {
LANGUAGE GetLanguage() const;
VIDEO_QUALITY GetVideoQuality() const;
VIDEO_FRAME_RATE GetVideoFrameRate() const;
ScreenCaptureMethod GetScreenCaptureMethod() const;
VIDEO_ADAPTATION_POLICY GetVideoAdaptationPolicy() const;
VIDEO_ENCODE_FORMAT GetVideoEncodeFormat() const;
bool IsHardwareVideoCodec() const;
@@ -88,6 +91,7 @@ class ConfigCenter {
LANGUAGE language_ = LANGUAGE::CHINESE;
VIDEO_QUALITY video_quality_ = VIDEO_QUALITY::HIGH;
VIDEO_FRAME_RATE video_frame_rate_ = VIDEO_FRAME_RATE::FPS_60;
ScreenCaptureMethod screen_capture_method_ = ScreenCaptureMethod::Auto;
VIDEO_ADAPTATION_POLICY video_adaptation_policy_ =
VIDEO_ADAPTATION_POLICY::QUALITY_PRIORITY;
VIDEO_ENCODE_FORMAT video_encode_format_ = VIDEO_ENCODE_FORMAT::H264;
@@ -1231,6 +1231,9 @@ void GuiApplication::ResetSettingsUi() {
ui_->main->set_autostart_enabled(enable_autostart_);
ui_->main->set_daemon_enabled(enable_daemon_);
#ifdef _WIN32
ui_->main->set_capture_method_visible(true);
ui_->main->set_capture_method_index(
static_cast<int>(config_center_->GetScreenCaptureMethod()));
ui_->main->set_privacy_setting_visible(true);
ui_->main->set_privacy_on_connect_enabled(
config_center_->IsEnablePrivacyScreen());
@@ -3008,6 +3011,15 @@ void GuiApplication::SaveSettingsFromUi() {
config_center_->SetAutostart(enable_autostart_);
config_center_->SetDaemon(enable_daemon_);
#ifdef _WIN32
if (!HasActiveSession()) {
const auto capture_method = static_cast<ScreenCaptureMethod>(
std::clamp(main->get_capture_method_index(), 0, 3));
if (config_center_->SetScreenCaptureMethod(capture_method) != 0) {
LOG_ERROR("Failed to save screen capture method");
}
}
main->set_capture_method_index(
static_cast<int>(config_center_->GetScreenCaptureMethod()));
if (config_center_->SetPrivacyScreen(main->get_privacy_on_connect_enabled()) !=
0) {
main->set_privacy_on_connect_enabled(
@@ -127,6 +127,9 @@ struct TranslationRow {
u8"стола") \
X(settings, u8"设置", "Settings", u8"Настройки") \
X(language, u8"语言:", "Language:", u8"Язык:") \
X(screen_capture_method, u8"采集方式:", "Capture Method:", \
u8"Способ захвата:") \
X(screen_capture_method_auto, u8"自动", "Auto", u8"Авто") \
X(video_quality, u8"画面质量:", "Video Quality:", u8"Качество видео:") \
X(video_frame_rate, u8"画面采集帧率:", \
"Video Capture Frame Rate:", u8"Частота захвата видео:") \
@@ -78,11 +78,13 @@ int SessionDeviceManager::InitializeScreenCapturer() {
if (!screen_capturer_) {
screen_capturer_ =
static_cast<ScreenCapturer *>(screen_capturer_factory_->Create());
#ifdef _WIN32
if (auto windows = dynamic_cast<ScreenCapturerWin*>(screen_capturer_))
windows->SetPrivacyController(&owner_.privacy_);
#endif
}
#ifdef _WIN32
if (auto windows = dynamic_cast<ScreenCapturerWin*>(screen_capturer_)) {
windows->SetPrivacyController(&owner_.privacy_);
windows->SetCaptureMethod(owner_.config_center_->GetScreenCaptureMethod());
}
#endif
last_frame_time_ = {};
next_frame_deadline_ = {};
@@ -39,6 +39,8 @@ export global UiStrings {
in-out property <string> language: "Language";
in-out property <string> video-quality: "Video quality";
in-out property <string> frame-rate: "Frame rate";
in-out property <string> capture-method: "Capture method";
in-out property <string> capture-method-auto: "Auto";
in-out property <string> adaptation-policy: "Video preference";
in-out property <string> priority-frame-rate: "Frame rate";
in-out property <string> priority-quality: "Quality";
@@ -239,6 +241,8 @@ export component MainWindow inherits Window {
in-out property <int> language-index: 0;
in-out property <int> video-quality-index: 2;
in-out property <int> frame-rate-index: 1;
in property <bool> capture-method-visible: false;
in-out property <int> capture-method-index: 0;
in-out property <int> adaptation-policy-index: 1;
in-out property <int> codec-index: 0;
in-out property <bool> hardware-codec-enabled: true;
@@ -1448,6 +1452,11 @@ export component MainWindow inherits Window {
Text { x: 8px; y: 3px; width: root.compact-language ? 94px : 162px; height: 24px; text: UiStrings.language; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
CompactComboBox { x: root.compact-language ? 106px : 174px; y: 2px; model: ["中文", "English", "Русский"]; current-index <=> root.language-index; }
}
if root.capture-method-visible: Rectangle {
height: 30px;
Text { x: 8px; y: 3px; width: root.compact-language ? 94px : 162px; height: 24px; text: UiStrings.capture-method; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
CompactComboBox { x: root.compact-language ? 106px : 174px; y: 2px; enabled: !root.settings-session-active; model: [UiStrings.capture-method-auto, "DXGI", "WGC", "GDI"]; current-index <=> root.capture-method-index; }
}
if root.privacy-setting-visible: Rectangle {
height: 30px;
Text { x: 8px; y: 3px; width: root.compact-language ? 145px : 212px; height: 24px; text: UiStrings.privacy-on-connect; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
@@ -54,6 +54,9 @@ inline int ApplyMainWindowStrings(
strings.set_language(Text(localization::language[language]));
strings.set_video_quality(Text(localization::video_quality[language]));
strings.set_frame_rate(Text(localization::video_frame_rate[language]));
strings.set_capture_method(Text(localization::screen_capture_method[language]));
strings.set_capture_method_auto(
Text(localization::screen_capture_method_auto[language]));
strings.set_adaptation_policy(
Text(localization::video_adaptation_policy[language]));
strings.set_priority_frame_rate(
@@ -439,9 +439,12 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
return true;
};
// Short-circuiting also keeps the unused WGC plugin unloaded.
if (try_init(std::make_unique<ScreenCapturerDxgi>()) ||
try_init(WgcPluginCapturer::Create()) ||
try_init(std::make_unique<ScreenCapturerGdi>())) {
if ((IsBackendEnabled(ScreenCaptureMethod::Dxgi) &&
try_init(std::make_unique<ScreenCapturerDxgi>())) ||
(IsBackendEnabled(ScreenCaptureMethod::Wgc) &&
try_init(WgcPluginCapturer::Create())) ||
(IsBackendEnabled(ScreenCaptureMethod::Gdi) &&
try_init(std::make_unique<ScreenCapturerGdi>()))) {
LOG_INFO("Windows capturer: using {}", CaptureBackendName(impl_.get()));
BuildCanonicalFromImpl();
monitor_index_.store(0, std::memory_order_relaxed);
@@ -449,7 +452,8 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
return 0;
}
LOG_ERROR("Windows capturer: all implementations failed, ret={}", ret);
LOG_ERROR("Windows capturer: selected capture method {} failed, ret={}",
static_cast<int>(capture_method_), ret);
return -1;
}
@@ -576,6 +580,11 @@ int ScreenCapturerWin::Start(bool show_cursor) {
}
}
if (ret != 0) {
if (capture_method_ != ScreenCaptureMethod::Auto) {
LOG_ERROR("Windows capturer: selected backend {} failed to start (ret={})",
CaptureBackendName(impl_.get()), ret);
return ret;
}
LOG_WARN("Windows capturer: refresh/start failed (ret={}), trying fallback",
ret);
@@ -799,10 +808,12 @@ bool ScreenCapturerWin::RestartCaptureBackendAfterSecureDesktop() {
return true;
}
if (TryStartBackend(std::make_unique<ScreenCapturerDxgi>(),
current_monitor) ||
TryStartBackend(WgcPluginCapturer::Create(), current_monitor) ||
TryStartBackend(std::make_unique<ScreenCapturerGdi>(), current_monitor)) {
if ((IsBackendEnabled(ScreenCaptureMethod::Dxgi) &&
TryStartBackend(std::make_unique<ScreenCapturerDxgi>(), current_monitor)) ||
(IsBackendEnabled(ScreenCaptureMethod::Wgc) &&
TryStartBackend(WgcPluginCapturer::Create(), current_monitor)) ||
(IsBackendEnabled(ScreenCaptureMethod::Gdi) &&
TryStartBackend(std::make_unique<ScreenCapturerGdi>(), current_monitor))) {
return true;
}
@@ -20,6 +20,7 @@
#include <vector>
#include "screen_capturer.h"
#include "screen_capture_method.h"
#include "privacy_controller.h"
namespace crossdesk {
@@ -45,9 +46,16 @@ class ScreenCapturerWin : public ScreenCapturer {
std::vector<DisplayInfo> GetDisplayInfoList() override;
void SetPrivacyController(PrivacyController* privacy) { privacy_ = privacy; }
// Set before Init(), while capture is stopped.
void SetCaptureMethod(ScreenCaptureMethod method) { capture_method_ = method; }
private:
std::unique_ptr<ScreenCapturer> impl_;
ScreenCaptureMethod capture_method_ = ScreenCaptureMethod::Auto;
bool IsBackendEnabled(ScreenCaptureMethod method) const {
return capture_method_ == ScreenCaptureMethod::Auto ||
capture_method_ == method;
}
PrivacyController* privacy_ = nullptr;
void NotifyPrivacyCapture(bool running);
int fps_ = 60;
@@ -0,0 +1,22 @@
/*
* @Author: DI JUNKUN
* @Date: 2026-09-11
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _SCREEN_CAPTURE_METHOD_H_
#define _SCREEN_CAPTURE_METHOD_H_
namespace crossdesk {
// Persisted values; keep these in the same order as the settings choices.
enum class ScreenCaptureMethod { Auto = 0, Dxgi = 1, Wgc = 2, Gdi = 3 };
inline bool IsValidScreenCaptureMethod(long value) {
return value >= static_cast<long>(ScreenCaptureMethod::Auto) &&
value <= static_cast<long>(ScreenCaptureMethod::Gdi);
}
} // namespace crossdesk
#endif
+2 -1
View File
@@ -298,7 +298,8 @@ function setup_targets()
set_kind("object")
add_deps("rd_log", "autostart")
add_files("apps/desktop/src/config_center/*.cpp")
add_includedirs("apps/desktop/src/config_center", {public = true})
add_includedirs("apps/desktop/src", "apps/desktop/src/config_center",
{public = true})
target("assets")
set_kind("headeronly")