Skip to content

Commit

Permalink
fix: Windows/Mac compatibility for webcam
Browse files Browse the repository at this point in the history
  • Loading branch information
richiemcilroy committed Jan 14, 2025
1 parent 10506dd commit 58fa7a8
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 34 deletions.
92 changes: 59 additions & 33 deletions crates/media/src/feeds/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,23 @@ impl FrameConverter {
camera_format.frame_rate(),
);

// Create FFmpeg converter
// Create FFmpeg converter with platform-specific pixel format
let initial_pixel_format = if camera_format.format() == FrameFormat::YUYV {
#[cfg(target_os = "macos")]
{
ffmpeg::format::Pixel::UYVY422
}
#[cfg(not(target_os = "macos"))]
{
ffmpeg::format::Pixel::YUYV422
}
} else {
video_info.pixel_format
};

let context = ffmpeg::software::converter(
(video_info.width, video_info.height),
if camera_format.format() == FrameFormat::YUYV {
// Try YUYV422 first, if that doesn't work the converter will be recreated with UYVY422
ffmpeg::format::Pixel::YUYV422
} else {
video_info.pixel_format
},
initial_pixel_format,
ffmpeg::format::Pixel::RGBA,
)
.unwrap();
Expand All @@ -382,37 +390,55 @@ impl FrameConverter {

match self.format {
FrameFormat::YUYV => {
// Try converting with YUYV422 first
let result = self.convert_with_ffmpeg(buffer, resolution);

// If conversion fails (black/corrupted output), try with UYVY422
if result.iter().all(|&x| x == 0) {
// Recreate context with UYVY422
self.context = ffmpeg::software::converter(
(self.video_info.width, self.video_info.height),
ffmpeg::format::Pixel::UYVY422,
ffmpeg::format::Pixel::RGBA,
)
.unwrap();

// Try converting again with UYVY422
self.convert_with_ffmpeg(buffer, resolution)
// Use platform-specific pixel format
#[cfg(target_os = "macos")]
let pixel_format = ffmpeg::format::Pixel::UYVY422;
#[cfg(not(target_os = "macos"))]
let pixel_format = ffmpeg::format::Pixel::YUYV422;

// Create input frame with platform-specific format
let mut input_frame =
FFVideo::new(pixel_format, resolution.width(), resolution.height());

let stride = resolution.width() as usize * 2;
let src = buffer.buffer();

// Copy data line by line
{
let dst_stride = input_frame.stride(0);
let dst = input_frame.data_mut(0);
for y in 0..resolution.height() as usize {
let src_offset = y * stride;
let dst_offset = y * dst_stride;
dst[dst_offset..dst_offset + stride]
.copy_from_slice(&src[src_offset..src_offset + stride]);
}
}

// Create output frame
let mut rgba_frame = FFVideo::new(
ffmpeg::format::Pixel::RGBA,
resolution.width(),
resolution.height(),
);

// Convert the frame
if self.context.run(&input_frame, &mut rgba_frame).is_ok() {
rgba_frame.data(0).to_vec()
} else {
result
vec![0; (resolution.width() * resolution.height() * 4) as usize]
}
},
}
_ => match &self.hw_converter {
Some(HwConverter::NV12(converter)) => {
converter.convert(
NV12Input::from_buffer(
buffer.buffer(),
resolution.width(),
resolution.height(),
),
Some(HwConverter::NV12(converter)) => converter.convert(
NV12Input::from_buffer(
buffer.buffer(),
resolution.width(),
resolution.height(),
)
}
),
resolution.width(),
resolution.height(),
),
_ => self.convert_with_ffmpeg(buffer, resolution),
},
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"type": "module",
"scripts": {
"build": "dotenv -e .env -- turbo run build",
"dev": "(cd apps/web && docker compose up -d && cd ../..) && dotenv -e .env -- pnpm --dir packages/database db:generate && dotenv -e .env -- pnpm --dir packages/database db:push && dotenv -e .env -- turbo run dev --filter=!@cap/storybook --no-cache --concurrency 12",
"dev": "(RUST_BACKTRACE=1 cd apps/web && docker compose up -d && cd ../..) && dotenv -e .env -- pnpm --dir packages/database db:generate && dotenv -e .env -- pnpm --dir packages/database db:push && dotenv -e .env -- turbo run dev --filter=!@cap/storybook --no-cache --concurrency 12",
"dev:manual": "dotenv -e .env -- turbo run dev --filter=!@cap/storybook --no-cache --concurrency 1",
"lint": "turbo run lint",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
Expand Down

1 comment on commit 58fa7a8

@vercel
Copy link

@vercel vercel bot commented on 58fa7a8 Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.