Skip to content

Conversation

@Brendonovich
Copy link
Contributor

@Brendonovich Brendonovich commented Sep 18, 2025

According to Chromium, rgb32 formats on Windows need their y axis inverted:
image
Additionally, ARGB is technically represented as BGRA - at least when using NVIDIA Broadcast. Maybe this needs to be more finetuned.

Summary by CodeRabbit

  • New Features

    • Recording CLI now captures from the first detected NVIDIA camera.
    • Improved Windows camera support and integration.
  • Bug Fixes

    • Corrected color ordering and vertical orientation for Windows camera frames for accurate previews/recordings.
    • More reliable camera switching with graceful handoff during reattachment.
  • Chores

    • Updated Windows-target dependencies/features.
  • Style

    • Minor type declaration formatting cleanup (consistent import quoting).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 18, 2025

Walkthrough

Renamed CapturedFrameExt::to_ffmpeg → as_ffmpeg with ToFfmpegError → AsFFmpegError across camera-ffmpeg; updated platform implementations and example usage; Windows pixel ordering and vertical row handling adjusted; recording crate wired to use camera feed (NVIDIA selection) with added tracing; minor Cargo and type-format tweaks.

Changes

Cohort / File(s) Summary
FFmpeg API rename & platform impls
crates/camera-ffmpeg/src/lib.rs, crates/camera-ffmpeg/src/macos.rs, crates/camera-ffmpeg/src/windows.rs, crates/camera-ffmpeg/examples/cli.rs
Renamed trait method to_ffmpegas_ffmpeg and error type ToFfmpegErrorAsFFmpegError; updated example call; Windows implementation changed color ordering (use BGRA for ARGB) and vertically flips input rows for ARGB/RGB32 paths.
Recording crate — camera wiring & logging
crates/recording/src/feeds/camera.rs, crates/recording/examples/recording-cli.rs
Example switched from mic to camera (selects first NVIDIA camera); uses CameraFeed::spawn and sets camera input; removed mic setup; added lifecycle traces and graceful reattach signaling; replaced to_ffmpeg calls with as_ffmpeg.
Cargo manifest adjustments
crates/camera-directshow/Cargo.toml, crates/recording/Cargo.toml
Added Win32_System_Performance feature to Windows bindings in camera-directshow Cargo.toml; added Windows-target dependency cap-camera-windows = { path = "../camera-windows" } to recording Cargo.toml.
Type formatting tweak
packages/ui-solid/src/auto-imports.d.ts
Changed import path quotes in ambient type for IconCapStopCircle from double to single quotes (formatting-only).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant CLI as Recording CLI
  participant Feed as CameraFeed Actor
  participant Dev as Camera Device
  participant Conv as FFmpeg Converter
  participant Rec as StudioRecording

  CLI->>Feed: SetInput(DeviceOrModelID)
  Note over Feed: If existing attached camera, signal done_tx then attach new
  Feed->>Dev: start_capture()
  Dev-->>Feed: native frames

  loop per frame
    Feed->>Conv: as_ffmpeg(frame)
    Conv-->>Feed: ffmpeg::frame::Video or AsFFmpegError
  end

  CLI->>Feed: ask(Lock)
  Feed-->>CLI: Arc<LockedCameraFeed>
  CLI->>Rec: with_camera_feed(Arc...)
  CLI->>Feed: stop / detach
  Note over Feed: "Waiting for camera to be done" → stop_capture() → "Stopped capture"
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

codex

Poem

In cables and frames my whiskers twitch—
I flip the rows and hop to BGRA switch.
From to_ffmpeg to as_ffmpeg I bound,
Error names neat, conversions sound.
Cameras click, recordings glow—🐇🎬

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely and accurately summarizes the primary change: improved handling of Windows RGB/ARGB formats. It maps directly to the changes in crates/camera-ffmpeg/src/windows.rs (channel ordering and vertical inversion) and matches the PR description, so it is specific and informative for reviewers scanning history.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch windows-camera-argb

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c869b33 and 65357f6.

