1use super::ffi;
4use super::{
5 AudioBuffer, AudioBufferList, AudioBufferListRaw, CMBlockBuffer, CMFormatDescription,
6 CMSampleTimingInfo, CMTime, CVPixelBuffer, SCFrameStatus,
7};
8use std::fmt;
9
10#[repr(transparent)]
12#[derive(Debug)]
13pub struct CMSampleBuffer(*mut std::ffi::c_void);
14
15impl PartialEq for CMSampleBuffer {
16 fn eq(&self, other: &Self) -> bool {
17 self.0 == other.0
18 }
19}
20
21impl Eq for CMSampleBuffer {}
22
23impl std::hash::Hash for CMSampleBuffer {
24 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
25 unsafe {
26 let hash_value = ffi::cm_sample_buffer_hash(self.0);
27 hash_value.hash(state);
28 }
29 }
30}
31
32impl CMSampleBuffer {
33 pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
34 if ptr.is_null() {
35 None
36 } else {
37 Some(Self(ptr))
38 }
39 }
40
41 pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
44 Self(ptr)
45 }
46
47 pub fn as_ptr(&self) -> *mut std::ffi::c_void {
48 self.0
49 }
50
51 pub fn create_for_image_buffer(
88 image_buffer: &CVPixelBuffer,
89 presentation_time: CMTime,
90 duration: CMTime,
91 ) -> Result<Self, i32> {
92 unsafe {
93 let mut sample_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
94 let status = ffi::cm_sample_buffer_create_for_image_buffer(
95 image_buffer.as_ptr(),
96 presentation_time.value,
97 presentation_time.timescale,
98 duration.value,
99 duration.timescale,
100 &mut sample_buffer_ptr,
101 );
102
103 if status == 0 && !sample_buffer_ptr.is_null() {
104 Ok(Self(sample_buffer_ptr))
105 } else {
106 Err(status)
107 }
108 }
109 }
110
111 pub fn get_image_buffer(&self) -> Option<CVPixelBuffer> {
112 unsafe {
113 let ptr = ffi::cm_sample_buffer_get_image_buffer(self.0);
114 CVPixelBuffer::from_raw(ptr)
115 }
116 }
117
118 pub fn get_frame_status(&self) -> Option<SCFrameStatus> {
145 unsafe {
146 let status = ffi::cm_sample_buffer_get_frame_status(self.0);
147 if status >= 0 {
148 SCFrameStatus::from_raw(status)
149 } else {
150 None
151 }
152 }
153 }
154
155 pub fn get_presentation_timestamp(&self) -> CMTime {
156 unsafe {
157 let mut value: i64 = 0;
158 let mut timescale: i32 = 0;
159 let mut flags: u32 = 0;
160 let mut epoch: i64 = 0;
161 ffi::cm_sample_buffer_get_presentation_timestamp(
162 self.0,
163 &mut value,
164 &mut timescale,
165 &mut flags,
166 &mut epoch,
167 );
168 CMTime {
169 value,
170 timescale,
171 flags,
172 epoch,
173 }
174 }
175 }
176
177 pub fn get_duration(&self) -> CMTime {
178 unsafe {
179 let mut value: i64 = 0;
180 let mut timescale: i32 = 0;
181 let mut flags: u32 = 0;
182 let mut epoch: i64 = 0;
183 ffi::cm_sample_buffer_get_duration(
184 self.0,
185 &mut value,
186 &mut timescale,
187 &mut flags,
188 &mut epoch,
189 );
190 CMTime {
191 value,
192 timescale,
193 flags,
194 epoch,
195 }
196 }
197 }
198
199 pub fn is_valid(&self) -> bool {
200 unsafe { ffi::cm_sample_buffer_is_valid(self.0) }
201 }
202
203 pub fn get_num_samples(&self) -> usize {
204 unsafe { ffi::cm_sample_buffer_get_num_samples(self.0) }
205 }
206
207 pub fn get_audio_buffer_list(&self) -> Option<AudioBufferList> {
208 unsafe {
209 let mut num_buffers: u32 = 0;
210 let mut buffers_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
211 let mut buffers_len: usize = 0;
212
213 ffi::cm_sample_buffer_get_audio_buffer_list(
214 self.0,
215 &mut num_buffers,
216 &mut buffers_ptr,
217 &mut buffers_len,
218 );
219
220 if num_buffers == 0 {
221 None
222 } else {
223 Some(AudioBufferList {
224 inner: AudioBufferListRaw {
225 num_buffers,
226 buffers_ptr: buffers_ptr.cast::<AudioBuffer>(),
227 buffers_len,
228 },
229 })
230 }
231 }
232 }
233
234 pub fn get_data_buffer(&self) -> Option<CMBlockBuffer> {
235 unsafe {
236 let ptr = ffi::cm_sample_buffer_get_data_buffer(self.0);
237 CMBlockBuffer::from_raw(ptr)
238 }
239 }
240
241 pub fn get_decode_timestamp(&self) -> CMTime {
243 unsafe {
244 let mut value: i64 = 0;
245 let mut timescale: i32 = 0;
246 let mut flags: u32 = 0;
247 let mut epoch: i64 = 0;
248 ffi::cm_sample_buffer_get_decode_timestamp(
249 self.0,
250 &mut value,
251 &mut timescale,
252 &mut flags,
253 &mut epoch,
254 );
255 CMTime {
256 value,
257 timescale,
258 flags,
259 epoch,
260 }
261 }
262 }
263
264 pub fn get_output_presentation_timestamp(&self) -> CMTime {
266 unsafe {
267 let mut value: i64 = 0;
268 let mut timescale: i32 = 0;
269 let mut flags: u32 = 0;
270 let mut epoch: i64 = 0;
271 ffi::cm_sample_buffer_get_output_presentation_timestamp(
272 self.0,
273 &mut value,
274 &mut timescale,
275 &mut flags,
276 &mut epoch,
277 );
278 CMTime {
279 value,
280 timescale,
281 flags,
282 epoch,
283 }
284 }
285 }
286
287 pub fn set_output_presentation_timestamp(&self, time: CMTime) -> Result<(), i32> {
293 unsafe {
294 let status = ffi::cm_sample_buffer_set_output_presentation_timestamp(
295 self.0,
296 time.value,
297 time.timescale,
298 time.flags,
299 time.epoch,
300 );
301 if status == 0 {
302 Ok(())
303 } else {
304 Err(status)
305 }
306 }
307 }
308
309 pub fn get_sample_size(&self, index: usize) -> usize {
311 unsafe { ffi::cm_sample_buffer_get_sample_size(self.0, index) }
312 }
313
314 pub fn get_total_sample_size(&self) -> usize {
316 unsafe { ffi::cm_sample_buffer_get_total_sample_size(self.0) }
317 }
318
319 pub fn is_data_ready(&self) -> bool {
321 unsafe { ffi::cm_sample_buffer_is_ready_for_data_access(self.0) }
322 }
323
324 pub fn make_data_ready(&self) -> Result<(), i32> {
330 unsafe {
331 let status = ffi::cm_sample_buffer_make_data_ready(self.0);
332 if status == 0 {
333 Ok(())
334 } else {
335 Err(status)
336 }
337 }
338 }
339
340 pub fn get_format_description(&self) -> Option<CMFormatDescription> {
342 unsafe {
343 let ptr = ffi::cm_sample_buffer_get_format_description(self.0);
344 CMFormatDescription::from_raw(ptr)
345 }
346 }
347
348 pub fn get_sample_timing_info(&self, index: usize) -> Result<CMSampleTimingInfo, i32> {
354 unsafe {
355 let mut timing_info = CMSampleTimingInfo {
356 duration: CMTime::INVALID,
357 presentation_time_stamp: CMTime::INVALID,
358 decode_time_stamp: CMTime::INVALID,
359 };
360 let status = ffi::cm_sample_buffer_get_sample_timing_info(
361 self.0,
362 index,
363 &mut timing_info.duration.value,
364 &mut timing_info.duration.timescale,
365 &mut timing_info.duration.flags,
366 &mut timing_info.duration.epoch,
367 &mut timing_info.presentation_time_stamp.value,
368 &mut timing_info.presentation_time_stamp.timescale,
369 &mut timing_info.presentation_time_stamp.flags,
370 &mut timing_info.presentation_time_stamp.epoch,
371 &mut timing_info.decode_time_stamp.value,
372 &mut timing_info.decode_time_stamp.timescale,
373 &mut timing_info.decode_time_stamp.flags,
374 &mut timing_info.decode_time_stamp.epoch,
375 );
376 if status == 0 {
377 Ok(timing_info)
378 } else {
379 Err(status)
380 }
381 }
382 }
383
384 pub fn get_sample_timing_info_array(&self) -> Result<Vec<CMSampleTimingInfo>, i32> {
390 let num_samples = self.get_num_samples();
391 let mut result = Vec::with_capacity(num_samples);
392 for i in 0..num_samples {
393 result.push(self.get_sample_timing_info(i)?);
394 }
395 Ok(result)
396 }
397
398 pub fn invalidate(&self) -> Result<(), i32> {
404 unsafe {
405 let status = ffi::cm_sample_buffer_invalidate(self.0);
406 if status == 0 {
407 Ok(())
408 } else {
409 Err(status)
410 }
411 }
412 }
413
414 pub fn create_copy_with_new_timing(
420 &self,
421 timing_info: &[CMSampleTimingInfo],
422 ) -> Result<Self, i32> {
423 unsafe {
424 let mut new_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
425 let status = ffi::cm_sample_buffer_create_copy_with_new_timing(
426 self.0,
427 timing_info.len(),
428 timing_info.as_ptr().cast::<std::ffi::c_void>(),
429 &mut new_buffer_ptr,
430 );
431 if status == 0 && !new_buffer_ptr.is_null() {
432 Ok(Self(new_buffer_ptr))
433 } else {
434 Err(status)
435 }
436 }
437 }
438
439 pub fn copy_pcm_data_into_audio_buffer_list(
445 &self,
446 frame_offset: i32,
447 num_frames: i32,
448 buffer_list: &mut AudioBufferList,
449 ) -> Result<(), i32> {
450 unsafe {
451 let status = ffi::cm_sample_buffer_copy_pcm_data_into_audio_buffer_list(
452 self.0,
453 frame_offset,
454 num_frames,
455 (buffer_list as *mut AudioBufferList).cast::<std::ffi::c_void>(),
456 );
457 if status == 0 {
458 Ok(())
459 } else {
460 Err(status)
461 }
462 }
463 }
464}
465
466impl Drop for CMSampleBuffer {
467 fn drop(&mut self) {
468 unsafe {
469 ffi::cm_sample_buffer_release(self.0);
470 }
471 }
472}
473
474unsafe impl Send for CMSampleBuffer {}
475unsafe impl Sync for CMSampleBuffer {}
476
477impl fmt::Display for CMSampleBuffer {
478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479 write!(
480 f,
481 "CMSampleBuffer(pts: {}, duration: {}, samples: {})",
482 self.get_presentation_timestamp(),
483 self.get_duration(),
484 self.get_num_samples()
485 )
486 }
487}