[feat] add display selection method for Windows platform

This commit is contained in:
dijunkun
2025-05-08 17:40:14 +08:00
parent e2a469ed65
commit dc05f2405f
5 changed files with 121 additions and 9 deletions

View File

@@ -13,6 +13,17 @@ class ScreenCapturer {
public: public:
typedef std::function<void(unsigned char*, int, int, int)> cb_desktop_data; typedef std::function<void(unsigned char*, int, int, int)> cb_desktop_data;
class DisplayInfo {
public:
void* handle = nullptr;
std::string name = "";
bool is_primary = false;
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
};
public: public:
virtual ~ScreenCapturer() {} virtual ~ScreenCapturer() {}
@@ -21,6 +32,8 @@ class ScreenCapturer {
virtual int Destroy() = 0; virtual int Destroy() = 0;
virtual int Start() = 0; virtual int Start() = 0;
virtual int Stop() = 0; virtual int Stop() = 0;
virtual std::vector<DisplayInfo> GetDisplayList() = 0;
}; };
#endif #endif

View File

@@ -8,17 +8,36 @@
#include <iostream> #include <iostream>
#include "libyuv.h" #include "libyuv.h"
#include "rd_log.h"
static std::vector<ScreenCapturer::DisplayInfo> gs_display_list;
std::string WideToUtf8(const wchar_t *wideStr) {
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, nullptr, 0,
nullptr, nullptr);
std::string result(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, &result[0], size_needed, nullptr,
nullptr);
result.pop_back();
return result;
}
BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, [[maybe_unused]] HDC hdc, BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, [[maybe_unused]] HDC hdc,
[[maybe_unused]] LPRECT lprc, LPARAM data) { [[maybe_unused]] LPRECT lprc, LPARAM data) {
MONITORINFOEX info_ex; MONITORINFOEX monitor_info_;
info_ex.cbSize = sizeof(MONITORINFOEX); monitor_info_.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hmonitor, &info_ex); if (GetMonitorInfo(hmonitor, &monitor_info_)) {
gs_display_list.push_back(
{(void *)hmonitor, WideToUtf8(monitor_info_.szDevice),
(monitor_info_.dwFlags & MONITORINFOF_PRIMARY) ? true : false,
monitor_info_.rcMonitor.left, monitor_info_.rcMonitor.top,
monitor_info_.rcMonitor.right, monitor_info_.rcMonitor.bottom});
}
if (info_ex.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER) return true; if (monitor_info_.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER) return true;
if (info_ex.dwFlags & MONITORINFOF_PRIMARY) { if (monitor_info_.dwFlags & MONITORINFOF_PRIMARY) {
*(HMONITOR *)data = hmonitor; *(HMONITOR *)data = hmonitor;
} }
@@ -28,12 +47,13 @@ BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, [[maybe_unused]] HDC hdc,
HMONITOR GetPrimaryMonitor() { HMONITOR GetPrimaryMonitor() {
HMONITOR hmonitor = nullptr; HMONITOR hmonitor = nullptr;
gs_display_list.clear();
::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&hmonitor); ::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&hmonitor);
return hmonitor; return hmonitor;
} }
ScreenCapturerWgc::ScreenCapturerWgc() {} ScreenCapturerWgc::ScreenCapturerWgc() : monitor_(nullptr) {}
ScreenCapturerWgc::~ScreenCapturerWgc() { ScreenCapturerWgc::~ScreenCapturerWgc() {
Stop(); Stop();
@@ -89,7 +109,17 @@ int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
session_->RegisterObserver(this); session_->RegisterObserver(this);
error = session_->Initialize(GetPrimaryMonitor()); monitor_ = GetPrimaryMonitor();
display_list_ = gs_display_list;
for (const auto &display : display_list_) {
LOG_INFO("Display Name: {}, Is Primary: {}, Bounds: ({}, {}) - ({}, {})",
display.name, (display.is_primary ? "Yes" : "No"), display.left,
display.top, display.right, display.bottom);
}
error = session_->Initialize(monitor_);
_inited = true; _inited = true;
} while (0); } while (0);
@@ -139,6 +169,44 @@ int ScreenCapturerWgc::Stop() {
return 0; return 0;
} }
int ScreenCapturerWgc::SwitchTo(int monitor_index) {
if (!_inited) return -1;
if (monitor_index >= display_list_.size()) {
LOG_ERROR("Invalid monitor index: {}", monitor_index);
return -3;
}
LOG_INFO("Switching to monitor {}:{}", monitor_index,
display_list_[monitor_index].name);
Stop();
if (session_) {
session_->Release();
delete session_;
session_ = nullptr;
}
session_ = new WgcSessionImpl();
if (!session_) {
LOG_ERROR("Failed to create new WgcSessionImpl.");
return -4;
}
session_->RegisterObserver(this);
int err = session_->Initialize((HMONITOR)display_list_[monitor_index].handle);
if (err != 0) {
LOG_ERROR("Failed to re-initialize session on new monitor.");
return -5;
}
monitor_ = (HMONITOR)display_list_[monitor_index].handle;
_inited = true;
return Start();
}
void ConvertABGRtoBGRA(const uint8_t *abgr_data, uint8_t *bgra_data, int width, void ConvertABGRtoBGRA(const uint8_t *abgr_data, uint8_t *bgra_data, int width,
int height, int abgr_stride, int bgra_stride) { int height, int abgr_stride, int bgra_stride) {
for (int i = 0; i < height; ++i) { for (int i = 0; i < height; ++i) {

View File

@@ -5,6 +5,7 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include <thread> #include <thread>
#include <vector>
#include "screen_capturer.h" #include "screen_capturer.h"
#include "wgc_session.h" #include "wgc_session.h"
@@ -27,11 +28,20 @@ class ScreenCapturerWgc : public ScreenCapturer,
int Pause(); int Pause();
int Resume(); int Resume();
std::vector<DisplayInfo> GetDisplayList() { return display_list_; }
int SwitchTo(int monitor_index);
void OnFrame(const WgcSession::wgc_session_frame &frame); void OnFrame(const WgcSession::wgc_session_frame &frame);
protected: protected:
void CleanUp(); void CleanUp();
private:
HMONITOR monitor_;
MONITORINFOEX monitor_info_;
std::vector<DisplayInfo> display_list_;
private: private:
WgcSession *session_ = nullptr; WgcSession *session_ = nullptr;

View File

@@ -33,7 +33,6 @@ class WgcSession {
virtual int Pause() = 0; virtual int Pause() = 0;
virtual int Resume() = 0; virtual int Resume() = 0;
protected:
virtual ~WgcSession(){}; virtual ~WgcSession(){};
}; };

View File

@@ -80,6 +80,28 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
2.0f); 2.0f);
} }
// const char* items[] = {"1", "2", "3"};
// static int item_selected_idx = 0;
// ImGui::Text("Display:");
// ImGui::SameLine();
// ImGui::SetNextItemWidth(25.0f);
// ImGuiComboFlags flags =
// ImGuiComboFlags_HeightSmall | ImGuiComboFlags_NoArrowButton;
// const char* combo_preview_value = items[item_selected_idx];
// ImGui::SetWindowFontScale(1.2f);
// if (ImGui::BeginCombo("##display", combo_preview_value, flags)) {
// ImGui::SetWindowFontScale(0.5f);
// for (int n = 0; n < IM_ARRAYSIZE(items); n++) {
// const bool is_selected = (item_selected_idx == n);
// if (ImGui::Selectable(items[n], is_selected)) item_selected_idx = n;
// if (is_selected) ImGui::SetItemDefaultFocus();
// }
// ImGui::SetWindowFontScale(1.0f);
// ImGui::EndCombo();
// }
// ImGui::SetWindowFontScale(1.0f);
ImGui::SameLine(); ImGui::SameLine();
// audio capture button // audio capture button
float disable_audio_x = ImGui::GetCursorScreenPos().x + 4; float disable_audio_x = ImGui::GetCursorScreenPos().x + 4;