mac-screen-cast
Stream macOS screen to browser over LAN. Uses ScreenCaptureKit for zero-copy capture, VideoToolbox for hardware H.264 encoding, and WebRTC for low-latency delivery.
Requirements
- macOS 12.3+ — ScreenCaptureKit availability
- Screen Recording permission — required by macOS for screen capture
Installation
From source (cargo)
Pre-built binary (macOS)
Download the latest binary for your architecture from GitHub Releases:
# Download (auto-detect architecture)
ARCH=
# Remove quarantine attribute (Gatekeeper bypass)
# Ad-hoc sign (bypass "Apple could not verify" warning)
# Make executable
Why these steps? Files downloaded via a browser get a
com.apple.quarantineflag, triggering Gatekeeper to block unsigned binaries —xattr -dremoves that flag. On newer macOS versions, even without quarantine, macOS may still refuse to run unsigned binaries with "Apple could not verify" —codesign --force -s -creates an ad-hoc signature to satisfy the check. These steps are standard practice for unsigned open-source macOS tools.
Usage
Screen Recording permission
The first run will automatically prompt for permission. If denied, reset and re-trigger:
Alternatively, grant manually in System Settings > Privacy & Security > Screen Recording.
Basic usage
Just run it — a terminal picker will show all visible windows. Type a number and press Enter to start streaming:
Press Ctrl+C to stop streaming. A second Ctrl+C forces an immediate exit if the first doesn't respond.
After selecting a window, open the printed URL (e.g. http://192.168.1.100:8080) in any browser on the same network.
No TURN server is configured, so streams only work within the local network.
Options
| Flag | Description | Default |
|---|---|---|
-w, --window-id |
Window ID to capture (skips picker) | (interactive) |
-l, --list |
List visible windows (also triggers Screen Recording permission prompt) | |
--width |
Max output width in pixels | 1280 |
--fps |
Target frame rate (1-60) | 30 |
--port |
HTTP server port | 8080 |
--json |
JSON output (use with --list) |
|
-h, --help |
Show help |
Examples
# Interactive: pick from a list
# List windows (find window IDs)
# List windows as JSON (for scripting)
# Stream a specific window
# 720p at 60 fps
# Custom port
How it works
ScreenCaptureKit → CVPixelBuffer → IOSurface
→ VideoToolbox (H.264 encode) → FU-A RTP packets
→ rustrtc (WebRTC) → Browser
ScreenCaptureKit delivers GPU-resident CVPixelBuffers directly, avoiding a CPU readback. The IOSurface is passed zero-copy to VideoToolbox for hardware encoding. Encoded H.264 NAL units are packetized into RTP (FU-A fragmentation per RFC 6184) and sent over WebRTC via rustrtc.
Performance
Measured at 1280×772 @ 30fps with VideoToolbox hardware encoding on Apple Silicon (M-series):
| Metric | Value |
|---|---|
| Pipeline latency (capture → send) | 8–16ms (measured via /latency) |
| CPU usage | ~3% of one core |
| Memory | ~22 MB RSS |
| Frame rate | Stable 30 fps |
The pipeline is entirely GPU-accelerated: ScreenCaptureKit delivers GPU-resident buffers, VideoToolbox encodes on the media engine, and the CPU is only used for RTP packetization (~1ms per frame). Total end-to-end latency (server → browser display) on LAN is typically 30–60ms.
Dependencies
- rustrtc — pure Rust WebRTC
- screencapturekit-rs — ScreenCaptureKit bindings
- videotoolbox-rs — VideoToolbox bindings
License
MIT