use core::ffi::c_void;
use core::ptr;
use apple_cf::cv::CVPixelBuffer;
use crate::error::VTError;
use crate::ffi;
extern "C" {
fn vtb_motion_session_create(
width: u32,
height: u32,
out: *mut *mut c_void,
) -> i32;
fn vtb_motion_session_release(session: *mut c_void);
fn vtb_motion_session_estimate(
session: *mut c_void,
reference_image: *mut c_void,
current_image: *mut c_void,
out: *mut *mut c_void,
) -> i32;
}
pub struct MotionEstimationSession {
inner: *mut c_void,
}
unsafe impl Send for MotionEstimationSession {}
unsafe impl Sync for MotionEstimationSession {}
impl Drop for MotionEstimationSession {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe {
ffi::VTMotionEstimationSessionInvalidate(self.inner);
vtb_motion_session_release(self.inner);
}
self.inner = ptr::null_mut();
}
}
}
impl MotionEstimationSession {
pub fn new(width: u32, height: u32) -> Result<Self, VTError> {
let mut p: *mut c_void = ptr::null_mut();
let s = unsafe { vtb_motion_session_create(width, height, &mut p) };
if s != 0 || p.is_null() {
return Err(VTError::SessionCreateFailed(s));
}
Ok(Self { inner: p })
}
pub fn source_pixel_buffer_attributes(&self) -> Result<*const c_void, VTError> {
let mut attrs: ffi::CFDictionaryRef = ptr::null();
let s = unsafe {
ffi::VTMotionEstimationSessionCopySourcePixelBufferAttributes(self.inner, &mut attrs)
};
if s != 0 {
return Err(VTError::EncodeFailed(s));
}
Ok(attrs)
}
pub fn complete_frames(&self) -> Result<(), VTError> {
let s = unsafe { ffi::VTMotionEstimationSessionCompleteFrames(self.inner) };
if s == 0 {
Ok(())
} else {
Err(VTError::EncodeFailed(s))
}
}
pub fn estimate(
&self,
reference: &CVPixelBuffer,
current: &CVPixelBuffer,
) -> Result<CVPixelBuffer, VTError> {
let mut out: *mut c_void = ptr::null_mut();
let s = unsafe {
vtb_motion_session_estimate(
self.inner,
reference.as_ptr().cast::<c_void>(),
current.as_ptr().cast::<c_void>(),
&mut out,
)
};
if s != 0 || out.is_null() {
return Err(VTError::EncodeFailed(s));
}
CVPixelBuffer::from_raw(out.cast()).ok_or(VTError::EncodeFailed(0))
}
#[must_use]
pub const fn as_ptr(&self) -> *mut c_void {
self.inner
}
}