Skip to content

Conversation

@jamnxdev
Copy link
Contributor

@jamnxdev jamnxdev commented Dec 4, 2025

This PR fixes Windows build failures in the cap-recording crate that occurred after updating to windows crate v0.60.0.The windows crate v0.60.0 introduced breaking changes by reorganizing Win32 API bindings. Specifically, the PrintWindow function and its associated types were relocated from Win32::Graphics::Gdi to Win32::Storage::Xps. Additionally, the PW_RENDERFULLCONTENT constant was moved to Win32::UI::WindowsAndMessaging.These changes caused unresolved import errors when building the recording crate on Windows, preventing the desktop app from compiling. This PR updates the import paths and fixes a related closure mutability issue to restore Windows build compatibility.

Changes

  • Updated PrintWindow imports in screenshot.rs: The PrintWindow function and PRINT_WINDOW_FLAGS type moved from Win32::Graphics::Gdi to Win32::Storage::Xps in windows crate 0.60.0
  • Replaced PW_RENDERFULLCONTENT: This constant moved to Win32::UI::WindowsAndMessaging, so replaced with PRINT_WINDOW_FLAGS(2) directly since it's only used once
  • Fixed closure mutability in output_pipeline/win.rs: Added mut to process_frame closure to fix borrow checker error

Why

