Skip to content

fix(macos): capture and tag the screen track as BT.709 studio range - #947

Merged
EtienneLescot merged 1 commit into
mainfrom
claude/recording-macos-bt709
Sep 30, 2026
Merged

EtienneLescot merged 1 commit into
mainfrom
claude/recording-macos-bt709

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary
The macOS helper now captures BT.709 studio-range YCbCr and tags the H.264 track BT.709, the colour the compositor decodes every recording as.

Fixes #943
Part of #920

Changes

  • ScreenCaptureKit: pixelFormat is 420v instead of BGRA, colorMatrix BT.709, colorSpaceName sRGB. Unset, the buffers carried the display's own colour space (P3 on most Macs) and VideoToolbox chose the matrix.
  • Writer: AVVideoColorPropertiesKey with BT.709 primaries, transfer function and YCbCr matrix. It sits in the top-level output settings, so no line of the compression dictionary that fix(macos): pin the keyframe interval to 1 s and count dropped video frames #938 edits is touched.
  • Core: the matrix and the tags live in OpenScreenCaptureCore/VideoColor.swift, with an XCTest that pins the capture matrix to the tagged one.

Why 420v is safe

  • Nothing reads the screen pixels. A frame goes from didOutputSampleBuffer through retimedSampleBuffer (timing only) to videoInput.append. isCompleteFrame reads the SCStreamFrameInfo attachments only.
  • The cursor helper is a separate executable with no SCStream. The picker session records through the same ScreenCaptureRecorder.
  • Apple's docs list 420v as a supported pixelFormat, and colorMatrix applies to 420v and 420f.
  • captureOutputSize already returns even dimensions, which 4:2:0 needs.
  • Side gain: 1.5 bytes a pixel instead of 4 over queueDepth = 6, so buffer memory drops by about 2.7.

Tested

  • Swift: validated only by the swift-macos-helper CI job (swift test and the release build). Swift cannot build on the Windows machine this was written on.
  • The colour itself needs a Mac. Nothing here has been recorded.

Pending (maintainer, on a Mac)

  • ffprobe -show_streams | grep color_ on a take reads tv / bt709 / bt709 / bt709.
  • Solid red read back as raw YUV: Y≈63, Cb≈102, Cr≈240.
  • Mid-grey (128,128,128) reads Y≈126. Apple's writer colour-converts source buffers whose tags differ from AVVideoColorPropertiesKey. If ScreenCaptureKit tags the sRGB buffers with an sRGB transfer function, the writer may re-encode them to the BT.709 curve, and grey then reads Y≈115. Red cannot show this; grey does. The fix would be to retag the buffer's transfer attachment before append.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 8 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 4b10c29a-bcfd-4221-adae-eada465ff5a2

📥 Commits

Reviewing files that changed from the base of the PR and between 32857bb and 55ff2c0.

📒 Files selected for processing (3)
  • electron/native/screencapturekit/Sources/OpenScreenCaptureCore/VideoColor.swift
  • electron/native/screencapturekit/Sources/OpenScreenScreenCaptureKitHelper/ScreenCaptureRecorder.swift
  • electron/native/screencapturekit/Tests/OpenScreenCaptureCoreTests/VideoColorTests.swift
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@EtienneLescot

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@EtienneLescot

Copy link
Copy Markdown
Collaborator Author

Tested on a Mac: the pending checks pass.

macOS 26.5, Apple M1, one 4K display at 2x (display profile "Evanlak4K60", not sRGB). swift test: 55 tests, 0 failures, including the two new VideoColorTests.

How: release builds of this branch's helper (55ff2c0) and of its parent (baseline), each run in --picker-session mode with a whole-display pick. The screen showed a borderless window of eight sRGB patches (NSColor(srgbRed:), window colour space sRGB). A 4 s take was recorded with each helper, and the raw YUV was read (-pix_fmt yuv420p -f rawvideo) at the centre of every patch. Only the helper was tested, not the app and not the compositor.

Tags (ffprobe)

  • This PR: color_range=tv, color_space=bt709, color_transfer=bt709, color_primaries=bt709, H.264 High.
  • Baseline: all four unknown.

Raw YUV, mean over an 80x80 px block

Patch Expected This PR Baseline
grey 128 Y≈126 (115 if the curve were re-encoded) Y 125.0 Y 116
grey 64 Y 71 71.0 64
grey 192 Y 181 181.0 174
white / black 235 / 16 234.8 / 16.0 235 / 16
red (Y/Cb/Cr) 63 / 102 / 240 74.0 / 96.0 / 232.8 63 / 113 / 237
green 172.8 / 42.0 / 26.1 181 / 74 / 37
blue 32.4 / 239.7 / 117.1 66 / 215 / 116

Reading it

  • Grey: Y 125, not 115. The writer does not re-encode sRGB-tagged buffers to the BT.709 curve, so no transfer retag before append is needed.
  • Red is off because of this display, not the PR. Its profile cannot show pure sRGB red. A ColorSync round trip sRGB -> display -> sRGB (8-bit quantised) gives red (255,19,0), green (0,255,3), blue (0,0,255). The PR take, decoded as BT.709 studio range, gives red (255,18,0), green (0,255,1), blue (0,1,255). So the capture reproduces what the screen actually shows. On an sRGB or P3 panel, red should land on 63/102/240.
  • Baseline carried the display's own values with no conversion and no tags (grey 128 is shown as 117 on this panel, which reads Y 116). That is the Recording (macOS): capture and tag BT.709 colour #943 defect.

Not covered: window capture (same SCStreamConfiguration code path, but not recorded), preview and export through the compositor, and a P3 display.

@EtienneLescot
EtienneLescot merged commit e04943a into main Sep 30, 2026
18 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.

Recording (macOS): capture and tag BT.709 colour

1 participant