Skip to content

feat(rendering): add opt-in macOS software codec mode - #2948

Open
AasishDairelSahayaGrinspan wants to merge 3 commits into
CapSoftware:mainfrom
AasishDairelSahayaGrinspan:split/macos-software-codecs
Open

AasishDairelSahayaGrinspan wants to merge 3 commits into
CapSoftware:mainfrom
AasishDairelSahayaGrinspan:split/macos-software-codecs

Conversation

@AasishDairelSahayaGrinspan

@AasishDairelSahayaGrinspan AasishDairelSahayaGrinspan commented Oct 22, 2026 •

Copy link
Copy Markdown

Summary

On dual-GPU Macs, VideoToolbox can keep using the integrated GPU for H.264 decode and encode even when the renderer is on the discrete GPU. There is no public API to pin VideoToolbox to a specific Metal device, so this adds an opt-in software codec mode:

  • CAP_MACOS_SOFTWARE_CODECS=1 forces FFmpeg software decode in the editor and export paths.
  • Export encoding switches to libx264 and disables zero-copy VideoToolbox input.
  • Live Studio recording encoding is unchanged; it keeps the normal hardware priority. CAP_EXPORT_FORCE_SOFTWARE_ENCODER remains the existing escape hatch.
  • When the variable is unset, codec selection is unchanged.

This only changes codec choice; it does not change GPU selection. Split out of #2776 at the maintainer's request.

Setting the variable

Apps launched from Finder or the Dock do not inherit shell environment variables. Set it for GUI apps and relaunch Cap:

launchctl setenv CAP_MACOS_SOFTWARE_CODECS 1
# relaunch Cap
launchctl unsetenv CAP_MACOS_SOFTWARE_CODECS

Verification

2019 MacBook Pro, AMD Radeon Pro 5300M + Intel UHD 630, 3072x1920 studio recording:

Scenario Decoder / encoder Intel GPU Result
Default playback AVAssetReader hardware active AMD renderer, 59.5 fps
CAP_MACOS_SOFTWARE_CODECS=1 playback FFmpeg software 0% AMD 20-100%, 59.4 fps, 0 dropped
Default export zero-copy VideoToolbox active AMD renderer, 141.8 fps
CAP_MACOS_SOFTWARE_CODECS=1 export libx264, no zero-copy 0% 58.3 fps, 2.37 s

The software export path is about 2.8x slower than hardware, which is why this is opt-in rather than the default. Live recording encoding is intentionally left on the hardware path.

Local checks: cargo fmt --all --check, cargo check -p cap-rendering -p cap-enc-ffmpeg -p cap-export, and cargo test -p cap-enc-ffmpeg software_codec_env_only_forces_export_encoder_priority.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; the preview fix remains in place, and export-only encoder selection matches the intended behavior.

Summary

Adds opt-in software codecs on macOS without changing renderer GPU selection.

  • Mac video playback can use software decoding when the setting is on.
  • MP4 exports can use software encoding without changing live recording.

Reviews (3) · Last reviewed commit: "fix(enc-ffmpeg): limit software codec en..." · Reviewed by Greptile

VideoToolbox can schedule H.264 decode and encode on the integrated GPU even when the renderer is on the discrete GPU. Add CAP_MACOS_SOFTWARE_CODECS=1 to force FFmpeg software decode and libx264 export so the integrated GPU stays idle. The default codec behavior is unchanged; this only changes codec choice when the variable is set.
@vercel

vercel Bot commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

@AasishDairelSahayaGrinspan is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

Comment on lines +1476 to +1477
let software_codecs = crate::software_video_codecs_requested();
if force_ffmpeg || path.is_dir() || software_codecs {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Preview ignores software codecs

Setting CAP_MACOS_SOFTWARE_CODECS=1 does not force software decoding in the preparing editor preview. This check only covers spawn_decoder, while that preview uses spawn_managed_decoder. The desktop enables hardware decoding on macOS, and the managed decoder forwards that choice unchanged, so FFmpeg still selects VideoToolbox. Users can therefore still get the integrated-GPU activity this option is meant to avoid. Apply the software-codec setting to the managed decoder path too.

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/rendering/src/decoder/mod.rs
Line: 1476-1477

Comment:
**Preview ignores software codecs**

Setting `CAP_MACOS_SOFTWARE_CODECS=1` does not force software decoding in the preparing editor preview. This check only covers `spawn_decoder`, while that preview uses `spawn_managed_decoder`. The desktop enables hardware decoding on macOS, and the managed decoder forwards that choice unchanged, so FFmpeg still selects VideoToolbox. Users can therefore still get the integrated-GPU activity this option is meant to avoid. Apply the software-codec setting to the managed decoder path too.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 0550695. spawn_managed_decoder now applies CAP_MACOS_SOFTWARE_CODECS before constructing the FFmpeg decoder, so the preparing preview and camera managed decoders use software decoding too.

The preparing editor preview uses spawn_managed_decoder, so CAP_MACOS_SOFTWARE_CODECS only affected spawn_decoder. Apply the same override to the managed decoder path so preview and camera decoders also avoid VideoToolbox on the integrated GPU.
@AasishDairelSahayaGrinspan

Copy link
Copy Markdown
Author

@greptileai review

@richiemcilroy

Copy link
Copy Markdown
Member

Thanks @AasishDairelSahayaGrinspan for splitting this out and for the clear measurements on the 2019 MBP! The decode and export changes look right: spawn_decoder and spawn_managed_decoder both fall back to software, and want_hw_input is disabled in crates/export/src/mp4.rs. One scope problem: CAP_MACOS_SOFTWARE_CODECS was added to force_software_encoder() in crates/enc-ffmpeg/src/video/h264.rs, and that function doesn't check is_export. It is used by get_encoder_priority_with_override and by the VideoToolbox hardware-input path. macOS Studio screen recording builds its encoder through H264EncoderBuilder (crates/recording/src/output_pipeline/macos_fragmented_m4s.rs and oop_fragmented_m4s.rs), so with the variable set, live recordings also switch to libx264. At 3072x1920 that is likely to drop frames, and it goes beyond what the description promises. Could you apply the new variable only when is_export is true (keep CAP_EXPORT_FORCE_SOFTWARE_ENCODER as it is), and add a small test that the recording encoder priority doesn't change when it is set? It would also help to note in the description how to set the variable for the app (for example launchctl setenv), because apps opened from Finder or the Dock don't inherit shell environment variables. CI on this fork PR also still needs a maintainer to approve it.

CAP_MACOS_SOFTWARE_CODECS was forcing libx264 for live Studio recording encoding as well as export. Live macOS recording builds its encoder through H264EncoderBuilder, so setting the variable could drop frames at high resolutions. Gate the new env var on is_export and keep CAP_EXPORT_FORCE_SOFTWARE_ENCODER unchanged.
@AasishDairelSahayaGrinspan

Copy link
Copy Markdown
Author

Fixed in 987d3f703.

  • force_software_encoder now takes is_export, and CAP_MACOS_SOFTWARE_CODECS is gated on export only. CAP_EXPORT_FORCE_SOFTWARE_ENCODER is unchanged.
  • Added software_codec_env_only_forces_export_encoder_priority, which sets CAP_MACOS_SOFTWARE_CODECS=1, asserts the live recording priority is unchanged, and asserts export resolves to libx264. It passes locally.
  • Updated the PR description with the launchctl setenv instructions and clarified that live Studio recording encoding remains on the hardware path.

The decode and export changes are unchanged from the reviewed revision.

@AasishDairelSahayaGrinspan

Copy link
Copy Markdown
Author

@greptileai review

This branch has not been deployed

No deployments
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