The windows crate reorganized some Win32 API bindings in v0.60.0. PrintWindow was moved from the Gdi module to the Xps module (it's defined in user32.dll but the crate relocated the binding). Without these changes, the recording crate fails to compile on Windows.

Testing

  • cargo check -p cap-recording passes
  • cargo build -p cap-recording completes successfully

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened Windows recording pipeline stability with more informative error messages
    • Enhanced screenshot capture robustness on Windows systems
    • Optimized hardware-accelerated frame conversion with improved memory safety
    • Refined video format processing for Windows recording operations
  • Chores

    • Updated platform-specific dependencies

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

Walkthrough

Updates Direct3D11 API bindings to newer Windows SDK paths with improved texture creation, view mapping, and error handling. Refactors camera feed buffer handling and screenshot capture logic with enhanced memory safety. Adds explicit unsafe blocks and error propagation throughout Direct3D and GDI interop paths. Marks NativeCameraFrame as Send/Sync and adds Win32 Xps storage feature to dependencies.

Changes

Cohort / File(s) Summary
Direct3D11 Framework Updates
crates/frame-converter/src/d3d11.rs
Updates Windows API imports to Win32::Foundation and Win32::Graphics::Direct3D11/Dxgi; replaces flag wrappers with raw u32 fields in texture descriptors; adds explicit out-parameter handling for texture and video processor views; introduces HardwareUnavailable error for null textures; wraps memory copies with scoped unsafe blocks; adds D3D11_MAPPED_SUBRESOURCE and HMODULE imports.
Camera Feed and Video Processing
crates/recording/src/feeds/camera.rs, crates/recording/src/output_pipeline/win.rs
Refactors MFCreateMemoryBuffer handling with buffer readiness flag; removes DXGI_FORMAT_UYVY import; consolidates YUYV422/UYVY422 to DXGI_FORMAT_YUY2; adds unsafe impl Send and Sync for NativeCameraFrame; reworks error paths to format messages as strings; makes process_frame closure mutable; improves video channel error reporting.
Windows Screenshot Capture
crates/recording/src/screenshot.rs
Refines OS-specific imports and feature gates; replaces raw handle checks with is_null(); updates GetDC/ReleaseDC calls with Some(hwnd) wrapping; changes biCompression from BI_RGB to 0; enhances error handling around D3D device and GDI operations; introduces explicit Ok/Some pattern matching in frame capture flow; strengthens null-check guards around bitmap manipulation.
Build Configuration
crates/recording/Cargo.toml
Adds Win32_Storage_Xps to Windows target feature dependencies.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Direct3D11 bindings update (crates/frame-converter/src/d3d11.rs): Requires deep familiarity with Direct3D11 memory management, texture/view creation, and mapping semantics; multiple scoped unsafe blocks need careful validation.
  • Memory safety changes: Numerous unsafe impls and unsafe blocks throughout Direct3D and GDI interop require verification of pointer validity and lifetime guarantees.
  • Error propagation refactors: Systematic changes to error handling paths across multiple files; ensure no silent failures or lost error context.
  • Handle wrapping updates (crates/recording/src/screenshot.rs): GDI handle management with new Some/Option wrapping requires careful validation to prevent use-after-free or double-release.

Possibly related PRs

  • Hardware accelerated encoding on Windows #976: Introduces hardware-accelerated Windows encoding with Direct3D/Media Foundation interop; shares D3D11 texture, view creation, mapping, and device initialization code paths.
  • Overhaul camera preview #945: Implements camera-feed actor-based refactor and CameraPreviewManager API updates that align with the camera feed buffer handling changes in this PR.

Poem

🐰 With Direct3D bindings fresh and new,
Textures map, and views break through,
Memory safe in unsafe blocks so tight,
Screenshots and feeds now shine just right!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% 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 'fix: update Windows API imports for windows crate 0.60.0 compatibility' accurately summarizes the main objective of the pull request, which is to update Windows API imports to be compatible with the windows crate version 0.60.0.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

🧹 Nitpick comments (1)
crates/frame-converter/src/d3d11.rs (1)

544-584: Redundant nested unsafe blocks inside an unsafe fn.

The copy_frame_to_mapped function is already declared unsafe, so the inner unsafe blocks on lines 551, 561, 573 are redundant. They don't cause issues but add unnecessary nesting.

 unsafe fn copy_frame_to_mapped(frame: &frame::Video, dst: *mut u8, dst_stride: usize) {
     let height = frame.height() as usize;
     let format = frame.format();

     match format {
         Pixel::NV12 => {
             for y in 0..height {
-                unsafe {
-                    ptr::copy_nonoverlapping(
-                        frame.data(0).as_ptr().add(y * frame.stride(0)),
-                        dst.add(y * dst_stride),
-                        frame.width() as usize,
-                    );
-                }
+                ptr::copy_nonoverlapping(
+                    frame.data(0).as_ptr().add(y * frame.stride(0)),
+                    dst.add(y * dst_stride),
+                    frame.width() as usize,
+                );
             }
             // ... similar for other blocks
         }
         // ...
     }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1fd6cb and 35eefb3.

📒 Files selected for processing (5)
  • crates/frame-converter/src/d3d11.rs (14 hunks)
  • crates/recording/Cargo.toml (1 hunks)
  • crates/recording/src/feeds/camera.rs (1 hunks)
  • crates/recording/src/output_pipeline/win.rs (7 hunks)
  • crates/recording/src/screenshot.rs (11 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx,rs,py,sh}

📄 CodeRabbit inference engine (CLAUDE.md)

Never add any form of comments to code (single-line //, multi-line /* /, documentation ///, //!, /* */, or any other comment syntax). Code must be self-explanatory through naming, types, and structure.

Files:

  • crates/recording/src/output_pipeline/win.rs
  • crates/recording/src/screenshot.rs
  • crates/recording/src/feeds/camera.rs
  • crates/frame-converter/src/d3d11.rs
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Use Rust 2024 edition and run cargo fmt to format all Rust code with rustfmt

**/*.rs: Format all Rust code using rustfmt and apply workspace clippy lints
Use snake_case for Rust module names and kebab-case for Rust crate names

Files:

  • crates/recording/src/output_pipeline/win.rs
  • crates/recording/src/screenshot.rs
  • crates/recording/src/feeds/camera.rs
  • crates/frame-converter/src/d3d11.rs
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,rs}: Use kebab-case for file names (e.g., user-menu.tsx)
Never add comments to code in any language (no //, /* */, ///, //!, #, etc.). Code must be self-explanatory through naming, types, and structure

Files:

  • crates/recording/src/output_pipeline/win.rs
  • crates/recording/src/screenshot.rs
  • crates/recording/src/feeds/camera.rs
  • crates/frame-converter/src/d3d11.rs
🧠 Learnings (2)
📚 Learning: 2025-10-28T08:39:42.230Z
Learnt from: Brendonovich
Repo: CapSoftware/Cap PR: 1305
File: crates/recording/src/output_pipeline/macos.rs:80-90
Timestamp: 2025-10-28T08:39:42.230Z
Learning: In `crates/recording/src/output_pipeline/macos.rs`, the `AVFoundationMp4Muxer` intentionally holds the `Mutex<MP4Encoder>` lock during retry attempts in `send_video_frame()` and `send_audio_frame()`. This blocking behavior is correct because frame processing must happen sequentially to prevent audio and video frames from being interleaved incorrectly in the encoder.

Applied to files:

  • crates/recording/src/output_pipeline/win.rs
  • crates/recording/src/feeds/camera.rs
  • crates/frame-converter/src/d3d11.rs
📚 Learning: 2025-10-17T05:58:22.586Z
Learnt from: Brendonovich
Repo: CapSoftware/Cap PR: 1219
File: crates/enc-avfoundation/src/mp4.rs:350-373
Timestamp: 2025-10-17T05:58:22.586Z
Learning: In crates/enc-avfoundation/src/mp4.rs, the `finish()` method intentionally skips video extension when `is_paused` is true. This is correct behavior because if recording is paused, the video should not be extended beyond the pause point—the pause is user-initiated, unlike the case where ScreenCaptureKit stops providing frames during static content.

Applied to files:

  • crates/recording/src/output_pipeline/win.rs
  • crates/recording/src/feeds/camera.rs
🧬 Code graph analysis (2)
crates/recording/src/feeds/camera.rs (2)
crates/camera-windows/src/lib.rs (1)
  • bytes (188-199)
crates/camera-mediafoundation/src/lib.rs (1)
  • bytes (468-483)
crates/frame-converter/src/d3d11.rs (2)
crates/frame-converter/src/lib.rs (1)
  • new (94-110)
crates/scap-direct3d/src/lib.rs (1)
  • texture (429-431)
🔇 Additional comments (18)
crates/recording/Cargo.toml (1)

77-77: LGTM!

The Win32_Storage_Xps feature is correctly added to support the relocated PrintWindow API in windows crate 0.60.0.

crates/frame-converter/src/d3d11.rs (6)

4-8: LGTM!

Import additions for ManuallyDrop and the restructured Windows API types are correct for windows crate 0.60.0 compatibility.


155-165: LGTM!

The HMODULE::default() correctly replaces the previous None parameter for the software module handle in D3D11CreateDevice.


245-283: LGTM!

The texture creation calls correctly adapt to the new API by extracting the raw u32 value from the flag types (.0 as u32).


378-392: LGTM!

The input view creation now uses an explicit Option out-parameter with a null check, improving robustness over the previous API.


420-432: LGTM!

The D3D11_VIDEO_PROCESSOR_STREAM initialization correctly uses ManuallyDrop::new(None) for the optional pInputSurfaceRight field to match the new API's expectations for optional COM pointers.


515-541: LGTM!

The create_texture function correctly adapts to the new API with u32 fields for flags and adds explicit null checking for the created texture.

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

565-587: LGTM!

The buffer handling refactor improves control flow by:

  1. Acquiring the lock in a scoped block that ensures it's released before subsequent operations
  2. Using a buffer_ready flag to gate frame sending on successful buffer population
  3. Only calling SetCurrentLength and sending the frame when the buffer is properly initialized
crates/recording/src/output_pipeline/win.rs (4)

569-571: LGTM!

The closure is correctly changed to mut because it captures and mutates first_timestamp and frame_count across invocations. This fixes the borrow checker error mentioned in the PR description.


674-676: LGTM!

The error message improvement provides clearer context when the video channel is closed.


410-412: Verify UYVY422 to DXGI_FORMAT_YUY2 mapping correctness.

YUYV422 and UYVY422 have different byte orderings:

  • YUYV: Y0 U0 Y1 V0
  • UYVY: U0 Y0 V0 Y1

Mapping both to DXGI_FORMAT_YUY2 (which expects YUYV ordering) may produce incorrect colors for UYVY422 input.

#!/bin/bash
# Check if there's any color conversion or if UYVY is actually handled differently elsewhere
rg -n "UYVY" --type rust -C 5

397-398: The Send/Sync implementation is appropriate given the Mutex wrapper, but verify the buffer was initialized for thread-safe use.

IMFMediaBuffer is not internally synchronized—Microsoft documentation confirms that Lock/Unlock do not provide thread synchronization. However, the Arc<Mutex<IMFMediaBuffer>> pattern correctly implements external synchronization, which is the recommended approach per Microsoft best practices.

The unsafe impl Send + Sync is sound because the Mutex serializes all access to the buffer. Verify that IMFMediaBuffer instances are created with a threading model compatible with multi-threaded access (typically free-threaded or properly marshaled), and that all buffer access occurs through the mutex-protected wrapper.

crates/recording/src/screenshot.rs (6)

38-38: LGTM!

The PrintWindow and PRINT_WINDOW_FLAGS imports are correctly updated to use the new location in Win32::Storage::Xps as required by windows crate 0.60.0.


344-350: LGTM!

The HDC null checks correctly use .0.is_null() which is the appropriate pattern for checking null handles in the windows crate.


360-360: LGTM!

Setting biCompression to 0 is semantically equivalent to BI_RGB (which has value 0) and aligns with the simplified API.


371-381: LGTM!

The CreateDIBSection call correctly handles the new Result return type and performs proper null checks on both the bitmap handle and data pointer before proceeding.


483-494: LGTM!

The PrintWindow call correctly uses PRINT_WINDOW_FLAGS(2) as a replacement for PW_RENDERFULLCONTENT which was relocated to a different module in windows crate 0.60.0. The value 2 corresponds to PW_RENDERFULLCONTENT.


614-614: LGTM!

The simplified result handling using res.ok()?.ok()? correctly unwraps the nested Result types.

@richiemcilroy richiemcilroy merged commit eed3f76 into CapSoftware:main Dec 4, 2025
11 of 12 checks passed
@jamnxdev jamnxdev deleted the fix/windows-crate-0.60-compat branch December 4, 2025 16:28
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