From 4f427990bb754a2a5a1f05ac081f30ce9c69537e Mon Sep 17 00:00:00 2001 From: Yury Date: Wed, 26 Feb 2025 18:11:42 +0300 Subject: [PATCH] continue on cm and vt api --- cidre/src/cm.rs | 2 + cidre/src/cm/format_description.rs | 59 ++++++++++-- cidre/src/cm/tagged_buffer_group.rs | 12 +++ cidre/src/vt.rs | 2 + cidre/src/vt/decompression.rs | 2 + cidre/src/vt/decompression/session.rs | 134 ++++++++++++++++---------- 6 files changed, 150 insertions(+), 61 deletions(-) diff --git a/cidre/src/cm.rs b/cidre/src/cm.rs index 8f480e6c..4465c256 100644 --- a/cidre/src/cm.rs +++ b/cidre/src/cm.rs @@ -9,7 +9,9 @@ pub use format_description::FormatDesc; pub use format_description::FormatDescExtKey; pub use format_description::LogTransferFn; pub use format_description::MediaType; +pub use format_description::MuxedFormatDesc; pub use format_description::PixelFormat; +pub use format_description::TaggedBufGroupFormatDesc; pub use format_description::VideoCodec; pub use format_description::VideoDimensions; pub use format_description::VideoFormatDesc; diff --git a/cidre/src/cm/format_description.rs b/cidre/src/cm/format_description.rs index 8848bf63..d2ec2e34 100644 --- a/cidre/src/cm/format_description.rs +++ b/cidre/src/cm/format_description.rs @@ -3,7 +3,7 @@ use std::{ffi::c_void, mem::transmute}; use crate::{ FourCharCode, api, arc, cf::{self, Allocator}, - define_cf_type, os, + cm, define_cf_type, os, }; #[cfg(feature = "cv")] @@ -66,7 +66,7 @@ pub struct VideoDimensions { } #[doc(alias = "CMMediaType")] -#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[derive(Eq, PartialEq, Copy, Clone, Hash)] #[repr(transparent)] pub struct MediaType(pub FourCharCode); @@ -106,8 +106,14 @@ impl MediaType { } } +impl std::fmt::Debug for MediaType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::four_cc_fmt_debug(self.0, "MediaType", f) + } +} + #[doc(alias = "CMVideoCodecType")] -#[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone, Copy, Hash)] #[repr(transparent)] pub struct VideoCodec(FourCharCode); @@ -171,6 +177,12 @@ impl VideoCodec { } } +impl std::fmt::Debug for VideoCodec { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::four_cc_fmt_debug(self.0, "VideoCodec", f) + } +} + define_cf_type!( #[doc(alias = "CMFormatDescriptionRef")] FormatDesc(cf::Type) @@ -179,26 +191,31 @@ define_cf_type!( unsafe impl Send for FormatDesc {} impl FormatDesc { + #[doc(alias = "CMFormatDescriptionGetTypeID")] #[inline] pub fn type_id() -> cf::TypeId { unsafe { CMFormatDescriptionGetTypeID() } } + #[doc(alias = "CMFormatDescriptionGetMediaType")] #[inline] pub fn media_type(&self) -> MediaType { unsafe { CMFormatDescriptionGetMediaType(self) } } + #[doc(alias = "CMFormatDescriptionGetMediaSubType")] #[inline] pub fn media_sub_type(&self) -> FourCharCode { unsafe { CMFormatDescriptionGetMediaSubType(self) } } + #[doc(alias = "CMFormatDescriptionGetExtensions")] #[inline] pub fn exts(&self) -> Option<&cf::DictionaryOf> { unsafe { CMFormatDescriptionGetExtensions(self) } } + #[doc(alias = "CMFormatDescriptionGetExtension")] pub fn ext<'a>(&'a self, key: &FormatDescExtKey) -> Option<&'a cf::Plist> { unsafe { CMFormatDescriptionGetExtension(self, key) } } @@ -308,21 +325,21 @@ impl VideoFormatDesc { /// let desc = cm::VideoFormatDesc::video(cm::VideoCodec::H264, 1920, 1080, None).unwrap(); /// ``` pub fn video( - codec_type: VideoCodec, + codec: VideoCodec, width: i32, height: i32, extensions: Option<&cf::DictionaryOf>, ) -> os::Result> { unsafe { os::result_unchecked(|res| { - Self::create_video_in(codec_type, width, height, extensions, res, None) + Self::create_video_in(codec, width, height, extensions, res, None) }) } } #[doc(alias = "CMVideoFormatDescriptionCreate")] pub fn create_video_in( - codec_type: VideoCodec, + codec: VideoCodec, width: i32, height: i32, extensions: Option<&cf::DictionaryOf>, @@ -332,7 +349,7 @@ impl VideoFormatDesc { unsafe { CMVideoFormatDescriptionCreate( allocator, - codec_type, + codec, width, height, extensions, @@ -357,6 +374,15 @@ impl VideoFormatDesc { unsafe { CMVideoFormatDescriptionMatchesImageBuffer(self, image_buffer) } } + #[api::available(macos = 14.0, ios = 17.0, tvos = 17.0, watchos = 10.0, visionos = 1.0)] + pub fn tag_collections(&self) -> os::Result>> { + unsafe { + let mut res = None; + CMVideoFormatDescriptionCopyTagCollectionArray(self, &mut res).result()?; + Ok(res.unwrap_unchecked()) + } + } + #[doc(alias = "CMVideoFormatDescriptionCreateForImageBuffer")] #[cfg(feature = "cv")] #[inline] @@ -887,7 +913,10 @@ impl FormatDescExtKey { } } -define_cf_type!(LogTransferFn(cf::String)); +define_cf_type!( + #[doc(alias = "CMFormatDescriptionLogTransferFunction")] + LogTransferFn(cf::String) +); impl LogTransferFn { #[doc(alias = "kCMFormatDescriptionLogTransferFunction_AppleLog")] @@ -897,6 +926,12 @@ impl LogTransferFn { } } +#[doc(alias = "CMTaggedBufferGroupFormatDescriptionRef")] +pub type TaggedBufGroupFormatDesc = FormatDesc; + +#[doc(alias = "CMMuxedFormatDescriptionRef")] +pub type MuxedFormatDesc = FormatDesc; + #[link(name = "CoreMedia", kind = "framework")] #[api::weak] unsafe extern "C-unwind" { @@ -947,7 +982,7 @@ unsafe extern "C-unwind" { fn CMVideoFormatDescriptionCreate( allocator: Option<&cf::Allocator>, - codec_type: VideoCodec, + codec: VideoCodec, width: i32, height: i32, extensions: Option<&cf::DictionaryOf>, @@ -962,6 +997,12 @@ unsafe extern "C-unwind" { image_buffer: &cv::ImageBuf, ) -> bool; + #[api::available(macos = 14.0, ios = 17.0, tvos = 17.0, watchos = 10.0, visionos = 1.0)] + fn CMVideoFormatDescriptionCopyTagCollectionArray( + video_desc: &VideoFormatDesc, + tag_collection_out: *mut Option>>, + ) -> os::Status; + fn CMFormatDescriptionGetMediaSubType(desc: &FormatDesc) -> FourCharCode; fn CMFormatDescriptionGetExtensions( diff --git a/cidre/src/cm/tagged_buffer_group.rs b/cidre/src/cm/tagged_buffer_group.rs index 00bd4fe2..1f033f50 100644 --- a/cidre/src/cm/tagged_buffer_group.rs +++ b/cidre/src/cm/tagged_buffer_group.rs @@ -79,6 +79,15 @@ impl TaggedBufGroup { } } +impl cm::SampleBuf { + #[doc(alias = "CMSampleBufferGetTaggedBufferGroup")] + #[doc(alias = "taggedBuffers")] + #[api::available(macos = 14.0, ios = 17.0, tvos = 17.0, watchos = 10.0, visionos = 1.0)] + pub fn tagged_bufs(&self) -> Option<&cm::TaggedBufGroup> { + unsafe { CMSampleBufferGetTaggedBufferGroup(self) } + } +} + #[link(name = "CoreMedia", kind = "framework")] #[api::weak] unsafe extern "C-unwind" { @@ -95,6 +104,9 @@ unsafe extern "C-unwind" { #[api::available(macos = 14.0, ios = 17.0, tvos = 17.0, watchos = 10.0, visionos = 1.0)] fn CMTaggedBufferGroupGetCount(group: &TaggedBufGroup) -> cm::ItemCount; + + #[api::available(macos = 14.0, ios = 17.0, tvos = 17.0, watchos = 10.0, visionos = 1.0)] + fn CMSampleBufferGetTaggedBufferGroup(sbuf: &cm::SampleBuf) -> Option<&cm::TaggedBufGroup>; } #[cfg(test)] diff --git a/cidre/src/vt.rs b/cidre/src/vt.rs index 672cdc61..e83c6116 100644 --- a/cidre/src/vt.rs +++ b/cidre/src/vt.rs @@ -11,8 +11,10 @@ pub use compression::Session as CompressionSession; pub use compression::properties as compression_properties; pub mod decompression; +pub use decompression::MultiImageCapableOutputHandler as DecompressionMultiImageCapableOutputHandler; pub use decompression::OutputCb as DecompressionOutputCb; pub use decompression::OutputCbRecord as DecompressionOutputCbRecord; +pub use decompression::OutputMultiImageCb as DecompressionOutputMultiImageCb; pub use decompression::Session as DecompressionSession; pub use decompression::properties as decompression_properties; pub use decompression::session::is_hardware_decode_supported; diff --git a/cidre/src/vt/decompression.rs b/cidre/src/vt/decompression.rs index 1c766542..0c98409c 100644 --- a/cidre/src/vt/decompression.rs +++ b/cidre/src/vt/decompression.rs @@ -1,6 +1,8 @@ pub mod session; +pub use session::MultiImageCapableOutputHandler; pub use session::OutputCb; pub use session::OutputCbRecord; +pub use session::OutputMultiImageCb; pub use session::Session; pub mod properties; diff --git a/cidre/src/vt/decompression/session.rs b/cidre/src/vt/decompression/session.rs index ae29c588..3454fd24 100644 --- a/cidre/src/vt/decompression/session.rs +++ b/cidre/src/vt/decompression/session.rs @@ -1,51 +1,61 @@ use std::ffi::c_void; -use crate::{ - arc, cf, - cm::{self, SampleBuf, VideoCodec}, - cv, define_cf_type, os, vt, -}; - -pub type OutputCb = extern "C" fn( - output_ref_con: *mut O, - source_frame_ref_con: *mut F, +use crate::{api, arc, cf, cm, cv, define_cf_type, os, vt}; + +#[cfg(feature = "blocks")] +use crate::blocks; + +pub type OutputCb = extern "C" fn( + // passed during session creation + output_ptr: *mut O, + // passed during decode_frame call + src_frame_ptr: *mut F, status: os::Status, info_flags: vt::DecodeInfoFlags, - image_buffer: Option<&cv::ImageBuf>, + image_buf: Option<&cv::ImageBuf>, pts: cm::Time, duration: cm::Time, ); +#[doc(alias = "VTDecompressionOutputCallbackRecord")] #[repr(C)] pub struct OutputCbRecord { - pub callback: OutputCb, - pub output_ref_con: *mut O, + pub cb: Option>, + pub ptr: *mut O, } -unsafe impl Send for OutputCbRecord {} - impl OutputCbRecord { - pub fn new(ref_con: O, callback: OutputCb) -> Self { - let b = Box::new(ref_con); - Self { - callback, - output_ref_con: Box::into_raw(b), - } + pub fn new(ptr: *mut O, cb: Option>) -> Self { + Self { cb, ptr } } } #[doc(alias = "VTDecompressionOutputMultiImageCallback")] -pub type OutputMultiImageCb = extern "C" fn( - output_ref_con: *mut O, - source_frame_ref_con: *mut F, +pub type OutputMultiImageCb = extern "C" fn( + // passed during session creation + output_ptr: *mut O, + // passed during decode_frame call + src_frame_ptr: *mut F, status: os::Status, info_flags: vt::DecodeInfoFlags, - // tagged_buf_group: Option<&cv::TaggedBufGroup>, - // image_buffer: Option<&cv::ImageBuf>, + tagged_buf_group: Option<&cm::TaggedBufGroup>, pts: cm::Time, duration: cm::Time, ); +#[doc(alias = "VTDecompressionMultiImageCapableOutputHandler")] +#[cfg(feature = "blocks")] +pub type MultiImageCapableOutputHandler = blocks::EscBlock< + fn( + status: os::Status, + info_flags: vt::DecodeInfoFlags, + image_buf: Option<&cv::ImageBuf>, + tagged_buf_group: Option<&cm::TaggedBufGroup>, + pts: cm::Time, + duration: cm::Time, + ), +>; + define_cf_type!( #[doc(alias = "VTDecompressionSessionRef")] Session(vt::Session) @@ -53,19 +63,19 @@ define_cf_type!( impl Session { pub fn new( - video_format_description: &cm::VideoFormatDesc, - video_decoder_specification: Option<&cf::Dictionary>, - destination_image_buffer_attirbutes: Option<&cf::Dictionary>, - output_callback: Option<&OutputCbRecord>, + video_format_desc: &cm::VideoFormatDesc, + video_decoder_spec: Option<&cf::Dictionary>, + dst_image_buf_attrs: Option<&cf::Dictionary>, + record: Option<&OutputCbRecord>, ) -> os::Result> { unsafe { os::result_unchecked(|res| { Self::create_in( None, - video_format_description, - video_decoder_specification, - destination_image_buffer_attirbutes, - std::mem::transmute(output_callback), + video_format_desc, + video_decoder_spec, + dst_image_buf_attrs, + std::mem::transmute(record), res, ) }) @@ -76,18 +86,18 @@ impl Session { /// Use safe new pub unsafe fn create_in( allocator: Option<&cf::Allocator>, - video_format_description: &cm::VideoFormatDesc, - video_decoder_specification: Option<&cf::Dictionary>, - destination_image_buffer_attirbutes: Option<&cf::Dictionary>, - output_callback: Option<&OutputCbRecord>, + video_format_desc: &cm::VideoFormatDesc, + video_decoder_spec: Option<&cf::Dictionary>, + destination_image_buf_attrs: Option<&cf::Dictionary>, + output_callback: *const OutputCbRecord, decompression_session_out: *mut Option>, ) -> os::Status { unsafe { VTDecompressionSessionCreate( allocator, - video_format_description, - video_decoder_specification, - destination_image_buffer_attirbutes, + video_format_desc, + video_decoder_spec, + destination_image_buf_attrs, output_callback, decompression_session_out, ) @@ -110,13 +120,13 @@ impl Session { #[inline] pub fn decode( &self, - sample_buffer: &SampleBuf, + sample_buf: &cm::SampleBuf, decode_flags: vt::DecodeFrameFlags, ) -> os::Result { unsafe { VTDecompressionSessionDecodeFrame( self, - sample_buffer, + sample_buf, decode_flags, std::ptr::null_mut(), std::ptr::null_mut(), @@ -130,7 +140,7 @@ impl Session { #[inline] pub unsafe fn decode_frame( &self, - sample_buffer: &SampleBuf, + sample_buf: &cm::SampleBuf, decode_flags: vt::DecodeFrameFlags, source_frame_ref_con: *mut F, info_flags_out: *mut vt::DecodeInfoFlags, @@ -138,7 +148,7 @@ impl Session { unsafe { VTDecompressionSessionDecodeFrame( self, - sample_buffer, + sample_buf, decode_flags, std::mem::transmute(source_frame_ref_con), info_flags_out, @@ -164,11 +174,26 @@ impl Session { /// /// The pixel buffer is in the same format that the session is decompressing to. #[inline] - pub fn copy_black_pixel_buffer(&self) -> os::Result> { + pub fn black_pixel_buf(&self) -> os::Result> { unsafe { os::result_unchecked(|res| VTDecompressionSessionCopyBlackPixelBuffer(self, res)) } } } +/// Multi-image decompression +impl Session { + #[api::available(macos = 14.0, ios = 17.0, visionos = 1.0)] + pub fn set_multi_image_cb( + &mut self, + cb: OutputMultiImageCb, + output_ptr: *mut c_void, + ) -> os::Result { + unsafe { + VTDecompressionSessionSetMultiImageCallback(self, std::mem::transmute(cb), output_ptr) + .result() + } + } +} + /// Indicates whether the current system supports hardware decode for a given codec /// /// This routine reports whether the current system supports hardware decode. Using @@ -178,7 +203,7 @@ impl Session { /// available at all times. #[doc(alias = "VTIsHardwareDecodeSupported")] #[inline] -pub fn is_hardware_decode_supported(codec_type: VideoCodec) -> bool { +pub fn is_hardware_decode_supported(codec_type: cm::VideoCodec) -> bool { unsafe { VTIsHardwareDecodeSupported(codec_type) } } @@ -199,7 +224,7 @@ unsafe extern "C-unwind" { video_format_description: &cm::VideoFormatDesc, video_decoder_specification: Option<&cf::Dictionary>, destination_image_buffer_attirbutes: Option<&cf::Dictionary>, - output_callback: Option<&OutputCbRecord>, + output_callback: *const OutputCbRecord, decompression_session_out: *mut Option>, ) -> os::Status; @@ -207,7 +232,7 @@ unsafe extern "C-unwind" { fn VTDecompressionSessionDecodeFrame( session: &Session, - sample_buffer: &SampleBuf, + sample_buffer: &cm::SampleBuf, decode_flags: vt::DecodeFrameFlags, source_frame_ref_con: *mut c_void, info_flags_out: *mut vt::DecodeInfoFlags, @@ -226,10 +251,15 @@ unsafe extern "C-unwind" { pixel_buffer_out: *mut Option>, ) -> os::Status; - fn VTIsHardwareDecodeSupported(codec_type: VideoCodec) -> bool; - + fn VTIsHardwareDecodeSupported(codec_type: cm::VideoCodec) -> bool; fn VTIsStereoMVHEVCDecodeSupported() -> bool; + #[api::available(macos = 14.0, ios = 17.0, visionos = 1.0)] + fn VTDecompressionSessionSetMultiImageCallback( + session: &mut Session, + output_multi_image_cb: OutputMultiImageCb, + output_multi_ref_con: *mut c_void, + ) -> os::Status; } #[cfg(test)] @@ -258,9 +288,9 @@ mod tests { ) { } - let ctx = Context {}; + let mut ctx = Context {}; - let _record = vt::DecompressionOutputCbRecord::new(ctx, callback); + let _record = vt::DecompressionOutputCbRecord::new(&mut ctx, Some(callback)); //vt::DecompressionSession::new(&desc, None, None, None).unwrap(); }