video-toolbox 0.2.1

Safe bindings to VideoToolbox framework
Documentation
use std::{
    mem,
    ptr::{addr_of_mut, null_mut},
};

use core_foundation::{
    base::{kCFAllocatorDefault, CFAllocatorRef, CFGetTypeID, CFRetain, CFType, CFTypeID, CFTypeRef, OSStatus, TCFType, TCFTypeRef},
    declare_TCFType,
    dictionary::{CFDictionary, CFDictionaryRef},
    impl_CFTypeDescription,
    string::{CFString, CFStringRef},
};
use libc::c_void;

pub type VTSessionRef = CFTypeRef;

pub type FrameDelay = i32;

pub const kVTUnlimitedFrameDelayCount: FrameDelay = -1;

extern "C" {
    pub fn VTSessionCopySupportedPropertyDictionary(session: VTSessionRef, supportedPropertyDictionaryOut: *mut CFDictionaryRef) -> OSStatus;

    pub static kVTPropertyTypeKey: CFStringRef;
    pub static kVTPropertyType_Enumeration: CFStringRef;
    pub static kVTPropertyType_Boolean: CFStringRef;
    pub static kVTPropertyType_Number: CFStringRef;
    pub static kVTPropertyReadWriteStatusKey: CFStringRef;
    pub static kVTPropertyReadWriteStatus_ReadOnly: CFStringRef;
    pub static kVTPropertyReadWriteStatus_ReadWrite: CFStringRef;
    pub static kVTPropertyShouldBeSerializedKey: CFStringRef;
    pub static kVTPropertySupportedValueMinimumKey: CFStringRef;
    pub static kVTPropertySupportedValueMaximumKey: CFStringRef;
    pub static kVTPropertySupportedValueListKey: CFStringRef;
    pub static kVTPropertyDocumentationKey: CFStringRef;

    pub fn VTSessionSetProperty(session: VTSessionRef, propertyKey: CFStringRef, propertyValue: CFTypeRef) -> OSStatus;
    pub fn VTSessionSetProperties(session: VTSessionRef, propertyDictionary: CFDictionaryRef) -> OSStatus;
    pub fn VTSessionCopyProperty(
        session: VTSessionRef,
        propertyKey: CFStringRef,
        allocator: CFAllocatorRef,
        propertyValueOut: *mut c_void,
    ) -> OSStatus;
    pub fn VTSessionCopySerializableProperties(session: VTSessionRef, allocator: CFAllocatorRef, dictionaryOut: *mut CFDictionaryRef) -> OSStatus;
}

declare_TCFType!(VTSession, VTSessionRef);
impl_CFTypeDescription!(VTSession);

impl VTSession {
    #[inline]
    pub fn as_concrete_TypeRef(&self) -> VTSessionRef {
        self.0
    }

    #[inline]
    pub fn as_CFType(&self) -> CFType {
        unsafe { CFType::wrap_under_get_rule(self.as_CFTypeRef()) }
    }

    #[inline]
    pub fn as_CFTypeRef(&self) -> CFTypeRef {
        self.as_concrete_TypeRef() as CFTypeRef
    }

    #[inline]
    pub fn into_CFType(self) -> CFType {
        let reference = self.as_CFTypeRef();
        mem::forget(self);
        unsafe { CFType::wrap_under_create_rule(reference) }
    }

    #[inline]
    pub unsafe fn wrap_under_create_rule(reference: VTSessionRef) -> VTSession {
        VTSession(reference)
    }

    #[inline]
    pub unsafe fn wrap_under_get_rule(reference: VTSessionRef) -> VTSession {
        VTSession(CFRetain(reference as CFTypeRef) as VTSessionRef)
    }

    #[inline]
    pub fn type_of(&self) -> CFTypeID {
        unsafe { CFGetTypeID(self.as_CFTypeRef()) }
    }

    #[inline]
    pub fn instance_of<T: TCFType>(&self) -> bool {
        self.type_of() == T::type_id()
    }
}

