This commit is contained in:
open-trade 2021-12-23 17:44:44 +08:00
parent 252d3cb797
commit a30aaebc72
5 changed files with 79 additions and 48 deletions

View File

@ -9,8 +9,8 @@ extern "C" {
src_stride_argb: c_int, src_stride_argb: c_int,
dst_argb: *mut u8, dst_argb: *mut u8,
dst_stride_argb: c_int, dst_stride_argb: c_int,
width: c_int, src_width: c_int,
height: c_int, src_height: c_int,
mode: c_int, mode: c_int,
) -> c_int; ) -> c_int;

View File

@ -3,32 +3,20 @@ pub mod gdi;
pub use gdi::CapturerGDI; pub use gdi::CapturerGDI;
use winapi::{ use winapi::{
shared::dxgi::{ shared::{
CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIResource, IDXGISurface, dxgi::*,
IID_IDXGIFactory1, IID_IDXGISurface, DXGI_MAP_READ, DXGI_OUTPUT_DESC, dxgi1_2::*,
DXGI_RESOURCE_PRIORITY_MAXIMUM, dxgitype::*,
minwindef::{DWORD, FALSE, TRUE, UINT},
ntdef::LONG,
windef::HMONITOR,
winerror::*,
// dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE},
}, },
shared::dxgi1_2::IDXGIOutputDuplication, um::{
// shared::dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE}, d3d11::*, d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, unknwnbase::IUnknown, wingdi::*,
shared::dxgi1_2::{IDXGIOutput1, IID_IDXGIOutput1}, winnt::HRESULT, winuser::*,
shared::dxgitype::DXGI_MODE_ROTATION,
shared::minwindef::{DWORD, FALSE, TRUE, UINT},
shared::ntdef::LONG,
shared::windef::HMONITOR,
shared::winerror::{
DXGI_ERROR_ACCESS_LOST, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
DXGI_ERROR_SESSION_DISCONNECTED, DXGI_ERROR_UNSUPPORTED, DXGI_ERROR_WAIT_TIMEOUT,
E_ACCESSDENIED, E_INVALIDARG, S_OK,
}, },
um::d3d11::{
D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, IID_ID3D11Texture2D,
D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING,
},
um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
um::unknwnbase::IUnknown,
um::wingdi::*,
um::winnt::HRESULT,
um::winuser::*,
}; };
pub struct ComPtr<T>(*mut T); pub struct ComPtr<T>(*mut T);
@ -54,12 +42,11 @@ pub struct Capturer {
duplication: ComPtr<IDXGIOutputDuplication>, duplication: ComPtr<IDXGIOutputDuplication>,
fastlane: bool, fastlane: bool,
surface: ComPtr<IDXGISurface>, surface: ComPtr<IDXGISurface>,
data: *const u8,
len: usize,
width: usize, width: usize,
height: usize, height: usize,
use_yuv: bool, use_yuv: bool,
yuv: Vec<u8>, yuv: Vec<u8>,
rotated: Vec<u8>,
gdi_capturer: Option<CapturerGDI>, gdi_capturer: Option<CapturerGDI>,
gdi_buffer: Vec<u8>, gdi_buffer: Vec<u8>,
} }
@ -158,10 +145,9 @@ impl Capturer {
width: display.width() as usize, width: display.width() as usize,
height: display.height() as usize, height: display.height() as usize,
display, display,
data: ptr::null(),
len: 0,
use_yuv, use_yuv,
yuv: Vec::new(), yuv: Vec::new(),
rotated: Vec::new(),
gdi_capturer, gdi_capturer,
gdi_buffer: Vec::new(), gdi_buffer: Vec::new(),
}) })
@ -181,10 +167,9 @@ impl Capturer {
self.gdi_capturer.take(); self.gdi_capturer.take();
} }
unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<()> { unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<(*const u8, i32)> {
let mut frame = ptr::null_mut(); let mut frame = ptr::null_mut();
let mut info = mem::MaybeUninit::uninit().assume_init(); let mut info = mem::MaybeUninit::uninit().assume_init();
self.data = ptr::null();
wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?; wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?;
let frame = ComPtr(frame); let frame = ComPtr(frame);
@ -200,9 +185,7 @@ impl Capturer {
self.surface = ComPtr(self.ohgodwhat(frame.0)?); self.surface = ComPtr(self.ohgodwhat(frame.0)?);
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?; wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
} }
self.data = rect.pBits; Ok((rect.pBits, rect.Pitch))
self.len = self.height * rect.Pitch as usize;
Ok(())
} }
// copy from GPU memory to system memory // copy from GPU memory to system memory
@ -257,8 +240,42 @@ impl Capturer {
} }
} else { } else {
self.unmap(); self.unmap();
self.load_frame(timeout)?; let r = self.load_frame(timeout)?;
slice::from_raw_parts(self.data, self.len) let rotate = match self.display.rotation() {
DXGI_MODE_ROTATION_IDENTITY | DXGI_MODE_ROTATION_UNSPECIFIED => 0,
DXGI_MODE_ROTATION_ROTATE90 => 90,
DXGI_MODE_ROTATION_ROTATE180 => 180,
DXGI_MODE_ROTATION_ROTATE270 => 270,
_ => {
return Err(io::Error::new(
io::ErrorKind::Other,
"Unknown roration".to_string(),
));
}
};
if rotate == 0 {
slice::from_raw_parts(r.0, r.1 as usize * self.height)
} else {
self.rotated.resize(self.width * self.height * 4, 0);
crate::common::ARGBRotate(
r.0,
r.1,
self.rotated.as_mut_ptr(),
4 * self.width as i32,
if rotate == 180 {
self.width
} else {
self.height
} as _,
if rotate != 180 {
self.width
} else {
self.height
} as _,
rotate,
);
&self.rotated[..]
}
} }
}; };
Ok({ Ok({
@ -478,7 +495,10 @@ pub struct Display {
gdi: bool, gdi: bool,
} }
// https://github.com/dchapyshev/aspia/blob/59233c5d01a4d03ed6de19b03ce77d61a6facf79/source/base/desktop/win/screen_capture_utils.cc // optimized for updated region
// https://github.com/dchapyshev/aspia/blob/master/source/base/desktop/win/dxgi_output_duplicator.cc
// rotation
// https://github.com/bryal/dxgcap-rs/blob/master/src/lib.rs
impl Display { impl Display {
pub fn width(&self) -> LONG { pub fn width(&self) -> LONG {

View File

@ -95,7 +95,10 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc<Mutex<String>>>)
let side = if old.is_none() { "host" } else { "client" }; let side = if old.is_none() { "host" } else { "client" };
let old = if let Some(old) = old { old } else { &CONTENT }; let old = if let Some(old) = old { old } else { &CONTENT };
*old.lock().unwrap() = content.clone(); *old.lock().unwrap() = content.clone();
allow_err!(ctx.set_text(content)); if !content.is_empty() {
// empty content make ctx.set_text crash
allow_err!(ctx.set_text(content));
}
log::debug!("{} updated on {}", CLIPBOARD_NAME, side); log::debug!("{} updated on {}", CLIPBOARD_NAME, side);
} }
Err(err) => { Err(err) => {
@ -240,7 +243,8 @@ async fn test_nat_type_() -> ResultType<bool> {
let rendezvous_server = get_rendezvous_server(100).await; let rendezvous_server = get_rendezvous_server(100).await;
let server1 = rendezvous_server; let server1 = rendezvous_server;
let mut server2 = server1; let mut server2 = server1;
if server1.port() == 0 { // offline if server1.port() == 0 {
// offline
// avoid overflow crash // avoid overflow crash
bail!("Offline"); bail!("Offline");
} }

View File

@ -97,8 +97,12 @@ mod listen {
fn trigger(ctx: &mut ClipboardContext) { fn trigger(ctx: &mut ClipboardContext) {
let _ = match ctx.get_text() { let _ = match ctx.get_text() {
Ok(text) => ctx.set_text(text), Ok(text) => {
Err(_) => ctx.set_text(Default::default()), if !text.is_empty() {
ctx.set_text(text).ok();
}
}
Err(_) => {}
}; };
} }
} }

View File

@ -220,7 +220,7 @@ fn run(sp: GenericService) -> ResultType<()> {
let start = time::Instant::now(); let start = time::Instant::now();
let mut last_check_displays = time::Instant::now(); let mut last_check_displays = time::Instant::now();
#[cfg(windows)] #[cfg(windows)]
let mut try_gdi = true; let mut try_gdi = 1;
#[cfg(windows)] #[cfg(windows)]
log::info!("gdi: {}", c.is_gdi()); log::info!("gdi: {}", c.is_gdi());
while sp.ok() { while sp.ok() {
@ -261,7 +261,7 @@ fn run(sp: GenericService) -> ResultType<()> {
frame_controller.set_send(now, send_conn_ids); frame_controller.set_send(now, send_conn_ids);
#[cfg(windows)] #[cfg(windows)]
{ {
try_gdi = false; try_gdi = 0;
} }
} }
Err(ref e) if e.kind() == WouldBlock => { Err(ref e) if e.kind() == WouldBlock => {
@ -271,10 +271,13 @@ fn run(sp: GenericService) -> ResultType<()> {
wait = 0 wait = 0
} }
#[cfg(windows)] #[cfg(windows)]
if try_gdi && !c.is_gdi() { if try_gdi > 0 && !c.is_gdi() {
c.set_gdi(); if try_gdi > 3 {
try_gdi = false; c.set_gdi();
log::info!("No image, fall back to gdi"); try_gdi = 0;
log::info!("No image, fall back to gdi");
}
try_gdi += 1;
} }
continue; continue;
} }