rustdesk/libs/scrap/src/x11/capturer.rs
21pages 534bfad50f opt codec
1. use src width/height to convert yuv
2. align dst yuv to avoid illegal memory access
3. init yuvfmt when new codec
4. move remote reset calls from empty conns judge to emtpy remote conns
   judge

Signed-off-by: 21pages <pages21@163.com>
2023-11-03 11:52:41 +08:00

122 lines
3.1 KiB
Rust

use std::{io, ptr, slice};
use hbb_common::libc;
use crate::Frame;
use super::ffi::*;
use super::Display;
pub struct Capturer {
display: Display,
shmid: i32,
xcbid: u32,
buffer: *const u8,
size: usize,
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl Capturer {
pub fn new(display: Display) -> io::Result<Capturer> {
// Calculate dimensions.
let pixel_width = 4;
let rect = display.rect();
let size = (rect.w as usize) * (rect.h as usize) * pixel_width;
// Create a shared memory segment.
let shmid = unsafe {
libc::shmget(
libc::IPC_PRIVATE,
size,
// Everyone can do anything.
libc::IPC_CREAT | 0o777,
)
};
if shmid == -1 {
return Err(io::Error::last_os_error());
}
// Attach the segment to a readable address.
let buffer = unsafe { libc::shmat(shmid, ptr::null(), libc::SHM_RDONLY) } as *mut u8;
if buffer as isize == -1 {
return Err(io::Error::last_os_error());
}
// Attach the segment to XCB.
let server = display.server().raw();
let xcbid = unsafe { xcb_generate_id(server) };
unsafe {
xcb_shm_attach(
server,
xcbid,
shmid as u32,
0, // False, i.e. not read-only.
);
}
let c = Capturer {
display,
shmid,
xcbid,
buffer,
size,
saved_raw_data: Vec::new(),
};
Ok(c)
}
pub fn display(&self) -> &Display {
&self.display
}
fn get_image(&self) {
let rect = self.display.rect();
unsafe {
let request = xcb_shm_get_image_unchecked(
self.display.server().raw(),
self.display.root(),
rect.x,
rect.y,
rect.w,
rect.h,
!0,
XCB_IMAGE_FORMAT_Z_PIXMAP,
self.xcbid,
0,
);
let response =
xcb_shm_get_image_reply(self.display.server().raw(), request, ptr::null_mut());
libc::free(response as *mut _);
}
}
pub fn frame<'b>(&'b mut self) -> std::io::Result<Frame> {
self.get_image();
let result = unsafe { slice::from_raw_parts(self.buffer, self.size) };
crate::would_block_if_equal(&mut self.saved_raw_data, result)?;
Ok(
Frame::new(result, crate::Pixfmt::BGRA, self.display.w(), self.display.h())
)
}
}
impl Drop for Capturer {
fn drop(&mut self) {
unsafe {
// Detach segment from XCB.
xcb_shm_detach(self.display.server().raw(), self.xcbid);
// Detach segment from our space.
libc::shmdt(self.buffer as *mut _);
// Destroy the shared memory segment.
libc::shmctl(self.shmid, libc::IPC_RMID, ptr::null_mut());
}
}
}