1#![allow(non_snake_case)]
2#![allow(non_camel_case_types)]
3
4mod bindings;
5
6#[cfg(target_os = "macos")]
7pub mod core_media {
8 #![allow(non_snake_case)]
9
10 pub use crate::bindings::{
11 CMItemIndex, CMSampleTimingInfo, CMTime, CMTimeMake, CMVideoCodecType,
12 kCMSampleAttachmentKey_NotSync, kCMTimeInvalid, kCMVideoCodecType_H264,
13 };
14 use anyhow::{Result, anyhow};
15 use core_foundation::{
16 array::{CFArray, CFArrayRef},
17 base::{CFTypeID, OSStatus, TCFType},
18 declare_TCFType,
19 dictionary::CFDictionary,
20 impl_CFTypeDescription, impl_TCFType,
21 string::CFString,
22 };
23 use core_video::image_buffer::{CVImageBuffer, CVImageBufferRef};
24 use std::{ffi::c_void, ptr};
25
26 #[repr(C)]
27 pub struct __CMSampleBuffer(c_void);
28 // The ref type must be a pointer to the underlying struct.
29 pub type CMSampleBufferRef = *const __CMSampleBuffer;
30
31 declare_TCFType!(CMSampleBuffer, CMSampleBufferRef);
32 impl_TCFType!(CMSampleBuffer, CMSampleBufferRef, CMSampleBufferGetTypeID);
33 impl_CFTypeDescription!(CMSampleBuffer);
34
35 impl CMSampleBuffer {
36 pub fn attachments(&self) -> Vec<CFDictionary<CFString>> {
37 unsafe {
38 let attachments =
39 CMSampleBufferGetSampleAttachmentsArray(self.as_concrete_TypeRef(), true);
40 CFArray::<CFDictionary>::wrap_under_get_rule(attachments)
41 .into_iter()
42 .map(|attachments| {
43 CFDictionary::wrap_under_get_rule(attachments.as_concrete_TypeRef())
44 })
45 .collect()
46 }
47 }
48
49 pub fn image_buffer(&self) -> Option<CVImageBuffer> {
50 unsafe {
51 let ptr = CMSampleBufferGetImageBuffer(self.as_concrete_TypeRef());
52 if ptr.is_null() {
53 None
54 } else {
55 Some(CVImageBuffer::wrap_under_get_rule(ptr))
56 }
57 }
58 }
59
60 pub fn sample_timing_info(&self, index: usize) -> Result<CMSampleTimingInfo> {
61 unsafe {
62 let mut timing_info = CMSampleTimingInfo {
63 duration: kCMTimeInvalid,
64 presentationTimeStamp: kCMTimeInvalid,
65 decodeTimeStamp: kCMTimeInvalid,
66 };
67 let result = CMSampleBufferGetSampleTimingInfo(
68 self.as_concrete_TypeRef(),
69 index as CMItemIndex,
70 &mut timing_info,
71 );
72
73 if result == 0 {
74 Ok(timing_info)
75 } else {
76 Err(anyhow!("error getting sample timing info, code {}", result))
77 }
78 }
79 }
80
81 pub fn format_description(&self) -> CMFormatDescription {
82 unsafe {
83 CMFormatDescription::wrap_under_get_rule(CMSampleBufferGetFormatDescription(
84 self.as_concrete_TypeRef(),
85 ))
86 }
87 }
88
89 pub fn data(&self) -> CMBlockBuffer {
90 unsafe {
91 CMBlockBuffer::wrap_under_get_rule(CMSampleBufferGetDataBuffer(
92 self.as_concrete_TypeRef(),
93 ))
94 }
95 }
96 }
97
98 #[link(name = "CoreMedia", kind = "framework")]
99 unsafe extern "C" {
100 fn CMSampleBufferGetTypeID() -> CFTypeID;
101 fn CMSampleBufferGetSampleAttachmentsArray(
102 buffer: CMSampleBufferRef,
103 create_if_necessary: bool,
104 ) -> CFArrayRef;
105 fn CMSampleBufferGetImageBuffer(buffer: CMSampleBufferRef) -> CVImageBufferRef;
106 fn CMSampleBufferGetSampleTimingInfo(
107 buffer: CMSampleBufferRef,
108 index: CMItemIndex,
109 timing_info_out: *mut CMSampleTimingInfo,
110 ) -> OSStatus;
111 fn CMSampleBufferGetFormatDescription(buffer: CMSampleBufferRef) -> CMFormatDescriptionRef;
112 fn CMSampleBufferGetDataBuffer(sample_buffer: CMSampleBufferRef) -> CMBlockBufferRef;
113 }
114
115 #[repr(C)]
116 pub struct __CMFormatDescription(c_void);
117 pub type CMFormatDescriptionRef = *const __CMFormatDescription;
118
119 declare_TCFType!(CMFormatDescription, CMFormatDescriptionRef);
120 impl_TCFType!(
121 CMFormatDescription,
122 CMFormatDescriptionRef,
123 CMFormatDescriptionGetTypeID
124 );
125 impl_CFTypeDescription!(CMFormatDescription);
126
127 impl CMFormatDescription {
128 pub fn h264_parameter_set_count(&self) -> usize {
129 unsafe {
130 let mut count = 0;
131 let result = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
132 self.as_concrete_TypeRef(),
133 0,
134 ptr::null_mut(),
135 ptr::null_mut(),
136 &mut count,
137 ptr::null_mut(),
138 );
139 assert_eq!(result, 0);
140 count
141 }
142 }
143
144 pub fn h264_parameter_set_at_index(&self, index: usize) -> Result<&[u8]> {
145 unsafe {
146 let mut bytes = ptr::null();
147 let mut len = 0;
148 let result = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
149 self.as_concrete_TypeRef(),
150 index,
151 &mut bytes,
152 &mut len,
153 ptr::null_mut(),
154 ptr::null_mut(),
155 );
156 if result == 0 {
157 Ok(std::slice::from_raw_parts(bytes, len))
158 } else {
159 Err(anyhow!("error getting parameter set, code: {}", result))
160 }
161 }
162 }
163 }
164
165 #[link(name = "CoreMedia", kind = "framework")]
166 unsafe extern "C" {
167 fn CMFormatDescriptionGetTypeID() -> CFTypeID;
168 fn CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
169 video_desc: CMFormatDescriptionRef,
170 parameter_set_index: usize,
171 parameter_set_pointer_out: *mut *const u8,
172 parameter_set_size_out: *mut usize,
173 parameter_set_count_out: *mut usize,
174 NALUnitHeaderLengthOut: *mut isize,
175 ) -> OSStatus;
176 }
177
178 #[repr(C)]
179 pub struct __CMBlockBuffer(c_void);
180 pub type CMBlockBufferRef = *const __CMBlockBuffer;
181
182 declare_TCFType!(CMBlockBuffer, CMBlockBufferRef);
183 impl_TCFType!(CMBlockBuffer, CMBlockBufferRef, CMBlockBufferGetTypeID);
184 impl_CFTypeDescription!(CMBlockBuffer);
185
186 impl CMBlockBuffer {
187 pub fn bytes(&self) -> &[u8] {
188 unsafe {
189 let mut bytes = ptr::null();
190 let mut len = 0;
191 let result = CMBlockBufferGetDataPointer(
192 self.as_concrete_TypeRef(),
193 0,
194 &mut 0,
195 &mut len,
196 &mut bytes,
197 );
198 assert!(result == 0, "could not get block buffer data");
199 std::slice::from_raw_parts(bytes, len)
200 }
201 }
202 }
203
204 #[link(name = "CoreMedia", kind = "framework")]
205 unsafe extern "C" {
206 fn CMBlockBufferGetTypeID() -> CFTypeID;
207 fn CMBlockBufferGetDataPointer(
208 buffer: CMBlockBufferRef,
209 offset: usize,
210 length_at_offset_out: *mut usize,
211 total_length_out: *mut usize,
212 data_pointer_out: *mut *const u8,
213 ) -> OSStatus;
214 }
215}
216
217#[cfg(target_os = "macos")]
218pub mod core_video {
219 #![allow(non_snake_case)]
220
221 #[cfg(target_os = "macos")]
222 use core_foundation::{
223 base::{CFTypeID, TCFType},
224 declare_TCFType, impl_CFTypeDescription, impl_TCFType,
225 };
226 #[cfg(target_os = "macos")]
227 use std::ffi::c_void;
228
229 use crate::bindings::{CVReturn, kCVReturnSuccess};
230 pub use crate::bindings::{
231 kCVPixelFormatType_32BGRA, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
232 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, kCVPixelFormatType_420YpCbCr8Planar,
233 };
234 use anyhow::{Result, anyhow};
235 use core_foundation::{
236 base::kCFAllocatorDefault, dictionary::CFDictionaryRef, mach_port::CFAllocatorRef,
237 };
238 use foreign_types::ForeignTypeRef;
239
240 use metal::{MTLDevice, MTLPixelFormat};
241 use std::ptr;
242
243 #[repr(C)]
244 pub struct __CVMetalTextureCache(c_void);
245 pub type CVMetalTextureCacheRef = *const __CVMetalTextureCache;
246
247 declare_TCFType!(CVMetalTextureCache, CVMetalTextureCacheRef);
248 impl_TCFType!(
249 CVMetalTextureCache,
250 CVMetalTextureCacheRef,
251 CVMetalTextureCacheGetTypeID
252 );
253 impl_CFTypeDescription!(CVMetalTextureCache);
254
255 impl CVMetalTextureCache {
256 /// # Safety
257 ///
258 /// metal_device must be valid according to CVMetalTextureCacheCreate
259 pub unsafe fn new(metal_device: *mut MTLDevice) -> Result<Self> {
260 let mut this = ptr::null();
261 let result = unsafe {
262 CVMetalTextureCacheCreate(
263 kCFAllocatorDefault,
264 ptr::null(),
265 metal_device,
266 ptr::null(),
267 &mut this,
268 )
269 };
270 if result == kCVReturnSuccess {
271 unsafe { Ok(CVMetalTextureCache::wrap_under_create_rule(this)) }
272 } else {
273 Err(anyhow!("could not create texture cache, code: {}", result))
274 }
275 }
276
277 /// # Safety
278 ///
279 /// The arguments to this function must be valid according to CVMetalTextureCacheCreateTextureFromImage
280 pub unsafe fn create_texture_from_image(
281 &self,
282 source: ::core_video::image_buffer::CVImageBufferRef,
283 texture_attributes: CFDictionaryRef,
284 pixel_format: MTLPixelFormat,
285 width: usize,
286 height: usize,
287 plane_index: usize,
288 ) -> Result<CVMetalTexture> {
289 let mut this = ptr::null();
290 let result = unsafe {
291 CVMetalTextureCacheCreateTextureFromImage(
292 kCFAllocatorDefault,
293 self.as_concrete_TypeRef(),
294 source,
295 texture_attributes,
296 pixel_format,
297 width,
298 height,
299 plane_index,
300 &mut this,
301 )
302 };
303 if result == kCVReturnSuccess {
304 unsafe { Ok(CVMetalTexture::wrap_under_create_rule(this)) }
305 } else {
306 Err(anyhow!("could not create texture, code: {}", result))
307 }
308 }
309 }
310
311 #[link(name = "CoreVideo", kind = "framework")]
312 unsafe extern "C" {
313 fn CVMetalTextureCacheGetTypeID() -> CFTypeID;
314 fn CVMetalTextureCacheCreate(
315 allocator: CFAllocatorRef,
316 cache_attributes: CFDictionaryRef,
317 metal_device: *const MTLDevice,
318 texture_attributes: CFDictionaryRef,
319 cache_out: *mut CVMetalTextureCacheRef,
320 ) -> CVReturn;
321 fn CVMetalTextureCacheCreateTextureFromImage(
322 allocator: CFAllocatorRef,
323 texture_cache: CVMetalTextureCacheRef,
324 source_image: ::core_video::image_buffer::CVImageBufferRef,
325 texture_attributes: CFDictionaryRef,
326 pixel_format: MTLPixelFormat,
327 width: usize,
328 height: usize,
329 plane_index: usize,
330 texture_out: *mut CVMetalTextureRef,
331 ) -> CVReturn;
332 }
333
334 #[repr(C)]
335 pub struct __CVMetalTexture(c_void);
336 pub type CVMetalTextureRef = *const __CVMetalTexture;
337
338 declare_TCFType!(CVMetalTexture, CVMetalTextureRef);
339 impl_TCFType!(CVMetalTexture, CVMetalTextureRef, CVMetalTextureGetTypeID);
340 impl_CFTypeDescription!(CVMetalTexture);
341
342 impl CVMetalTexture {
343 pub fn as_texture_ref(&self) -> &metal::TextureRef {
344 unsafe {
345 let texture = CVMetalTextureGetTexture(self.as_concrete_TypeRef());
346 metal::TextureRef::from_ptr(texture as *mut _)
347 }
348 }
349 }
350
351 #[link(name = "CoreVideo", kind = "framework")]
352 unsafe extern "C" {
353 fn CVMetalTextureGetTypeID() -> CFTypeID;
354 fn CVMetalTextureGetTexture(texture: CVMetalTextureRef) -> *mut c_void;
355 }
356}