Skip to content

Commit b1e7ecb

Browse files
authored
Merge pull request #127 from CapSoftware/raw-pixel-buffers
raw pixel buffers
2 parents f63eb09 + 88d0e14 commit b1e7ecb

File tree

8 files changed

+343
-109
lines changed

8 files changed

+343
-109
lines changed

src/capturer/engine/mac/apple_sys.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(non_upper_case_globals)]
2+
13
pub use screencapturekit_sys::os_types::base::*;
24

35
#[repr(C)]

src/capturer/engine/mac/mod.rs

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::cmp;
22
use std::sync::mpsc;
33

4+
use pixelformat::get_pts_in_nanoseconds;
45
use screencapturekit::{
56
cm_sample_buffer::CMSampleBuffer,
67
sc_content_filter::{InitParams, SCContentFilter},
@@ -16,13 +17,16 @@ use screencapturekit_sys::os_types::geometry::{CGPoint, CGRect, CGSize};
1617

1718
use crate::frame::{Frame, FrameType};
1819
use crate::targets::Target;
19-
use crate::{capturer::Resolution, targets};
2020
use crate::{
21-
capturer::{Area, Options, Point, Size},
21+
capturer::{Area, Options, Point, Resolution, Size},
2222
frame::BGRAFrame,
23+
targets,
2324
};
2425

26+
use super::ChannelItem;
27+
2528
mod apple_sys;
29+
mod pixel_buffer;
2630
mod pixelformat;
2731

2832
struct ErrorHandler;
@@ -33,69 +37,22 @@ impl StreamErrorHandler for ErrorHandler {
3337
}
3438

3539
pub struct Capturer {
36-
pub tx: mpsc::Sender<Frame>,
37-
pub output_type: FrameType,
40+
pub tx: mpsc::Sender<ChannelItem>,
3841
}
3942

4043
impl Capturer {
41-
pub fn new(tx: mpsc::Sender<Frame>, output_type: FrameType) -> Self {
42-
Capturer { tx, output_type }
44+
pub fn new(tx: mpsc::Sender<ChannelItem>) -> Self {
45+
Capturer { tx }
4346
}
4447
}
4548

4649
impl StreamOutput for Capturer {
4750
fn did_output_sample_buffer(&self, sample: CMSampleBuffer, of_type: SCStreamOutputType) {
48-
match of_type {
49-
SCStreamOutputType::Screen => {
50-
let frame_status = &sample.frame_status;
51-
52-
match frame_status {
53-
SCFrameStatus::Complete | SCFrameStatus::Started => unsafe {
54-
let frame = match self.output_type {
55-
FrameType::YUVFrame => {
56-
let yuvframe = pixelformat::create_yuv_frame(sample).unwrap();
57-
Frame::YUVFrame(yuvframe)
58-
}
59-
FrameType::RGB => {
60-
let rgbframe = pixelformat::create_rgb_frame(sample).unwrap();
61-
Frame::RGB(rgbframe)
62-
}
63-
FrameType::BGR0 => {
64-
let bgrframe = pixelformat::create_bgr_frame(sample).unwrap();
65-
Frame::BGR0(bgrframe)
66-
}
67-
FrameType::BGRAFrame => {
68-
let bgraframe = pixelformat::create_bgra_frame(sample).unwrap();
69-
Frame::BGRA(bgraframe)
70-
}
71-
};
72-
self.tx.send(frame).unwrap_or(());
73-
},
74-
SCFrameStatus::Idle => {
75-
// Quick hack - just send an empty frame, and the caller can figure out how to handle it
76-
match self.output_type {
77-
FrameType::BGRAFrame => {
78-
let display_time = pixelformat::get_pts_in_nanoseconds(&sample);
79-
let frame = BGRAFrame {
80-
display_time,
81-
width: 0,
82-
height: 0,
83-
data: vec![],
84-
};
85-
self.tx.send(Frame::BGRA(frame)).unwrap_or(());
86-
}
87-
_ => {}
88-
}
89-
}
90-
_ => {}
91-
}
92-
}
93-
_ => {}
94-
}
51+
self.tx.send((sample, of_type)).unwrap_or(());
9552
}
9653
}
9754

98-
pub fn create_capturer(options: &Options, tx: mpsc::Sender<Frame>) -> SCStream {
55+
pub fn create_capturer(options: &Options, tx: mpsc::Sender<ChannelItem>) -> SCStream {
9956
// If no target is specified, capture the main display
10057
let target = options
10158
.target
@@ -133,14 +90,13 @@ pub fn create_capturer(options: &Options, tx: mpsc::Sender<Frame>) -> SCStream {
13390
.into_iter()
13491
.filter(|window| {
13592
excluded_targets
136-
.into_iter()
137-
.find(|excluded_target| match excluded_target {
93+
.iter()
94+
.any(|excluded_target| match excluded_target {
13895
Target::Window(excluded_window) => {
13996
excluded_window.id == window.window_id
14097
}
14198
_ => false,
14299
})
143-
.is_some()
144100
})
145101
.collect();
146102

@@ -190,10 +146,7 @@ pub fn create_capturer(options: &Options, tx: mpsc::Sender<Frame>) -> SCStream {
190146
};
191147

192148
let mut stream = SCStream::new(filter, stream_config, ErrorHandler);
193-
stream.add_output(
194-
Capturer::new(tx, options.output_type),
195-
SCStreamOutputType::Screen,
196-
);
149+
stream.add_output(Capturer::new(tx), SCStreamOutputType::Screen);
197150

198151
stream
199152
}
@@ -251,8 +204,8 @@ pub fn get_crop_area(options: &Options) -> Area {
251204
y: val.origin.y,
252205
},
253206
size: Size {
254-
width: input_width as f64,
255-
height: input_height as f64,
207+
width: input_width,
208+
height: input_height,
256209
},
257210
}
258211
})
@@ -264,3 +217,50 @@ pub fn get_crop_area(options: &Options) -> Area {
264217
},
265218
})
266219
}
220+
221+
pub fn process_sample_buffer(
222+
sample: CMSampleBuffer,
223+
of_type: SCStreamOutputType,
224+
output_type: FrameType,
225+
) -> Option<Frame> {
226+
if let SCStreamOutputType::Screen = of_type {
227+
let frame_status = &sample.frame_status;
228+
229+
match frame_status {
230+
SCFrameStatus::Complete | SCFrameStatus::Started => unsafe {
231+
return Some(match output_type {
232+
FrameType::YUVFrame => {
233+
let yuvframe = pixelformat::create_yuv_frame(sample).unwrap();
234+
Frame::YUVFrame(yuvframe)
235+
}
236+
FrameType::RGB => {
237+
let rgbframe = pixelformat::create_rgb_frame(sample).unwrap();
238+
Frame::RGB(rgbframe)
239+
}
240+
FrameType::BGR0 => {
241+
let bgrframe = pixelformat::create_bgr_frame(sample).unwrap();
242+
Frame::BGR0(bgrframe)
243+
}
244+
FrameType::BGRAFrame => {
245+
let bgraframe = pixelformat::create_bgra_frame(sample).unwrap();
246+
Frame::BGRA(bgraframe)
247+
}
248+
});
249+
},
250+
SCFrameStatus::Idle => {
251+
// Quick hack - just send an empty frame, and the caller can figure out how to handle it
252+
if let FrameType::BGRAFrame = output_type {
253+
return Some(Frame::BGRA(BGRAFrame {
254+
display_time: get_pts_in_nanoseconds(&sample),
255+
width: 0,
256+
height: 0,
257+
data: vec![],
258+
}));
259+
}
260+
}
261+
_ => {}
262+
}
263+
}
264+
265+
None
266+
}
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
use core::slice;
2+
use core_video_sys::{
3+
CVPixelBufferGetBaseAddress, CVPixelBufferGetBaseAddressOfPlane, CVPixelBufferGetBytesPerRow,
4+
CVPixelBufferGetBytesPerRowOfPlane, CVPixelBufferGetHeight, CVPixelBufferGetHeightOfPlane,
5+
CVPixelBufferGetPlaneCount, CVPixelBufferGetWidth, CVPixelBufferGetWidthOfPlane,
6+
CVPixelBufferLockBaseAddress, CVPixelBufferRef, CVPixelBufferUnlockBaseAddress,
7+
};
8+
use screencapturekit::{cm_sample_buffer::CMSampleBuffer, sc_types::SCFrameStatus};
9+
use screencapturekit_sys::cm_sample_buffer_ref::CMSampleBufferGetImageBuffer;
10+
use std::{ops::Deref, sync::mpsc};
11+
12+
use crate::capturer::{engine::ChannelItem, RawCapturer};
13+
14+
pub struct PixelBuffer {
15+
display_time: u64,
16+
width: usize,
17+
height: usize,
18+
bytes_per_row: usize,
19+
buffer: CMSampleBuffer,
20+
}
21+
22+
impl PixelBuffer {
23+
pub fn display_time(&self) -> u64 {
24+
self.display_time
25+
}
26+
27+
pub fn width(&self) -> usize {
28+
self.width
29+
}
30+
31+
pub fn height(&self) -> usize {
32+
self.height
33+
}
34+
35+
pub fn buffer(&self) -> &CMSampleBuffer {
36+
&self.buffer
37+
}
38+
39+
pub fn bytes_per_row(&self) -> usize {
40+
self.bytes_per_row
41+
}
42+
43+
pub fn data(&self) -> PixelBufferData {
44+
unsafe {
45+
let pixel_buffer = sample_buffer_to_pixel_buffer(&self.buffer);
46+
47+
CVPixelBufferLockBaseAddress(pixel_buffer, 0);
48+
49+
let base_address = CVPixelBufferGetBaseAddress(pixel_buffer);
50+
51+
PixelBufferData {
52+
buffer: pixel_buffer,
53+
data: slice::from_raw_parts(
54+
base_address as *mut _,
55+
self.bytes_per_row * self.height,
56+
),
57+
}
58+
}
59+
}
60+
61+
pub fn planes(&self) -> Vec<Plane> {
62+
unsafe {
63+
let pixel_buffer = sample_buffer_to_pixel_buffer(&self.buffer);
64+
let count = CVPixelBufferGetPlaneCount(pixel_buffer);
65+
66+
CVPixelBufferLockBaseAddress(pixel_buffer, 0);
67+
68+
(0..count)
69+
.map(|i| Plane {
70+
buffer: pixel_buffer,
71+
width: CVPixelBufferGetWidthOfPlane(pixel_buffer, i),
72+
height: CVPixelBufferGetHeightOfPlane(pixel_buffer, i),
73+
bytes_per_row: CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer, i),
74+
index: i,
75+
})
76+
.collect()
77+
}
78+
}
79+
80+
pub(crate) fn new(item: ChannelItem) -> Option<Self> {
81+
unsafe {
82+
let display_time = pixel_buffer_display_time(&item.0);
83+
let pixel_buffer = sample_buffer_to_pixel_buffer(&item.0);
84+
let (width, height) = pixel_buffer_bounds(pixel_buffer);
85+
86+
match item.0.frame_status {
87+
SCFrameStatus::Complete | SCFrameStatus::Started | SCFrameStatus::Idle => {
88+
Some(Self {
89+
display_time,
90+
width,
91+
height,
92+
bytes_per_row: pixel_buffer_bytes_per_row(pixel_buffer),
93+
buffer: item.0,
94+
})
95+
}
96+
_ => None,
97+
}
98+
}
99+
}
100+
}
101+
102+
#[derive(Debug)]
103+
pub struct Plane {
104+
buffer: CVPixelBufferRef,
105+
index: usize,
106+
width: usize,
107+
height: usize,
108+
bytes_per_row: usize,
109+
}
110+
111+
impl Plane {
112+
pub fn width(&self) -> usize {
113+
self.width
114+
}
115+
116+
pub fn height(&self) -> usize {
117+
self.height
118+
}
119+
120+
pub fn bytes_per_row(&self) -> usize {
121+
self.bytes_per_row
122+
}
123+
124+
pub fn data(&self) -> PixelBufferData {
125+
unsafe {
126+
CVPixelBufferLockBaseAddress(self.buffer, 0);
127+
128+
let base_address = CVPixelBufferGetBaseAddressOfPlane(self.buffer, self.index);
129+
130+
PixelBufferData {
131+
buffer: self.buffer,
132+
data: slice::from_raw_parts(
133+
base_address as *mut _,
134+
self.bytes_per_row * self.height,
135+
),
136+
}
137+
}
138+
}
139+
}
140+
141+
pub struct PixelBufferData<'a> {
142+
buffer: CVPixelBufferRef,
143+
data: &'a [u8],
144+
}
145+
146+
impl<'a> Deref for PixelBufferData<'a> {
147+
type Target = [u8];
148+
149+
fn deref(&self) -> &'a Self::Target {
150+
self.data
151+
}
152+
}
153+
154+
impl<'a> Drop for PixelBufferData<'a> {
155+
fn drop(&mut self) {
156+
unsafe { CVPixelBufferUnlockBaseAddress(self.buffer, 0) };
157+
}
158+
}
159+
160+
impl RawCapturer<'_> {
161+
#[cfg(target_os = "macos")]
162+
pub fn get_next_pixel_buffer(&self) -> Result<PixelBuffer, mpsc::RecvError> {
163+
loop {
164+
if let Some(frame) = PixelBuffer::new(self.capturer.rx.recv()?) {
165+
return Ok(frame);
166+
}
167+
}
168+
}
169+
}
170+
171+
pub unsafe fn sample_buffer_to_pixel_buffer(sample_buffer: &CMSampleBuffer) -> CVPixelBufferRef {
172+
let buffer_ref = &(*sample_buffer.sys_ref);
173+
174+
175+
CMSampleBufferGetImageBuffer(buffer_ref) as CVPixelBufferRef
176+
}
177+
178+
pub unsafe fn pixel_buffer_bounds(pixel_buffer: CVPixelBufferRef) -> (usize, usize) {
179+
let width = CVPixelBufferGetWidth(pixel_buffer);
180+
let height = CVPixelBufferGetHeight(pixel_buffer);
181+
182+
(width, height)
183+
}
184+
185+
pub unsafe fn pixel_buffer_bytes_per_row(pixel_buffer: CVPixelBufferRef) -> usize {
186+
CVPixelBufferGetBytesPerRow(pixel_buffer)
187+
}
188+
189+
pub unsafe fn pixel_buffer_display_time(sample_buffer: &CMSampleBuffer) -> u64 {
190+
sample_buffer.sys_ref.get_presentation_timestamp().value as u64
191+
}

0 commit comments

Comments
 (0)