Capture display frames and access underlying IOSurface
This commit is contained in:
parent
014246f569
commit
1611635e5f
2 changed files with 155 additions and 3 deletions
|
@ -4,8 +4,10 @@ use crate::bindings::{dispatch_queue_create, NSObject, SCStreamOutputType};
|
|||
use block::ConcreteBlock;
|
||||
use cocoa::{
|
||||
base::{id, nil, YES},
|
||||
foundation::{NSArray, NSBundle, NSString, NSUInteger},
|
||||
foundation::{NSArray, NSString, NSUInteger},
|
||||
};
|
||||
use core_foundation::{base::TCFType, number::CFNumberRef, string::CFStringRef};
|
||||
use core_media::{CMSampleBuffer, CMSampleBufferRef};
|
||||
use gpui::{actions, elements::*, keymap::Binding, Menu, MenuItem};
|
||||
use log::LevelFilter;
|
||||
use objc::{
|
||||
|
@ -49,6 +51,8 @@ fn main() {
|
|||
let applications: id = msg_send![content, applications];
|
||||
let displays: id = msg_send![content, displays];
|
||||
let display: id = displays.objectAtIndex(0);
|
||||
let display_width: usize = msg_send![display, width];
|
||||
let display_height: usize = msg_send![display, height];
|
||||
|
||||
let mut decl = ClassDecl::new("CaptureOutput", class!(NSObject)).unwrap();
|
||||
decl.add_protocol(Protocol::get("SCStreamOutput").unwrap());
|
||||
|
@ -63,6 +67,8 @@ fn main() {
|
|||
// let filter: id = msg_send![filter, initWithDesktopIndependentWindow: window];
|
||||
let config: id = msg_send![class!(SCStreamConfiguration), alloc];
|
||||
let config: id = msg_send![config, init];
|
||||
let _: () = msg_send![config, setWidth: display_width];
|
||||
let _: () = msg_send![config, setHeight: display_height];
|
||||
let _: () = msg_send![config, setMinimumFrameInterval: bindings::CMTimeMake(1, 60)];
|
||||
let _: () = msg_send![config, setQueueDepth: 6];
|
||||
let _: () = msg_send![config, setShowsCursor: YES];
|
||||
|
@ -134,12 +140,156 @@ extern "C" fn sample_output(
|
|||
_: &Object,
|
||||
_: Sel,
|
||||
_stream: id,
|
||||
_buffer: id,
|
||||
buffer: id,
|
||||
_kind: SCStreamOutputType,
|
||||
) {
|
||||
println!("sample output");
|
||||
let buffer = unsafe { CMSampleBuffer::wrap_under_get_rule(buffer as CMSampleBufferRef) };
|
||||
let attachments = buffer.attachments();
|
||||
let attachments = attachments.first().expect("no attachments for sample");
|
||||
|
||||
unsafe {
|
||||
let string = bindings::SCStreamFrameInfoStatus.0 as CFStringRef;
|
||||
let status = core_foundation::number::CFNumber::wrap_under_get_rule(
|
||||
*attachments.get(string) as CFNumberRef,
|
||||
)
|
||||
.to_i64()
|
||||
.expect("invalid frame info status");
|
||||
|
||||
if status != bindings::SCFrameStatus_SCFrameStatusComplete {
|
||||
println!("received incomplete frame");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let image_buffer = buffer.image_buffer();
|
||||
dbg!(image_buffer.width(), image_buffer.height());
|
||||
let io_surface = image_buffer.io_surface();
|
||||
}
|
||||
|
||||
fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
|
||||
cx.platform().quit();
|
||||
}
|
||||
|
||||
mod core_media {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::core_video::{CVImageBuffer, CVImageBufferRef};
|
||||
use core_foundation::{
|
||||
array::{CFArray, CFArrayRef},
|
||||
base::{CFTypeID, TCFType},
|
||||
declare_TCFType,
|
||||
dictionary::CFDictionary,
|
||||
impl_CFTypeDescription, impl_TCFType,
|
||||
string::CFString,
|
||||
};
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct __CMSampleBuffer(c_void);
|
||||
// The ref type must be a pointer to the underlying struct.
|
||||
pub type CMSampleBufferRef = *const __CMSampleBuffer;
|
||||
|
||||
declare_TCFType!(CMSampleBuffer, CMSampleBufferRef);
|
||||
impl_TCFType!(CMSampleBuffer, CMSampleBufferRef, CMSampleBufferGetTypeID);
|
||||
impl_CFTypeDescription!(CMSampleBuffer);
|
||||
|
||||
impl CMSampleBuffer {
|
||||
pub fn attachments(&self) -> Vec<CFDictionary<CFString>> {
|
||||
unsafe {
|
||||
let attachments =
|
||||
CMSampleBufferGetSampleAttachmentsArray(self.as_concrete_TypeRef(), true);
|
||||
CFArray::<CFDictionary>::wrap_under_get_rule(attachments)
|
||||
.into_iter()
|
||||
.map(|attachments| {
|
||||
CFDictionary::wrap_under_get_rule(attachments.as_concrete_TypeRef())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_buffer(&self) -> CVImageBuffer {
|
||||
unsafe {
|
||||
CVImageBuffer::wrap_under_get_rule(CMSampleBufferGetImageBuffer(
|
||||
self.as_concrete_TypeRef(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn CMSampleBufferGetTypeID() -> CFTypeID;
|
||||
fn CMSampleBufferGetSampleAttachmentsArray(
|
||||
buffer: CMSampleBufferRef,
|
||||
create_if_necessary: bool,
|
||||
) -> CFArrayRef;
|
||||
fn CMSampleBufferGetImageBuffer(buffer: CMSampleBufferRef) -> CVImageBufferRef;
|
||||
}
|
||||
}
|
||||
|
||||
mod core_video {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::io_surface::{IOSurface, IOSurfaceRef};
|
||||
use core_foundation::{
|
||||
base::{CFTypeID, TCFType},
|
||||
declare_TCFType, impl_CFTypeDescription, impl_TCFType,
|
||||
};
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct __CVImageBuffer(c_void);
|
||||
// The ref type must be a pointer to the underlying struct.
|
||||
pub type CVImageBufferRef = *const __CVImageBuffer;
|
||||
|
||||
declare_TCFType!(CVImageBuffer, CVImageBufferRef);
|
||||
impl_TCFType!(CVImageBuffer, CVImageBufferRef, CVImageBufferGetTypeID);
|
||||
impl_CFTypeDescription!(CVImageBuffer);
|
||||
|
||||
impl CVImageBuffer {
|
||||
pub fn io_surface(&self) -> IOSurface {
|
||||
unsafe {
|
||||
IOSurface::wrap_under_get_rule(CVPixelBufferGetIOSurface(
|
||||
self.as_concrete_TypeRef(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
unsafe { CVPixelBufferGetWidth(self.as_concrete_TypeRef()) }
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
unsafe { CVPixelBufferGetHeight(self.as_concrete_TypeRef()) }
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn CVImageBufferGetTypeID() -> CFTypeID;
|
||||
fn CVPixelBufferGetIOSurface(buffer: CVImageBufferRef) -> IOSurfaceRef;
|
||||
fn CVPixelBufferGetWidth(buffer: CVImageBufferRef) -> usize;
|
||||
fn CVPixelBufferGetHeight(buffer: CVImageBufferRef) -> usize;
|
||||
}
|
||||
}
|
||||
|
||||
mod io_surface {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core_foundation::{
|
||||
base::{CFTypeID, TCFType},
|
||||
declare_TCFType, impl_CFTypeDescription, impl_TCFType,
|
||||
};
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct __IOSurface(c_void);
|
||||
// The ref type must be a pointer to the underlying struct.
|
||||
pub type IOSurfaceRef = *const __IOSurface;
|
||||
|
||||
declare_TCFType!(IOSurface, IOSurfaceRef);
|
||||
impl_TCFType!(IOSurface, IOSurfaceRef, IOSurfaceGetTypeID);
|
||||
impl_CFTypeDescription!(IOSurface);
|
||||
|
||||
extern "C" {
|
||||
fn IOSurfaceGetTypeID() -> CFTypeID;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue