diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f8e3dcf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "[rust]": { + "editor.formatOnSave": true + } +} diff --git a/src/capturer/engine/mac/apple_sys.rs b/src/capturer/engine/mac/apple_sys.rs index d7889ae..7ecf3b4 100644 --- a/src/capturer/engine/mac/apple_sys.rs +++ b/src/capturer/engine/mac/apple_sys.rs @@ -1,3 +1,5 @@ +pub use screencapturekit_sys::os_types::base::*; + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct __CFDictionary { @@ -35,6 +37,7 @@ extern "C" { theType: CFNumberType, valuePtr: *mut ::std::os::raw::c_void, ) -> Boolean; + pub fn CMTimeGetSeconds(time: CMTime) -> Float64; pub static SCStreamFrameInfoStatus: SCStreamFrameInfo; } pub const CFNumberType_kCFNumberSInt64Type: CFNumberType = 4; diff --git a/src/capturer/engine/mac/mod.rs b/src/capturer/engine/mac/mod.rs index e036d56..5a17780 100644 --- a/src/capturer/engine/mac/mod.rs +++ b/src/capturer/engine/mac/mod.rs @@ -14,10 +14,13 @@ use screencapturekit::{ use screencapturekit_sys::os_types::base::{CMTime, CMTimeScale}; use screencapturekit_sys::os_types::geometry::{CGPoint, CGRect, CGSize}; -use crate::{capturer::{Area, Options, Point, Size}, frame::BGRAFrame}; use crate::frame::{Frame, FrameType}; use crate::targets::Target; use crate::{capturer::Resolution, targets}; +use crate::{ + capturer::{Area, Options, Point, Size}, + frame::BGRAFrame, +}; mod apple_sys; mod pixelformat; @@ -72,7 +75,7 @@ impl StreamOutput for Capturer { // Quick hack - just send an empty frame, and the caller can figure out how to handle it match self.output_type { FrameType::BGRAFrame => { - let display_time = sample.sys_ref.get_presentation_timestamp().value as u64; + let display_time = pixelformat::get_pts_in_nanoseconds(&sample); let frame = BGRAFrame { display_time, width: 0, @@ -80,10 +83,10 @@ impl StreamOutput for Capturer { data: vec![], }; self.tx.send(Frame::BGRA(frame)).unwrap_or(()); - }, + } _ => {} } - }, + } _ => {} } } diff --git a/src/capturer/engine/mac/pixelformat.rs b/src/capturer/engine/mac/pixelformat.rs index 911bb3c..0e10ad4 100644 --- a/src/capturer/engine/mac/pixelformat.rs +++ b/src/capturer/engine/mac/pixelformat.rs @@ -17,6 +17,16 @@ use core_video_sys::{ CVPixelBufferLockBaseAddress, CVPixelBufferRef, CVPixelBufferUnlockBaseAddress, }; +// Returns a frame's presentation timestamp in nanoseconds since an arbitrary start time. +// This is typically yielded from a monotonic clock started on system boot. +pub fn get_pts_in_nanoseconds(sample_buffer: &CMSampleBuffer) -> u64 { + let pts = sample_buffer.sys_ref.get_presentation_timestamp(); + + let seconds = unsafe { CMTimeGetSeconds(pts) }; + + (seconds * 1_000_000_000.).trunc() as u64 +} + pub unsafe fn create_yuv_frame(sample_buffer: CMSampleBuffer) -> Option { // Check that the frame status is complete let buffer_ref = &(*sample_buffer.sys_ref); @@ -47,8 +57,7 @@ pub unsafe fn create_yuv_frame(sample_buffer: CMSampleBuffer) -> Option Option Option Option { + let display_time = get_pts_in_nanoseconds(&sample_buffer); let buffer_ref = &(*sample_buffer.sys_ref); - let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value; let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef; CVPixelBufferLockBaseAddress(pixel_buffer, 0); @@ -117,7 +126,7 @@ pub unsafe fn create_bgr_frame(sample_buffer: CMSampleBuffer) -> Option Option Option { + let display_time = get_pts_in_nanoseconds(&sample_buffer); let buffer_ref = &(*sample_buffer.sys_ref); - let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value; let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef; CVPixelBufferLockBaseAddress(pixel_buffer, 0); @@ -149,7 +158,7 @@ pub unsafe fn create_bgra_frame(sample_buffer: CMSampleBuffer) -> Option Option Option { + let display_time = get_pts_in_nanoseconds(&sample_buffer); let buffer_ref = &(*sample_buffer.sys_ref); - let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value; let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef; CVPixelBufferLockBaseAddress(pixel_buffer, 0); @@ -184,7 +193,7 @@ pub unsafe fn create_rgb_frame(sample_buffer: CMSampleBuffer) -> Option [u32; 2] { + #[cfg(target_os = "macos")] + { + mac::get_output_frame_size(options) + } + + #[cfg(target_os = "windows")] + { + win::get_output_frame_size(options) + } + + #[cfg(target_os = "linux")] + { + // TODO: How to calculate this on Linux? + return [0, 0]; + } +} + pub struct Engine { options: Options, #[cfg(target_os = "macos")] @@ -90,19 +108,6 @@ impl Engine { } pub fn get_output_frame_size(&mut self) -> [u32; 2] { - #[cfg(target_os = "macos")] - { - mac::get_output_frame_size(&self.options) - } - - #[cfg(target_os = "windows")] - { - win::get_output_frame_size(&self.options) - } - - #[cfg(target_os = "linux")] - { - return [0, 0]; - } + get_output_frame_size(&self.options) } } diff --git a/src/capturer/mod.rs b/src/capturer/mod.rs index 7624389..d9ac794 100644 --- a/src/capturer/mod.rs +++ b/src/capturer/mod.rs @@ -8,6 +8,8 @@ use crate::{ targets::Target, }; +pub use engine::get_output_frame_size; + #[derive(Debug, Clone, Copy, Default)] pub enum Resolution { _480p,