[fix] select the correct X11 pixel format conversion to prevent green-tinted screen capture on ubuntu

This commit is contained in:
dijunkun
2026-04-27 17:57:11 +08:00
parent 37b9badb2a
commit 71bce08549
2 changed files with 35 additions and 24 deletions
@@ -122,8 +122,7 @@ int ScreenCapturerX11::Init(const int fps, cb_desktop_data cb) {
height_ = attr.height; height_ = attr.height;
if ((width_ & 1) != 0 || (height_ & 1) != 0) { if ((width_ & 1) != 0 || (height_ & 1) != 0) {
LOG_WARN( LOG_WARN("X11 root size {}x{} is not even, aligning down to {}x{} for NV12",
"X11 root size {}x{} is not even, aligning down to {}x{} for NV12",
width_, height_, width_ & ~1, height_ & ~1); width_, height_, width_ & ~1, height_ & ~1);
width_ &= ~1; width_ &= ~1;
height_ &= ~1; height_ &= ~1;
@@ -183,8 +182,9 @@ int ScreenCapturerX11::Start(bool show_cursor) {
OnFrame(); OnFrame();
} }
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( const auto elapsed =
clock::now() - frame_start); std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() -
frame_start);
if (elapsed < frame_interval) { if (elapsed < frame_interval) {
std::this_thread::sleep_for(frame_interval - elapsed); std::this_thread::sleep_for(frame_interval - elapsed);
} }
@@ -282,20 +282,16 @@ void ScreenCapturerX11::OnFrame() {
} }
} }
bool needs_copy = image->bytes_per_line != width_ * 4; if (image->bits_per_pixel != 32 || image->bytes_per_line <= 0) {
std::vector<uint8_t> argb_buf; LOG_WARN(
uint8_t* src_argb = nullptr; "Unsupported X11 image layout: bits_per_pixel={}, bytes_per_line={}",
image->bits_per_pixel, image->bytes_per_line);
XDestroyImage(image);
return;
}
if (needs_copy) { const uint8_t* src_argb = reinterpret_cast<const uint8_t*>(image->data);
argb_buf.resize(width_ * height_ * 4); const int src_stride_argb = image->bytes_per_line;
for (int y = 0; y < height_; ++y) {
memcpy(&argb_buf[y * width_ * 4], image->data + y * image->bytes_per_line,
width_ * 4);
}
src_argb = argb_buf.data();
} else {
src_argb = reinterpret_cast<uint8_t*>(image->data);
}
const size_t y_size = const size_t y_size =
static_cast<size_t>(width_) * static_cast<size_t>(height_); static_cast<size_t>(width_) * static_cast<size_t>(height_);
@@ -307,8 +303,20 @@ void ScreenCapturerX11::OnFrame() {
uv_plane_.resize(uv_size); uv_plane_.resize(uv_size);
} }
libyuv::ARGBToNV12(src_argb, width_ * 4, y_plane_.data(), width_, const int convert_ret =
uv_plane_.data(), width_, width_, height_); use_abgr_to_nv12_
? libyuv::ABGRToNV12(src_argb, src_stride_argb, y_plane_.data(),
width_, uv_plane_.data(), width_, width_,
height_)
: libyuv::ARGBToNV12(src_argb, src_stride_argb, y_plane_.data(),
width_, uv_plane_.data(), width_, width_,
height_);
if (convert_ret != 0) {
LOG_WARN("X11 {} failed: {}",
use_abgr_to_nv12_ ? "ABGRToNV12" : "ARGBToNV12", convert_ret);
XDestroyImage(image);
return;
}
std::vector<uint8_t> nv12; std::vector<uint8_t> nv12;
nv12.reserve(y_plane_.size() + uv_plane_.size()); nv12.reserve(y_plane_.size() + uv_plane_.size());
@@ -416,16 +424,18 @@ bool ScreenCapturerX11::ProbeCapture() {
x11_error = trap.SyncAndGetError(); x11_error = trap.SyncAndGetError();
} }
if (probe_image) {
XDestroyImage(probe_image);
}
if (x11_error != 0 || !probe_image) { if (x11_error != 0 || !probe_image) {
LOG_WARN("X11 probe XGetImage failed: x11_error={}, image={}", x11_error, LOG_WARN("X11 probe XGetImage failed: x11_error={}, image={}", x11_error,
probe_image ? "valid" : "null"); probe_image ? "valid" : "null");
return false; return false;
} }
const bool red_in_low_byte = (probe_image->red_mask & 0x000000FFu) != 0;
const bool blue_in_low_byte = (probe_image->blue_mask & 0x000000FFu) != 0;
use_abgr_to_nv12_ = red_in_low_byte && !blue_in_low_byte;
XDestroyImage(probe_image);
return true; return true;
} }
} // namespace crossdesk } // namespace crossdesk
@@ -71,6 +71,7 @@ class ScreenCapturerX11 : public ScreenCapturer {
cb_desktop_data callback_; cb_desktop_data callback_;
std::vector<DisplayInfo> display_info_list_; std::vector<DisplayInfo> display_info_list_;
int capture_error_count_ = 0; int capture_error_count_ = 0;
bool use_abgr_to_nv12_ = false;
std::vector<uint8_t> y_plane_; std::vector<uint8_t> y_plane_;
std::vector<uint8_t> uv_plane_; std::vector<uint8_t> uv_plane_;