Skip to content

Commit f63eb09

Browse files
authored
Merge pull request #128 from filleduchaos/main
fix yielded presentation timestamp on macOS
2 parents c38d421 + 8eb00ce commit f63eb09

File tree

6 files changed

+54
-27
lines changed

6 files changed

+54
-27
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"[rust]": {
3+
"editor.formatOnSave": true
4+
}
5+
}

src/capturer/engine/mac/apple_sys.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub use screencapturekit_sys::os_types::base::*;
2+
13
#[repr(C)]
24
#[derive(Debug, Copy, Clone)]
35
pub struct __CFDictionary {
@@ -35,6 +37,7 @@ extern "C" {
3537
theType: CFNumberType,
3638
valuePtr: *mut ::std::os::raw::c_void,
3739
) -> Boolean;
40+
pub fn CMTimeGetSeconds(time: CMTime) -> Float64;
3841
pub static SCStreamFrameInfoStatus: SCStreamFrameInfo;
3942
}
4043
pub const CFNumberType_kCFNumberSInt64Type: CFNumberType = 4;

src/capturer/engine/mac/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ use screencapturekit::{
1414
use screencapturekit_sys::os_types::base::{CMTime, CMTimeScale};
1515
use screencapturekit_sys::os_types::geometry::{CGPoint, CGRect, CGSize};
1616

17-
use crate::{capturer::{Area, Options, Point, Size}, frame::BGRAFrame};
1817
use crate::frame::{Frame, FrameType};
1918
use crate::targets::Target;
2019
use crate::{capturer::Resolution, targets};
20+
use crate::{
21+
capturer::{Area, Options, Point, Size},
22+
frame::BGRAFrame,
23+
};
2124

2225
mod apple_sys;
2326
mod pixelformat;
@@ -72,18 +75,18 @@ impl StreamOutput for Capturer {
7275
// Quick hack - just send an empty frame, and the caller can figure out how to handle it
7376
match self.output_type {
7477
FrameType::BGRAFrame => {
75-
let display_time = sample.sys_ref.get_presentation_timestamp().value as u64;
78+
let display_time = pixelformat::get_pts_in_nanoseconds(&sample);
7679
let frame = BGRAFrame {
7780
display_time,
7881
width: 0,
7982
height: 0,
8083
data: vec![],
8184
};
8285
self.tx.send(Frame::BGRA(frame)).unwrap_or(());
83-
},
86+
}
8487
_ => {}
8588
}
86-
},
89+
}
8790
_ => {}
8891
}
8992
}

src/capturer/engine/mac/pixelformat.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ use core_video_sys::{
1717
CVPixelBufferLockBaseAddress, CVPixelBufferRef, CVPixelBufferUnlockBaseAddress,
1818
};
1919

20+
// Returns a frame's presentation timestamp in nanoseconds since an arbitrary start time.
21+
// This is typically yielded from a monotonic clock started on system boot.
22+
pub fn get_pts_in_nanoseconds(sample_buffer: &CMSampleBuffer) -> u64 {
23+
let pts = sample_buffer.sys_ref.get_presentation_timestamp();
24+
25+
let seconds = unsafe { CMTimeGetSeconds(pts) };
26+
27+
(seconds * 1_000_000_000.).trunc() as u64
28+
}
29+
2030
pub unsafe fn create_yuv_frame(sample_buffer: CMSampleBuffer) -> Option<YUVFrame> {
2131
// Check that the frame status is complete
2232
let buffer_ref = &(*sample_buffer.sys_ref);
@@ -47,8 +57,7 @@ pub unsafe fn create_yuv_frame(sample_buffer: CMSampleBuffer) -> Option<YUVFrame
4757
}
4858
}
4959

50-
//let epoch = CMSampleBufferGetPresentationTimeStamp(buffer_ref).epoch;
51-
let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value;
60+
let display_time = get_pts_in_nanoseconds(&sample_buffer);
5261
let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef;
5362

5463
CVPixelBufferLockBaseAddress(pixel_buffer, 0);
@@ -78,7 +87,7 @@ pub unsafe fn create_yuv_frame(sample_buffer: CMSampleBuffer) -> Option<YUVFrame
7887
CVPixelBufferUnlockBaseAddress(pixel_buffer, 0);
7988

8089
YUVFrame {
81-
display_time: epoch as u64,
90+
display_time,
8291
width: width as i32,
8392
height: height as i32,
8493
luminance_bytes,
@@ -90,8 +99,8 @@ pub unsafe fn create_yuv_frame(sample_buffer: CMSampleBuffer) -> Option<YUVFrame
9099
}
91100

