Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 33 additions & 31 deletions crates/camera/src/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,40 @@ pub(super) fn list_cameras_impl() -> impl Iterator<Item = CameraInfo> {

impl CameraInfo {
pub(super) fn formats_impl(&self) -> Option<Vec<Format>> {
let device = find_device(self)?;

let mut ret = vec![];

for format in device.formats().iter() {
let desc = format.format_desc();
let width = desc.dims().width as u32;
let height = desc.dims().height as u32;
let pixel_format = fourcc_display(desc.media_sub_type());

for fr_range in format.video_supported_frame_rate_ranges().iter() {
// SAFETY: trust me bro it crashes on intel mac otherwise
let fr_range = unsafe {
&*(fr_range as *const av::capture::device::FrameRateRange)
.cast::<AVFrameRateRange>()
};

let min = unsafe { fr_range.minFrameDuration() };

ret.push(Format {
native: format.retained(),
info: FormatInfo {
width,
height,
frame_rate: min.timescale as f32 / min.value as f32,
},
pixel_format: Some(pixel_format.clone()),
})
objc::ar_pool(|| {
let device = find_device(self)?;

let mut ret = vec![];

for format in device.formats().iter() {
let desc = format.format_desc();
let width = desc.dims().width as u32;
let height = desc.dims().height as u32;
let pixel_format = fourcc_display(desc.media_sub_type());

for fr_range in format.video_supported_frame_rate_ranges().iter() {
// SAFETY: trust me bro it crashes on intel mac otherwise
let fr_range = unsafe {
&*(fr_range as *const av::capture::device::FrameRateRange)
.cast::<AVFrameRateRange>()
};

let min = unsafe { fr_range.minFrameDuration() };

ret.push(Format {
native: format.retained(),
info: FormatInfo {
width,
height,
frame_rate: min.timescale as f32 / min.value as f32,
},
pixel_format: Some(pixel_format.clone()),
})
}
}
}

Some(ret)
Some(ret)
})
}
}

Expand Down Expand Up @@ -156,7 +158,7 @@ pub(super) fn start_capturing_impl(
let input =
av::capture::DeviceInput::with_device(&device).map_err(AVFoundationError::Static)?;

let queue = dispatch::Queue::new();
let queue = dispatch::Queue::serial_with_ar_pool();
let mut missing_image_bufs: u64 = 0;
let delegate =
CallbackOutputDelegate::with(CallbackOutputDelegateInner::new(Box::new(move |data| {
Expand Down
120 changes: 70 additions & 50 deletions crates/recording/src/output_pipeline/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,65 +457,85 @@ impl Muxer for AVFoundationMp4Muxer {
let mut retry_count = 0;
const MAX_RETRIES: u32 = 100;

loop {
let queue_result = {
let mut encoder = match encoder_clone.lock() {
Ok(e) => e,
Err(_) => {
let message = "MP4 encoder mutex poisoned".to_string();
set_fatal_error(&video_fatal_error, message.clone());
return Err(anyhow!(message));
}
let mut step_result = Ok(None);
cidre::objc::ar_pool(|| {
loop {
let queue_result = {
let mut encoder = match encoder_clone.lock() {
Ok(e) => e,
Err(_) => {
let message = "MP4 encoder mutex poisoned".to_string();
set_fatal_error(&video_fatal_error, message.clone());
step_result = Err(anyhow!(message));
return;
}
};
encoder.queue_video_frame(sample_buf.clone(), timestamp)
};
encoder.queue_video_frame(sample_buf.clone(), timestamp)
};

match queue_result {
Ok(()) => break,
Err(QueueFrameError::NotReadyForMore) => {
retry_count += 1;
if retry_count >= MAX_RETRIES {
encoder_busy_count += 1;
video_busy_thread.store(
encoder_busy_count,
std::sync::atomic::Ordering::Relaxed,
);
if encoder_busy_count <= 5 || encoder_busy_count.is_multiple_of(100) {
debug!(
match queue_result {
Ok(()) => {
step_result = Ok(None);
break;
}
Err(QueueFrameError::NotReadyForMore) => {
retry_count += 1;
if retry_count >= MAX_RETRIES {
encoder_busy_count += 1;
video_busy_thread.store(
encoder_busy_count,
"MP4 encoder busy, frame queued after max retries"
std::sync::atomic::Ordering::Relaxed,
);
if encoder_busy_count <= 5 || encoder_busy_count.is_multiple_of(100) {
debug!(
encoder_busy_count,
"MP4 encoder busy, frame queued after max retries"
);
}
step_result = Ok(None);
break;
}
std::thread::sleep(Duration::from_micros(500));
}
Err(QueueFrameError::WriterFailed(err)) => {
let total = video_count_thread
.load(std::sync::atomic::Ordering::Relaxed);
let message = format!(
"Failed to encode video frame: WriterFailed/{err:?} \
(frame #{total}, ts={timestamp:?})"
);
set_fatal_error(&video_fatal_error, message.clone());
step_result = Err(anyhow!(message));
return;
}
Err(QueueFrameError::Failed) => {
let total = video_count_thread
.load(std::sync::atomic::Ordering::Relaxed);
let message = format!(
"Failed to encode video frame: Failed \
(frame #{total}, ts={timestamp:?})"
);
set_fatal_error(&video_fatal_error, message.clone());
step_result = Err(anyhow!(message));
return;
}
Err(QueueFrameError::Finished) => {
step_result = Ok(Some(()));
return;
}
Err(e) => {
warn!("Failed to encode video frame: {e}");
step_result = Ok(None);
break;
}
std::thread::sleep(Duration::from_micros(500));
}
Err(QueueFrameError::WriterFailed(err)) => {
let total = video_count_thread
.load(std::sync::atomic::Ordering::Relaxed);
let message = format!(
"Failed to encode video frame: WriterFailed/{err:?} \
(frame #{total}, ts={timestamp:?})"
);
set_fatal_error(&video_fatal_error, message.clone());
return Err(anyhow!(message));
}
Err(QueueFrameError::Failed) => {
let total = video_count_thread
.load(std::sync::atomic::Ordering::Relaxed);
let message = format!(
"Failed to encode video frame: Failed \
(frame #{total}, ts={timestamp:?})"
);
set_fatal_error(&video_fatal_error, message.clone());
return Err(anyhow!(message));
}
Err(QueueFrameError::Finished) => return Ok(()),
Err(e) => {
warn!("Failed to encode video frame: {e}");
break;
}
}
});

match step_result {
Ok(Some(())) => return Ok(()),
Ok(None) => {}
Err(err) => return Err(err),
}

video_count_thread.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Expand Down
Loading