📒 Files selected for processing (1)
  • crates/camera-ffmpeg/src/windows.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/camera-ffmpeg/src/windows.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
crates/camera-ffmpeg/src/macos.rs (1)

16-23: Avoid unwrap() to prevent panics in library code.

Propagate an error when the format description is unavailable.

-        let format_desc = native.sample_buf().format_desc().unwrap();
+        let Some(format_desc) = native.sample_buf().format_desc() else {
+            return Err(AsFFmpegError::MissingFormatDesc);
+        };

This should satisfy clippy’s unwrap_used if enabled.

crates/camera-ffmpeg/src/windows.rs (2)

106-112: Fix RGB24 copy: use 3 bytes/pixel and correct per-row indexing

crates/camera-ffmpeg/src/windows.rs — PixelFormat::RGB24 branch. RGB24 is 3 bytes/pixel; current loop uses width*4 and reads from bytes[height * row_width] each iteration (wrong and OOB).

-                for y in 0..height {
-                    let row_width = width * 4;
-                    let src_row = &bytes[height * row_width..];
+                for y in 0..height {
+                    let row_width = width * 3;
+                    let src_row = &bytes[y * row_width..];
                     let dest_row = &mut ff_frame.data_mut(0)[y * stride..];
 
                     dest_row[0..row_width].copy_from_slice(&src_row[0..row_width]);
                 }

If Windows RGB24 is bottom-up, flip rows as done for ARGB/RGB32: use (height - 1 - y) * row_width.


117-129: Replace Pixel::RGB32 with BGRA (Windows RGB32 is BGRA on little-endian).

MEDIASUBTYPE_RGB32 / MFVideoFormat_RGB32 is laid out as Blue,Green,Red,Alpha (or don't‑care) on little‑endian — use Pixel::BGRA to avoid channel swaps; if the alpha byte is always unused prefer Pixel::BGR0. Y‑flip in the branch is correct.

File: crates/camera-ffmpeg/src/windows.rs (PixelFormat::RGB32 branch)

-                let mut ff_frame = FFVideo::new(Pixel::RGB32, width as u32, height as u32);
+                let mut ff_frame = FFVideo::new(Pixel::BGRA, width as u32, height as u32);
🧹 Nitpick comments (12)
crates/camera-ffmpeg/src/macos.rs (1)

8-13: Unify/extend error type to cover format-desc absence.

Add a non-panicking variant (used below) and keep variants platform-consistent where feasible.

 #[derive(thiserror::Error, Debug)]
 pub enum AsFFmpegError {
     #[error("Unsupported media subtype '{0}'")]
     UnsupportedSubType(String),
+    #[error("Failed to get sample buffer format description")]
+    MissingFormatDesc,
     #[error("{0}")]
     Native(#[from] cidre::os::Error),
 }
crates/camera-ffmpeg/examples/cli.rs (1)

26-29: Surface the conversion error for easier debugging.

Print the concrete AsFFmpegError.

-            let Ok(ff_frame) = frame.as_ffmpeg() else {
-                eprintln!("Failed to convert frame to FFmpeg");
-                return;
-            };
+            let ff_frame = match frame.as_ffmpeg() {
+                Ok(f) => f,
+                Err(e) => {
+                    eprintln!("Failed to convert frame to FFmpeg: {e}");
+                    return;
+                }
+            };
crates/recording/examples/recording-cli.rs (6)

28-30: Avoid hard‑panic on camera selection; add fallback and case‑insensitive match.

Unwrapping here will panic on non‑NVIDIA setups. Prefer a case‑insensitive match and fallback to first available camera (or bail with a clear error).

Apply this diff:

-    let camera_info = cap_camera::list_cameras()
-        .find(|c| c.display_name().contains("NVIDIA"))
-        .unwrap();
+    let camera_info = cap_camera::list_cameras()
+        .find(|c| c.display_name().to_ascii_uppercase().contains("NVIDIA"))
+        .or_else(|| cap_camera::list_cameras().next())
+        .expect("No cameras found on the system");

32-32: Consider propagating SetInput errors instead of unwrap‑chain.

The example will panic on device/format errors. Return a Result or log and exit cleanly.

Apply this diff:

-    let camera_feed = CameraFeed::spawn(CameraFeed::default());
+    let camera_feed = CameraFeed::spawn(CameraFeed::default());

And below (lines 34‑41), replace unwraps (see next comment) with proper handling.


34-41: Replace double .unwrap().await.unwrap() with error propagation.

This masks whether the actor call or device init failed.

-    camera_feed
-        .ask(feeds::camera::SetInput {
-            id: feeds::camera::DeviceOrModelID::from_info(&camera_info),
-        })
-        .await
-        .unwrap()
-        .await
-        .unwrap();
+    if let Err(e) = camera_feed
+        .ask(feeds::camera::SetInput {
+            id: feeds::camera::DeviceOrModelID::from_info(&camera_info),
+        })
+        .await
+        .and_then(|fut| futures::executor::block_on(fut))
+    {
+        eprintln!("Failed to set camera input: {e}");
+        return;
+    }

43-60: Remove dead/commented mic code and the unused feeds::microphone import.

Keeps the example clean and avoids unused‑import warnings with strict lints.

If desired, move this to a separate example file instead of commented blocks.


9-10: Drop unnecessary unsafe around std::env::set_var.

set_var is safe; unnecessary unsafe triggers clippy.

-    unsafe { std::env::set_var("RUST_LOG", "trace") };
-    unsafe { std::env::set_var("RUST_BACKTRACE", "1") };
+    std::env::set_var("RUST_LOG", "trace");
+    std::env::set_var("RUST_BACKTRACE", "1");

21-23: Remove unused scratch dir writes to /tmp/bruh.

These side effects don’t affect the example and may be surprising on non‑Linux hosts.

-    let _ = std::fs::remove_dir_all("/tmp/bruh");
-    let _ = std::fs::create_dir("/tmp/bruh");
+    // removed: stray tmp dir writes
crates/recording/src/feeds/camera.rs (2)

385-394: Typo in log message and minor log polish.

Fix “Stoppping” and consider making the three messages consistent in level (trace/info).

-                trace!("Waiting for camera to be done");
+                trace!("Waiting for camera to be done");
...
-                trace!("Stoppping capture of {:?}", &id);
+                trace!("Stopping capture of {:?}", &id);
...
-                info!("Stopped capture of {:?}", &id);
+                trace!("Stopped capture of {:?}", &id);

355-395: Avoid creating a new Tokio runtime per input — reuse an existing runtime or spawn onto it.

Found instances: crates/recording/src/feeds/camera.rs:355 and apps/desktop/src-tauri/src/camera.rs:121.
Problem: per-call Runtime::new() spawns extra threads and complicates shutdown.
Fixes (pick one): use tokio::spawn / tokio::task::spawn_blocking on an existing runtime, pass a Runtime/Handle into the worker, or create a single dedicated runtime owned by the actor.

crates/camera-ffmpeg/src/windows.rs (2)

82-97: ARGB → BGRA + vertical flip: good, but document source semantics.

Change is correct for little‑endian ARGB. Add a brief comment (endianness, bottom‑up DIB semantics) to prevent regressions.

Example doc:

  • Windows ARGB32 memory order: BGRA on little‑endian.
  • Many RGB family frames are bottom‑up; we reverse rows here.

55-76: NV12 copy shadows src_row; harmless but slightly confusing.

Minor readability: avoid re‑binding src_row inside loop.

-                let stride = ff_frame.stride(1);
-                let src_row = &bytes[width * height..];
-
-                for y in 0..height / 2 {
-                    let row_width = width;
-                    let src_row = &src_row[y * row_width..];
+                let stride = ff_frame.stride(1);
+                let src = &bytes[width * height..];
+
+                for y in 0..height / 2 {
+                    let row_width = width;
+                    let src_row = &src[y * row_width..];
                     let dest_row = &mut ff_frame.data_mut(1)[y * stride..];
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1341743 and c869b33.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • crates/camera-directshow/Cargo.toml (1 hunks)
  • crates/camera-ffmpeg/examples/cli.rs (1 hunks)
  • crates/camera-ffmpeg/src/lib.rs (1 hunks)
  • crates/camera-ffmpeg/src/macos.rs (2 hunks)
  • crates/camera-ffmpeg/src/windows.rs (4 hunks)
  • crates/recording/Cargo.toml (1 hunks)
  • crates/recording/examples/recording-cli.rs (2 hunks)
  • crates/recording/src/feeds/camera.rs (4 hunks)
  • packages/ui-solid/src/auto-imports.d.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
{crates/*,apps/cli,apps/desktop/src-tauri}/Cargo.toml

📄 CodeRabbit inference engine (AGENTS.md)

Crate package names should be kebab-case

Files:

  • crates/camera-directshow/Cargo.toml
  • crates/recording/Cargo.toml
{apps/desktop,packages/ui-solid}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Component naming (Solid): components in PascalCase; hooks/utilities in camelCase starting with 'use' where applicable

Files:

  • packages/ui-solid/src/auto-imports.d.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; prefer shared types from packages

**/*.{ts,tsx}: Use Biome to format/lint TypeScript with a 2-space indent
TypeScript file names should be kebab-case (e.g., user-menu.tsx)

Files:

  • packages/ui-solid/src/auto-imports.d.ts
{crates,apps/cli,apps/desktop/src-tauri}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

{crates,apps/cli,apps/desktop/src-tauri}/**/*.rs: Rust code must be formatted with rustfmt and adhere to workspace clippy lints
Rust module files should use snake_case names

Files:

  • crates/camera-ffmpeg/examples/cli.rs
  • crates/camera-ffmpeg/src/lib.rs
  • crates/recording/examples/recording-cli.rs
  • crates/camera-ffmpeg/src/macos.rs
  • crates/recording/src/feeds/camera.rs
  • crates/camera-ffmpeg/src/windows.rs
{crates,apps/cli,apps/desktop/src-tauri}/**/{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Rust tests should live in src (inline/unit) or tests (integration) directories

Files:

  • crates/camera-ffmpeg/src/lib.rs
  • crates/camera-ffmpeg/src/macos.rs
  • crates/recording/src/feeds/camera.rs
  • crates/camera-ffmpeg/src/windows.rs
🧠 Learnings (1)
📚 Learning: 2025-08-25T10:58:06.142Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-25T10:58:06.142Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : In the desktop app, rely on unplugin-icons auto-imports; do not manually import icon modules

Applied to files:

  • packages/ui-solid/src/auto-imports.d.ts
🧬 Code graph analysis (5)
crates/camera-ffmpeg/src/lib.rs (2)
crates/camera-ffmpeg/src/windows.rs (1)
  • as_ffmpeg (14-162)
crates/camera-ffmpeg/src/macos.rs (1)
  • as_ffmpeg (16-120)
crates/recording/examples/recording-cli.rs (4)
crates/recording/src/feeds/camera.rs (3)
  • camera_info (115-117)
  • default (93-103)
  • from_info (147-151)
apps/desktop/src-tauri/src/recording.rs (1)
  • list_cameras (183-185)
crates/camera/src/lib.rs (1)
  • list_cameras (42-44)
crates/recording/src/studio_recording.rs (2)
  • new (144-153)
  • new (634-649)
crates/camera-ffmpeg/src/macos.rs (2)
crates/camera-ffmpeg/src/windows.rs (1)
  • as_ffmpeg (14-162)
crates/camera-ffmpeg/src/lib.rs (1)
  • as_ffmpeg (14-14)
crates/recording/src/feeds/camera.rs (1)
crates/recording/src/feeds/microphone.rs (8)
  • handle (245-365)
  • handle (371-383)
  • handle (389-391)
  • handle (397-417)
  • handle (433-467)
  • handle (473-485)
  • handle (491-507)
  • handle (513-526)
crates/camera-ffmpeg/src/windows.rs (2)
crates/camera-ffmpeg/src/lib.rs (1)
  • as_ffmpeg (14-14)
crates/camera-windows/src/lib.rs (3)
  • bytes (188-199)
  • new (457-475)
  • new (501-521)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (7)
crates/camera-ffmpeg/src/macos.rs (1)

115-116: Good: error mapping aligns with the new AsFFmpegError.

crates/recording/Cargo.toml (1)

64-64: Approve — Windows-only dependency wiring verified.
crates/camera-windows exists and its Cargo.toml lists name = "cap-camera-windows".

crates/camera-directshow/Cargo.toml (1)

20-22: Confirm necessity of Win32_System_Performance

crates/camera-directshow/Cargo.toml enables Win32_System_Performance; automated search was inconclusive (ripgrep skipped files). Verify whether any PDH/Pdh/PDH_ APIs are used — if none, remove the feature to reduce build time and metadata.

crates/recording/examples/recording-cli.rs (1)

70-72: Good: correctly locking and passing the camera feed into the builder.

The locking pattern aligns with the Feed API and avoids TOCTOU on attachment state.

crates/recording/src/feeds/camera.rs (2)

62-67: Early detach on reattach is correct.

Gracefully signalling the old done_tx before swapping attached prevents leaked capture threads.


273-277: API rename adoption looks good.

Using frame.as_ffmpeg() matches the new trait and error type.

crates/camera-ffmpeg/src/windows.rs (1)

21-56: YUV420P indexing assumes tightly packed planes; confirm no stride/padding from source.

DirectShow/MF often provide per‑row stride. If bytes() delivers padded rows, current indexing will misplace data.

Please confirm cap_camera_windows::CapturedFrame::bytes() yields tightly packed planes for these formats. If not, you'll need to use the source stride/pitch for each row.

Comment on lines 11 to 15
pub trait CapturedFrameExt {
/// Creates an ffmpeg video frame from the native frame.
/// Only size, format, and data are set.
fn to_ffmpeg(&self) -> Result<ffmpeg::frame::Video, ToFfmpegError>;
fn as_ffmpeg(&self) -> Result<ffmpeg::frame::Video, AsFFmpegError>;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Gate the trait on supported platforms to avoid missing-type compile errors on others.

AsFFmpegError is re-exported only on macOS/Windows. On other targets, this trait references an undefined type.

Apply:

- pub trait CapturedFrameExt {
+ #[cfg(any(target_os = "macos", target_os = "windows"))]
+ pub trait CapturedFrameExt {
     /// Creates an ffmpeg video frame from the native frame.
     /// Only size, format, and data are set.
     fn as_ffmpeg(&self) -> Result<ffmpeg::frame::Video, AsFFmpegError>;
 }

Optionally, also make the windows module gating consistent with macOS by using target_os = "windows".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub trait CapturedFrameExt {
/// Creates an ffmpeg video frame from the native frame.
/// Only size, format, and data are set.
fn to_ffmpeg(&self) -> Result<ffmpeg::frame::Video, ToFfmpegError>;
fn as_ffmpeg(&self) -> Result<ffmpeg::frame::Video, AsFFmpegError>;
}
#[cfg(any(target_os = "macos", target_os = "windows"))]
pub trait CapturedFrameExt {
/// Creates an ffmpeg video frame from the native frame.
/// Only size, format, and data are set.
fn as_ffmpeg(&self) -> Result<ffmpeg::frame::Video, AsFFmpegError>;
}
🤖 Prompt for AI Agents
In crates/camera-ffmpeg/src/lib.rs around lines 11 to 15, the CapturedFrameExt
trait references AsFFmpegError which is only re-exported on macOS/Windows
causing missing-type compile errors on other targets; add a cfg attribute to
gate the trait definition to supported platforms (e.g. #[cfg(any(target_os =
"macos", target_os = "windows"))]) so the trait is only compiled where
AsFFmpegError exists, and optionally make the windows module gating consistent
by using target_os = "windows" wherever the windows-specific items are declared.

/// Creates an ffmpeg video frame from the native frame.
/// Only size, format, and data are set.
fn to_ffmpeg(&self) -> Result<ffmpeg::frame::Video, ToFfmpegError>;
fn as_ffmpeg(&self) -> Result<ffmpeg::frame::Video, AsFFmpegError>;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Breaking rename: ensure all call sites migrated from to_ffmpeg to as_ffmpeg.

This is a public API change; sweep the workspace for stragglers.

Additionally, sanity‑check Windows RGB handling as part of this PR’s objective (RGB24 row width and Y inversion).

I can propose a fix if the checks above surface issues.


🏁 Script executed:

#!/bin/bash
rg -nP '\bto_ffmpeg\s*\(' -S -C2

Length of output: 402


🏁 Script executed:

#!/bin/bash
# Expect row_width = width * 3 for RGB24; flag suspicious width*4
rg -nP 'PixelFormat::RGB24[\s\S]*row_width\s*=\s*width\s*\*\s*4' -C3 crates/camera-ffmpeg/src/windows.rs
# Expect per-row indexing; flag constant starting offset without y
rg -nP 'PixelFormat::RGB24[\s\S]*src_row\s*=\s*&bytes\[\s*height\s*\*\s*row_width' -C3 crates/camera-ffmpeg/src/windows.rs

Length of output: 0


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== to_ffmpeg occurrences =="
rg -n --hidden -S '\bto_ffmpeg\b' -C2 || true
echo

echo "== as_ffmpeg occurrences =="
rg -n --hidden -S '\bas_ffmpeg\b' -C2 || true
echo

echo "== ToFfmpeg / AsFFmpegError / ToFfmpegError occurrences =="
rg -n --hidden -S 'ToFfmpeg|ToFfmpegError|AsFFmpegError|AsFfmpeg|AsFfmpegError' -C2 || true
echo

echo "== camera-ffmpeg src listing =="
ls -la crates/camera-ffmpeg/src || true
echo

echo "== Search for RGB24 / row_width / src_row patterns in crate =="
rg -n --hidden -S 'RGB24|row_width|src_row|height \* row_width|row_width\s*=' crates/camera-ffmpeg -C3 || true
echo

echo "== PixelFormat occurrences in crate =="
rg -n --hidden -S 'PixelFormat' crates/camera-ffmpeg -C3 || true
echo

if [ -f crates/camera-ffmpeg/src/windows.rs ]; then
  echo "== windows.rs matches =="
  rg -n -S 'RGB24|row_width|src_row|height \* row_width|row_width\s*=' crates/camera-ffmpeg/src/windows.rs -C3 || true
  echo
  echo "== windows.rs head (first 240 lines) =="
  sed -n '1,240p' crates/camera-ffmpeg/src/windows.rs || true
else
  echo "windows.rs not found at crates/camera-ffmpeg/src/windows.rs"
  echo "Searching for windows.rs anywhere in repo..."
  find . -type f -name 'windows.rs' -print || true
fi

Length of output: 41545


Rename migrated; docs update + critical Windows RGB24 bug

  • API rename: all code call-sites use as_ffmpeg; remaining reference is in docs — crates/camera-ffmpeg/README.md (lines 22–23) mentions CapturedFrameExt::to_ffmpeg() and ToFfmpegError — update to as_ffmpeg / AsFFmpegError.
  • Critical bug: crates/camera-ffmpeg/src/windows.rs — PixelFormat::RGB24 arm (≈lines 101–112) sets row_width = width * 4 and src_row = &bytes[height * row_width..] (constant offset). Change to 3 bytes/pixel and per-row indexing (e.g. row_width = width * 3 and src_row = &bytes[y * row_width..] or &bytes[(height - y - 1) * row_width..] to match ARGB/RGB32 inversion). Current code will copy incorrect byte counts and can cause pixel corruption / OOB.
  • Can provide a patch for the RGB24 branch.
🤖 Prompt for AI Agents
crates/camera-ffmpeg/src/lib.rs (around line 14); docs:
crates/camera-ffmpeg/README.md (lines 22–23); windows impl:
crates/camera-ffmpeg/src/windows.rs (around lines 101–112): update the README to
rename the documented API from CapturedFrameExt::to_ffmpeg() and ToFfmpegError
to as_ffmpeg() and AsFFmpegError respectively; in the Windows RGB24 branch
change the per-pixel math to 3 bytes/pixel and compute per-row offsets (e.g.
row_width = width * 3 and use &bytes[y * row_width ..] or &bytes[(height - y -
1) * row_width ..] depending on whether the source scanlines are inverted) so
each src_row/slice uses the correct start for that row and you copy width*3
bytes per row, and add bounds checks to avoid OOB.

const IconCapShadow: typeof import('~icons/cap/shadow.jsx')['default']
const IconCapSquare: typeof import('~icons/cap/square.jsx')['default']
const IconCapStopCircle: typeof import("~icons/cap/stop-circle.jsx")["default"]
const IconCapStopCircle: typeof import('~icons/cap/stop-circle.jsx')['default']
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Analysis chain

Formatting-only change in a generated file; OK, but avoid hand-editing artifacts.

Swapping to single quotes matches the prevailing style in this file and is no-op semantically. Since this file is generated by unplugin-auto-import, prefer regenerating rather than hand edits to prevent drift and churn.

Run this to check for remaining double-quoted imports so you can fix at the generator/config level instead of manual edits:


🏁 Script executed:

#!/bin/bash
# List any lines still using double-quoted typeof import() entries
rg -nP 'typeof import\("~icons/.+?"\)\["default"\]' packages/ui-solid/src/auto-imports.d.ts || true

Length of output: 476


Regenerate auto-imports with single-quote imports

There are still double-quoted typeof import() entries in packages/ui-solid/src/auto-imports.d.ts — change the auto-import generator/config to emit single quotes and regenerate the file (avoid hand edits).

Occurrences:

  • packages/ui-solid/src/auto-imports.d.ts:24 — const IconCapEditor: typeof import("~icons/cap/editor.jsx")["default"]
  • packages/ui-solid/src/auto-imports.d.ts:59 — const IconCapUpload: typeof import("~icons/cap/upload.jsx")["default"]
  • packages/ui-solid/src/auto-imports.d.ts:69 — const IconLucideDatabase: typeof import("~icons/lucide/database.jsx")["default"]
  • packages/ui-solid/src/auto-imports.d.ts:71 — const IconLucideEye: typeof import("~icons/lucide/eye.jsx")["default"]
  • packages/ui-solid/src/auto-imports.d.ts:88 — const IconLucideVolumeX: typeof import("~icons/lucide/volume-x.jsx")["default"]
  • packages/ui-solid/src/auto-imports.d.ts:90 — const IconMdiLoading: typeof import("~icons/mdi/loading.jsx")["default"]
🤖 Prompt for AI Agents
packages/ui-solid/src/auto-imports.d.ts around line 56 (and other occurrences
listed) — the auto-generated type imports use double quotes (e.g. typeof
import("~icons/…")["default"]); update the auto-import generator/config to emit
single-quoted module specifiers (typeof import('~icons/…')['default']) and then
regenerate the auto-imports.d.ts file (do not hand-edit the file); run the
generator/build step that produces auto-imports.d.ts and commit the regenerated
file so all occurrences are corrected.

@Brendonovich Brendonovich merged commit 9e58824 into main Sep 18, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants