[feat] enable screen switch on Linux platform

This commit is contained in:
dijunkun
2025-05-29 18:09:34 +08:00
parent d72c6d9df7
commit 094204361c
8 changed files with 111 additions and 52 deletions

View File

@@ -18,6 +18,34 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
}
root_ = DefaultRootWindow(display_);
screen_res_ = XRRGetScreenResources(display_, root_);
if (!screen_res_) {
LOG_ERROR("Failed to get screen resources");
XCloseDisplay(display_);
return 1;
}
for (int i = 0; i < screen_res_->noutput; ++i) {
RROutput output = screen_res_->outputs[i];
XRROutputInfo* output_info =
XRRGetOutputInfo(display_, screen_res_, output);
if (output_info->connection == RR_Connected && output_info->crtc != 0) {
XRRCrtcInfo* crtc_info =
XRRGetCrtcInfo(display_, screen_res_, output_info->crtc);
display_info_list_.push_back(
DisplayInfo((void*)display_, output_info->name, true, crtc_info->x,
crtc_info->y, crtc_info->width, crtc_info->height));
XRRFreeCrtcInfo(crtc_info);
}
if (output_info) {
XRRFreeOutputInfo(output_info);
}
}
XWindowAttributes attr;
XGetWindowAttributes(display_, root_, &attr);
@@ -40,7 +68,19 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
int ScreenCapturerX11::Destroy() {
Stop();
CleanUp();
y_plane_.clear();
uv_plane_.clear();
if (screen_res_) {
XRRFreeScreenResources(screen_res_);
screen_res_ = nullptr;
}
if (display_) {
XCloseDisplay(display_);
display_ = nullptr;
}
return 0;
}
@@ -63,21 +103,43 @@ int ScreenCapturerX11::Stop() {
return 0;
}
int ScreenCapturerX11::Pause() {
int ScreenCapturerX11::Pause(int monitor_index) {
paused_ = true;
return 0;
}
int ScreenCapturerX11::Resume() {
int ScreenCapturerX11::Resume(int monitor_index) {
paused_ = false;
return 0;
}
void ScreenCapturerX11::OnFrame() {
if (!display_) return;
int ScreenCapturerX11::SwitchTo(int monitor_index) {
monitor_index_ = monitor_index;
return 0;
}
XImage* image =
XGetImage(display_, root_, 0, 0, width_, height_, AllPlanes, ZPixmap);
std::vector<DisplayInfo> ScreenCapturerX11::GetDisplayInfoList() {
return display_info_list_;
}
void ScreenCapturerX11::OnFrame() {
if (!display_) {
LOG_ERROR("Display is not initialized");
return;
}
if (monitor_index_ < 0 || monitor_index_ >= display_info_list_.size()) {
LOG_ERROR("Invalid monitor index: {}", monitor_index_.load());
return;
}
left_ = display_info_list_[monitor_index_].left;
top_ = display_info_list_[monitor_index_].top;
width_ = display_info_list_[monitor_index_].width;
height_ = display_info_list_[monitor_index_].height;
XImage* image = XGetImage(display_, root_, left_, top_, width_, height_,
AllPlanes, ZPixmap);
if (!image) return;
bool needs_copy = image->bytes_per_line != width_ * 4;
@@ -104,15 +166,9 @@ void ScreenCapturerX11::OnFrame() {
nv12.insert(nv12.end(), uv_plane_.begin(), uv_plane_.end());
if (callback_) {
callback_(nv12.data(), width_ * height_ * 3 / 2, width_, height_, "");
callback_(nv12.data(), width_ * height_ * 3 / 2, width_, height_,
display_info_list_[monitor_index_].name.c_str());
}
XDestroyImage(image);
}
void ScreenCapturerX11::CleanUp() {
if (display_) {
XCloseDisplay(display_);
display_ = nullptr;
}
}

View File

@@ -9,6 +9,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xrandr.h>
#include <atomic>
#include <cstring>
@@ -17,17 +18,7 @@
#include <thread>
#include <vector>
class ScreenCapturer {
public:
typedef std::function<void(unsigned char*, int width, int height, int stride)>
cb_desktop_data;
virtual ~ScreenCapturer() {}
virtual int Init(const int fps, cb_desktop_data cb) = 0;
virtual int Destroy() = 0;
virtual int Start() = 0;
virtual int Stop() = 0;
};
#include "screen_capturer.h"
class ScreenCapturerX11 : public ScreenCapturer {
public:
@@ -40,24 +31,30 @@ class ScreenCapturerX11 : public ScreenCapturer {
int Start() override;
int Stop() override;
int Pause();
int Resume();
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
int SwitchTo(int monitor_index) override;
std::vector<DisplayInfo> GetDisplayInfoList() override;
void OnFrame();
protected:
void CleanUp();
private:
Display* display_ = nullptr;
Window root_ = 0;
XRRScreenResources* screen_res_ = nullptr;
int left_ = 0;
int top_ = 0;
int width_ = 0;
int height_ = 0;
std::thread thread_;
std::atomic<bool> running_{false};
std::atomic<bool> paused_{false};
std::atomic<int> monitor_index_{0};
int fps_ = 30;
cb_desktop_data callback_;
std::vector<DisplayInfo> display_info_list_;
// 缓冲区
std::vector<uint8_t> y_plane_;

View File

@@ -22,13 +22,12 @@ class ScreenCapturerSck : public ScreenCapturer {
~ScreenCapturerSck();
public:
virtual int Init(const int fps, cb_desktop_data cb) override;
virtual int Destroy() override;
virtual int Start() override;
virtual int Stop() override;
int Init(const int fps, cb_desktop_data cb) override;
int Destroy() override;
int Start() override;
int Stop() override;
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
int SwitchTo(int monitor_index) override;

View File

@@ -20,13 +20,13 @@ class ScreenCapturerWgc : public ScreenCapturer,
public:
bool IsWgcSupported();
virtual int Init(const int fps, cb_desktop_data cb) override;
virtual int Destroy() override;
virtual int Start() override;
virtual int Stop() override;
int Init(const int fps, cb_desktop_data cb) override;
int Destroy() override;
int Start() override;
int Stop() override;
virtual int Pause(int monitor_index) override;
virtual int Resume(int monitor_index) override;
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
std::vector<DisplayInfo> GetDisplayInfoList() { return display_info_list_; }