92101
pub unsafe fn create_bgr_frame(sample_buffer: CMSampleBuffer) -> Option<BGRFrame> {
102+
let display_time = get_pts_in_nanoseconds(&sample_buffer);
93103
let buffer_ref = &(*sample_buffer.sys_ref);
94-
let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value;
95104
let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef;
96105

97106
CVPixelBufferLockBaseAddress(pixel_buffer, 0);
@@ -117,16 +126,16 @@ pub unsafe fn create_bgr_frame(sample_buffer: CMSampleBuffer) -> Option<BGRFrame
117126
CVPixelBufferUnlockBaseAddress(pixel_buffer, 0);
118127

119128
Some(BGRFrame {
120-
display_time: epoch as u64,
129+
display_time,
121130
width: width as i32, // width does not give accurate results - https://stackoverflow.com/questions/19587185/cvpixelbuffergetbytesperrow-for-cvimagebufferref-returns-unexpected-wrong-valu
122131
height: height as i32,
123132
data: remove_alpha_channel(cropped_data),
124133
})
125134
}
126135

127136
pub unsafe fn create_bgra_frame(sample_buffer: CMSampleBuffer) -> Option<BGRAFrame> {
137+
let display_time = get_pts_in_nanoseconds(&sample_buffer);
128138
let buffer_ref = &(*sample_buffer.sys_ref);
129-
let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value;
130139
let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef;
131140

132141
CVPixelBufferLockBaseAddress(pixel_buffer, 0);
@@ -149,16 +158,16 @@ pub unsafe fn create_bgra_frame(sample_buffer: CMSampleBuffer) -> Option<BGRAFra
149158
CVPixelBufferUnlockBaseAddress(pixel_buffer, 0);
150159

151160
Some(BGRAFrame {
152-
display_time: epoch as u64,
161+
display_time,
153162
width: width as i32, // width does not give accurate results - https://stackoverflow.com/questions/19587185/cvpixelbuffergetbytesperrow-for-cvimagebufferref-returns-unexpected-wrong-valu
154163
height: height as i32,
155164
data,
156165
})
157166
}
158167

159168
pub unsafe fn create_rgb_frame(sample_buffer: CMSampleBuffer) -> Option<RGBFrame> {
169+
let display_time = get_pts_in_nanoseconds(&sample_buffer);
160170
let buffer_ref = &(*sample_buffer.sys_ref);
161-
let epoch = sample_buffer.sys_ref.get_presentation_timestamp().value;
162171
let pixel_buffer = CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef;
163172

164173
CVPixelBufferLockBaseAddress(pixel_buffer, 0);
@@ -184,7 +193,7 @@ pub unsafe fn create_rgb_frame(sample_buffer: CMSampleBuffer) -> Option<RGBFrame
184193
CVPixelBufferUnlockBaseAddress(pixel_buffer, 0);
185194

186195
Some(RGBFrame {
187-
display_time: epoch as u64,
196+
display_time,
188197
width: width as i32, // width does not give accurate results - https://stackoverflow.com/questions/19587185/cvpixelbuffergetbytesperrow-for-cvimagebufferref-returns-unexpected-wrong-valu
189198
height: height as i32,
190199
data: convert_bgra_to_rgb(cropped_data),

src/capturer/engine/mod.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@ mod win;
1212
#[cfg(target_os = "linux")]
1313
mod linux;
1414

15+
pub fn get_output_frame_size(options: &Options) -> [u32; 2] {
16+
#[cfg(target_os = "macos")]
17+
{
18+
mac::get_output_frame_size(options)
19+
}
20+
21+
#[cfg(target_os = "windows")]
22+
{
23+
win::get_output_frame_size(options)
24+
}
25+
26+
#[cfg(target_os = "linux")]
27+
{
28+
// TODO: How to calculate this on Linux?
29+
return [0, 0];
30+
}
31+
}
32+
1533
pub struct Engine {
1634
options: Options,
1735
#[cfg(target_os = "macos")]
@@ -90,19 +108,6 @@ impl Engine {
90108
}
91109

92110
pub fn get_output_frame_size(&mut self) -> [u32; 2] {
93-
#[cfg(target_os = "macos")]
94-
{
95-
mac::get_output_frame_size(&self.options)
96-
}
97-
98-
#[cfg(target_os = "windows")]
99-
{
100-
win::get_output_frame_size(&self.options)
101-
}
102-
103-
#[cfg(target_os = "linux")]
104-
{
105-
return [0, 0];
106-
}
111+
get_output_frame_size(&self.options)
107112
}
108113
}

src/capturer/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::{
88
targets::Target,
99
};
1010

11+
pub use engine::get_output_frame_size;
12+
1113
#[derive(Debug, Clone, Copy, Default)]
1214
pub enum Resolution {
1315
_480p,

0 commit comments

Comments
 (0)