Cap icon indicating copy to clipboard operation
Cap copied to clipboard

feat: Implement Windows ARM build

Open richiemcilroy opened this issue 1 month ago β€’ 2 comments

Summary by CodeRabbit

  • New Features

    • Windows ARM64 build added; publish workflow inputs to select Windows target and toggle macOS builds. Build matrix expanded with platform/arch entries and run gating.
  • Bug Fixes

    • Clamp invalid recording segment durations with warnings.
    • Safer FPS/duration estimation with multiple fallbacks and warnings.
    • More reliable encoder setup, header handling and flush/error propagation.
  • Chores

    • Architecture-aware FFmpeg retrieval; platform-targeted dependency layouts.
    • Desktop app version bumped.

richiemcilroy avatar Nov 05 '25 13:11 richiemcilroy

Walkthrough

Added Windows ARM64 target across configs and CI; expanded per-target Cargo dependencies; extended publish workflow with platform/arch matrix and RUN_BUILD gating; made FFmpeg setup architecture-aware; validated/clamped recording durations and updated TimelineSegment field; adjusted Windows encoder locking/flush and FPS/duration fallbacks; bumped desktop version.

Changes

Cohort / File(s) Summary
Hakari config
/.config/hakari.toml
Added aarch64-pc-windows-msvc to platforms.
CI workflows
.github/workflows/ci.yml
Added aarch64-pc-windows-msvc to job matrices and updated Clippy condition to include it.
Publish workflow
.github/workflows/publish.yml
Added inputs windowsTarget and buildMac; expanded matrix to include platform/arch; introduced RUN_BUILD gating across build/sign/upload steps; adjusted tag creation/async usage and payloads.
Workspace dependencies
crates/workspace-hack/Cargo.toml
Replaced direct getrandom with an aliased entry and added extensive per-target [target.*.dependencies] and build-dependencies for macOS aarch64 and Windows (x86_64/aarch64).
FFmpeg setup script
scripts/setup.js, package.json
Architecture-aware FFmpeg ZIP selection (latest release), arch fallback to x86_64, computed names/paths, standardized download/extract/rename variables, and updated PowerShell vswhere invocation.
Desktop version
apps/desktop/src-tauri/Cargo.toml
Bumped package version 0.3.82 β†’ 0.3.83.
Recording: timeline segments
apps/desktop/src-tauri/src/recording.rs
Clamp non-finite/non-positive segment durations to 0.0 with a warning; use recording_segment (was recording_clip) and set segment start to 0.0.
Recording: encoder path
crates/recording/src/output_pipeline/win.rs
Make Windows encoder path message-driven, acquire output lock before queuing/flush, move header write into encoder thread, consolidate AsFFmpeg usage, and propagate errors via ready signaling.
Rendering: duration/fps guards
crates/rendering/src/project_recordings.rs
Guard fps/division by zero; compute duration from container, stream, packets, or frames/fps fallbacks; clamp non-finite/<=0 durations to 0.0 and log diagnostics.
FFmpeg encoding metadata
crates/enc-ffmpeg/src/video/h264.rs
Initialize and assign AVRational frame-rate fields on the output stream from input frame rate (unsafe block added).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as Trigger
  participant Publish as .github/workflows/publish.yml
  participant Matrix as build matrix
  participant Runner as GitHub runner

  User->>Publish: start workflow (inputs: windowsTarget, buildMac)
  Publish->>Matrix: expand to entries with platform + arch
  Publish->>Publish: compute RUN_BUILD based on matrix + inputs
  alt RUN_BUILD == true
    Matrix->>Runner: run gated build/sign/upload steps
  else RUN_BUILD == false
    Publish-->>Runner: skip build steps
  end
sequenceDiagram
  autonumber
  participant Setup as scripts/setup.js
  participant GH as GitHub Releases
  participant Cache as local cache

  Setup->>GH: request "latest" release assets
  GH-->>Setup: return asset list
  Setup->>Setup: pick asset by arch (aarch64 or x86_64), fallback to x86_64
  alt asset found
    Setup->>Cache: download ZIP -> extract -> rename -> cache
  else asset missing
    Setup-->>Setup: fallback handling (use x86_64)
  end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Points to review closely:

  • crates/workspace-hack/Cargo.toml β€” large per-target dependency lists and aliased getrandom.
  • .github/workflows/publish.yml β€” correctness of RUN_BUILD expression, new inputs, matrix expansion, and step gating.
  • scripts/setup.js β€” FFmpeg asset selection/fallback, extraction/rename, and PowerShell vswhere invocation.
  • crates/recording/src/output_pipeline/win.rs β€” encoder message handling, header write relocation, flush and locking semantics.
  • crates/rendering/src/project_recordings.rs β€” duration/fps fallback logic and logging correctness.

Possibly related PRs

  • CapSoftware/Cap#1297 β€” touches crates/recording/src/output_pipeline/win.rs and encoder setup; overlaps with Windows encoder changes.
  • CapSoftware/Cap#1121 β€” modifies Windows recording/encoding pipeline and frame handling; related to message-driven changes.
  • CapSoftware/Cap#976 β€” touches Windows target configuration and dependency manifests; related to added aarch64 Windows target.

Suggested reviewers

  • Brendonovich

Poem

πŸ‡ I hop through CI and Cargo trees,
ARM64 now joins the Windows breeze,
FFmpeg zips pick arch with care,
Durations clamped, encoders flush and share,
Version bumped β€” I nibble a carrot, bright! πŸ₯•

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 accurately describes the main change: implementing Windows ARM build support across multiple configuration files, CI/CD workflows, and dependencies.
✨ Finishing touches
  • [ ] πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment
  • [ ] Commit unit tests in branch windows-arm

πŸ“œ 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 d8aec67491150f9c68624fcd23607408d586fb35 and d7cd6244995f410e5240033ab7816986ad2d3a49.

πŸ“’ Files selected for processing (1)
  • crates/rendering/src/project_recordings.rs (1 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (2)
**/*.rs

πŸ“„ CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints. Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • crates/rendering/src/project_recordings.rs
crates/*/src/**/*

πŸ“„ CodeRabbit inference engine (AGENTS.md)

Rust crates should place tests within the src/ and/or a sibling tests/ directory for each crate inside crates/*.

Files:

  • crates/rendering/src/project_recordings.rs
🧠 Learnings (2)
πŸ“š 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/rendering/src/project_recordings.rs
πŸ“š 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/rendering/src/project_recordings.rs
🧬 Code graph analysis (1)
crates/rendering/src/project_recordings.rs (2)
apps/desktop/src-tauri/src/export.rs (1)
  • fps (17-22)
apps/desktop/src/utils/tauri.ts (1)
  • Video (484-484)
⏰ 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). (4)
  • GitHub Check: Clippy (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Clippy (aarch64-pc-windows-msvc, windows-latest)
  • GitHub Check: Clippy (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.

coderabbitai[bot] avatar Nov 05 '25 13:11 coderabbitai[bot]

looks like a merge went wrong or something, a bunch of changes have been undone

image

Brendonovich avatar Nov 06 '25 06:11 Brendonovich