impl Clone for VTSession {
    #[inline]
    fn clone(&self) -> VTSession {
        unsafe { VTSession::wrap_under_get_rule(self.0) }
    }
}

impl PartialEq for VTSession {
    #[inline]
    fn eq(&self, other: &VTSession) -> bool {
        self.as_CFType().eq(&other.as_CFType())
    }
}

pub trait TVTSession: TCFType {
    #[inline]
    fn as_session(&self) -> VTSession {
        unsafe { VTSession::wrap_under_get_rule(self.as_concrete_TypeRef().as_void_ptr() as VTSessionRef) }
    }

    #[inline]
    fn into_session(self) -> VTSession
    where
        Self: Sized,
    {
        let reference = self.as_concrete_TypeRef().as_void_ptr() as VTSessionRef;
        mem::forget(self);
        unsafe { VTSession::wrap_under_create_rule(reference) }
    }
}

impl VTSession {
    #[inline]
    pub fn downcast<T: TVTSession>(&self) -> Option<T> {
        if self.instance_of::<T>() {
            unsafe { Some(T::wrap_under_get_rule(T::Ref::from_void_ptr(self.as_concrete_TypeRef().as_void_ptr()))) }
        } else {
            None
        }
    }

    #[inline]
    pub fn downcast_into<T: TVTSession>(self) -> Option<T> {
        if self.instance_of::<T>() {
            unsafe {
                let reference = T::Ref::from_void_ptr(self.as_concrete_TypeRef().as_void_ptr());
                mem::forget(self);
                Some(T::wrap_under_create_rule(reference))
            }
        } else {
            None
        }
    }
}

impl VTSession {
    pub fn copy_supported_property_dictionary(&self) -> Result<CFDictionary<CFString, CFType>, OSStatus> {
        unsafe {
            let mut dict: CFDictionaryRef = null_mut();
            let status = VTSessionCopySupportedPropertyDictionary(self.as_concrete_TypeRef(), &mut dict);
            if status == 0 {
                Ok(CFDictionary::wrap_under_create_rule(dict))
            } else {
                Err(status)
            }
        }
    }

    pub fn copy_property(&self, property_key: CFString) -> Result<CFType, OSStatus> {
        unsafe {
            let mut value: CFTypeRef = null_mut();
            let status = VTSessionCopyProperty(
                self.as_concrete_TypeRef(),
                property_key.as_concrete_TypeRef(),
                kCFAllocatorDefault,
                addr_of_mut!(value).cast(),
            );
            if status == 0 {
                Ok(CFType::wrap_under_create_rule(value))
            } else {
                Err(status)
            }
        }
    }

    pub fn copy_serializable_properties(&self) -> Result<CFDictionary<CFString, CFType>, OSStatus> {
        unsafe {
            let mut dict: CFDictionaryRef = null_mut();
            let status = VTSessionCopySerializableProperties(self.as_concrete_TypeRef(), kCFAllocatorDefault, &mut dict);
            if status == 0 {
                Ok(CFDictionary::wrap_under_create_rule(dict))
            } else {
                Err(status)
            }
        }
    }

    pub fn set_property(&self, property_key: CFString, property_value: CFType) -> Result<(), OSStatus> {
        unsafe {
            let status = VTSessionSetProperty(self.as_concrete_TypeRef(), property_key.as_concrete_TypeRef(), property_value.as_concrete_TypeRef());
            if status == 0 {
                Ok(())
            } else {
                Err(status)
            }
        }
    }

    pub fn set_properties(&self, property_dictionary: &CFDictionary<CFString, CFType>) -> Result<(), OSStatus> {
        unsafe {
            let status = VTSessionSetProperties(self.as_concrete_TypeRef(), property_dictionary.as_concrete_TypeRef());
            if status == 0 {
                Ok(())
            } else {
                Err(status)
            }
        }
    }
}