diff --git a/libs/scrap/src/common/mod.rs b/libs/scrap/src/common/mod.rs index 47e60f1a2..78e328f5b 100644 --- a/libs/scrap/src/common/mod.rs +++ b/libs/scrap/src/common/mod.rs @@ -30,3 +30,16 @@ pub use self::convert::*; pub const STRIDE_ALIGN: usize = 64; // commonly used in libvpx vpx_img_alloc caller mod vpx; + +#[inline] +pub fn would_block_if_equal(old: &mut Vec, b: &[u8]) -> std::io::Result<()> { + let b = unsafe { + std::slice::from_raw_parts::(b.as_ptr() as _, b.len() / 16) + }; + if b == &old[..] { + return Err(std::io::ErrorKind::WouldBlock.into()); + } + old.resize(b.len(), 0); + old.copy_from_slice(b); + Ok(()) +} diff --git a/libs/scrap/src/common/quartz.rs b/libs/scrap/src/common/quartz.rs index 3eb1d49f9..b35b56b61 100644 --- a/libs/scrap/src/common/quartz.rs +++ b/libs/scrap/src/common/quartz.rs @@ -8,6 +8,7 @@ pub struct Capturer { frame: Arc>>, use_yuv: bool, i420: Vec, + saved_raw_data: Vec, // for faster compare and copy } impl Capturer { @@ -38,6 +39,7 @@ impl Capturer { frame, use_yuv, i420: Vec::new(), + saved_raw_data: Vec::new(), }) } @@ -57,6 +59,7 @@ impl Capturer { match frame { Some(mut frame) => { + crate::would_block_if_equal(&mut self.saved_raw_data, frame.inner())?; if self.use_yuv { frame.nv12_to_i420(self.width(), self.height(), &mut self.i420); } diff --git a/libs/scrap/src/common/x11.rs b/libs/scrap/src/common/x11.rs index e9640cbbf..f8217e3b7 100644 --- a/libs/scrap/src/common/x11.rs +++ b/libs/scrap/src/common/x11.rs @@ -17,7 +17,7 @@ impl Capturer { } pub fn frame<'a>(&'a mut self, _timeout_ms: u32) -> io::Result> { - Ok(Frame(self.0.frame())) + Ok(Frame(self.0.frame()?)) } } diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index 677811b93..0d343962d 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -49,6 +49,7 @@ pub struct Capturer { rotated: Vec, gdi_capturer: Option, gdi_buffer: Vec, + saved_raw_data: Vec, // for faster compare and copy } impl Capturer { @@ -150,6 +151,7 @@ impl Capturer { rotated: Vec::new(), gdi_capturer, gdi_buffer: Vec::new(), + saved_raw_data: Vec::new(), }) } @@ -233,7 +235,13 @@ impl Capturer { let result = { if let Some(gdi_capturer) = &self.gdi_capturer { match gdi_capturer.frame(&mut self.gdi_buffer) { - Ok(_) => &self.gdi_buffer, + Ok(_) => { + crate::would_block_if_equal( + &mut self.saved_raw_data, + &self.gdi_buffer, + )?; + &self.gdi_buffer + } Err(err) => { return Err(io::Error::new(io::ErrorKind::Other, err.to_string())); } diff --git a/libs/scrap/src/quartz/frame.rs b/libs/scrap/src/quartz/frame.rs index 61dd4b50d..9cdb2a90a 100644 --- a/libs/scrap/src/quartz/frame.rs +++ b/libs/scrap/src/quartz/frame.rs @@ -29,10 +29,12 @@ impl Frame { } } + #[inline] + pub fn inner(&self) -> &[u8] { + self.inner + } + pub fn nv12_to_i420<'a>(&'a mut self, w: usize, h: usize, i420: &'a mut Vec) { - if self.inner.is_empty() { - return; - } unsafe { let plane0 = IOSurfaceGetBaseAddressOfPlane(self.surface, 0); let stride0 = IOSurfaceGetBytesPerRowOfPlane(self.surface, 0); diff --git a/libs/scrap/src/x11/capturer.rs b/libs/scrap/src/x11/capturer.rs index d989660f9..890b9db63 100644 --- a/libs/scrap/src/x11/capturer.rs +++ b/libs/scrap/src/x11/capturer.rs @@ -14,6 +14,7 @@ pub struct Capturer { size: usize, use_yuv: bool, yuv: Vec, + saved_raw_data: Vec, // for faster compare and copy } impl Capturer { @@ -68,6 +69,7 @@ impl Capturer { size, use_yuv, yuv: Vec::new(), + saved_raw_data: Vec::new(), }; Ok(c) } @@ -97,15 +99,16 @@ impl Capturer { } } - pub fn frame<'b>(&'b mut self) -> &'b [u8] { + pub fn frame<'b>(&'b mut self) -> std::io::Result<&'b [u8]> { self.get_image(); let result = unsafe { slice::from_raw_parts(self.buffer, self.size) }; - if self.use_yuv { + crate::would_block_if_equal(&mut self.saved_raw_data, result)?; + Ok(if self.use_yuv { crate::common::bgra_to_i420(self.display.w(), self.display.h(), &result, &mut self.yuv); &self.yuv[..] } else { result - } + }) } }