screencapturekit 1.0.0

ScreenCaptureKit bindings for rust
docs.rs failed to build screencapturekit-1.0.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

ScreenCaptureKit-rs

Crates.io Documentation License Build Status

๐Ÿ’ผ Looking for a hosted desktop recording API?
Check out Recall.ai - an API for recording Zoom, Google Meet, Microsoft Teams, in-person meetings, and more.


Safe, idiomatic Rust bindings for macOS ScreenCaptureKit framework.

Capture screen content, windows, and applications with high performance and low overhead on macOS 12.3+.

โœจ Features

  • ๐ŸŽฅ Screen & Window Capture - Capture displays, windows, or specific applications
  • ๐Ÿ”Š Audio Capture - Capture system audio and microphone input
  • โšก Real-time Processing - High-performance frame callbacks with custom dispatch queues
  • ๐Ÿ—๏ธ Builder Pattern API - Clean, type-safe configuration with ::build()
  • ๐Ÿ”„ Async Support - Runtime-agnostic async API (works with Tokio, async-std, smol, etc.)
  • ๐ŸŽจ IOSurface Access - Zero-copy GPU texture access for Metal/OpenGL
  • ๐Ÿ›ก๏ธ Memory Safe - Proper reference counting and leak-free by design
  • ๐Ÿ“ฆ Zero Dependencies - No runtime dependencies (only dev dependencies for examples)

๐Ÿ“ฆ Installation

Add to your Cargo.toml:

[dependencies]
screencapturekit = "1.0"

For async support:

[dependencies]
screencapturekit = { version = "1.0", features = ["async"] }

For latest macOS features:

[dependencies]
screencapturekit = { version = "1.0", features = ["macos_15_0"] }

๐Ÿš€ Quick Start

Basic Screen Capture

use screencapturekit::prelude::*;
use std::sync::Arc;

struct Handler;

impl SCStreamOutputTrait for Handler {
    fn did_output_sample_buffer(&self, sample: CMSampleBuffer, _type: SCStreamOutputType) {
        println!("๐Ÿ“น Received frame at {} pts", sample.get_presentation_timestamp());
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Get available displays
    let content = SCShareableContent::get()?;
    let display = &content.displays()[0];
    
    // Configure capture
    let filter = SCContentFilter::build()
        .display(display)
        .exclude_windows(&[])
        .build();
    
    let config = SCStreamConfiguration::build()
        .set_width(1920)?
        .set_height(1080)?
        .set_pixel_format(PixelFormat::ARGB8)?;
    
    // Start streaming
    let mut stream = SCStream::new(&filter, &config);
    stream.add_output_handler(Handler, SCStreamOutputType::Screen);
    stream.start_capture()?;
    
    // Capture runs in background...
    std::thread::sleep(std::time::Duration::from_secs(5));
    
    stream.stop_capture()?;
    Ok(())
}

Async Capture

use screencapturekit::async_api::{AsyncSCShareableContent, AsyncSCStream};
use screencapturekit::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Get content asynchronously
    let content = AsyncSCShareableContent::get().await?;
    let display = &content.displays()[0];
    
    // Create filter and config
    let filter = SCContentFilter::build()
        .display(display)
        .exclude_windows(&[])
        .build();
    
    let config = SCStreamConfiguration::build()
        .set_width(1920)?
        .set_height(1080)?;
    
    // Create async stream with frame buffer
    let stream = AsyncSCStream::new(&filter, &config, 30, SCStreamOutputType::Screen);
    stream.start_capture()?;
    
    // Capture frames asynchronously
    for _ in 0..10 {
        if let Some(frame) = stream.next().await {
            println!("๐Ÿ“น Got frame!");
        }
    }
    
    stream.stop_capture()?;
    Ok(())
}

Window Capture with Audio

use screencapturekit::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let content = SCShareableContent::get()?;
    
    // Find a specific window
    let window = content.windows()
        .iter()
        .find(|w| w.title().as_deref() == Some("Safari"))
        .ok_or("Safari window not found")?;
    
    // Capture window with audio
    let filter = SCContentFilter::build()
        .window(window)
        .build();
    
    let config = SCStreamConfiguration::build()
        .set_width(1920)?
        .set_height(1080)?
        .set_captures_audio(true)?
        .set_sample_rate(48000)?
        .set_channel_count(2)?;
    
    let mut stream = SCStream::new(&filter, &config);
    // Add handlers...
    stream.start_capture()?;
    
    Ok(())
}

๐ŸŽฏ Key Concepts

Builder Pattern

All main types use a consistent builder pattern with ::build():

// Content filters
let filter = SCContentFilter::build()
    .display(&display)
    .exclude_windows(&windows)
    .build();

// Stream configuration
let config = SCStreamConfiguration::build()
    .set_width(1920)?
    .set_height(1080)?
    .set_pixel_format(PixelFormat::ARGB8)?
    .set_captures_audio(true)?;

// Options for content retrieval
let content = SCShareableContent::with_options()
    .on_screen_windows_only(true)
    .exclude_desktop_windows(true)
    .get()?;

Custom Dispatch Queues

Control callback threading with custom dispatch queues:

use screencapturekit::dispatch_queue::{DispatchQueue, DispatchQoS};

let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);

stream.add_output_handler_with_queue(
    my_handler,
    SCStreamOutputType::Screen,
    Some(&queue)
);

QoS Levels:

  • Background - Maintenance tasks
  • Utility - Long-running tasks
  • Default - Standard priority
  • UserInitiated - User-initiated tasks
  • UserInteractive - UI updates (highest priority)

IOSurface Access

Zero-copy GPU texture access:

impl SCStreamOutputTrait for Handler {
    fn did_output_sample_buffer(&self, sample: CMSampleBuffer, _type: SCStreamOutputType) {
        if let Some(pixel_buffer) = sample.get_image_buffer() {
            if let Some(surface) = pixel_buffer.get_iosurface() {
                let width = surface.get_width();
                let height = surface.get_height();
                let pixel_format = surface.get_pixel_format();
                
                // Use with Metal/OpenGL...
                println!("IOSurface: {}x{} format: {}", width, height, pixel_format);
            }
        }
    }
}

๐ŸŽ›๏ธ Feature Flags

Core Features

Feature Description
async Runtime-agnostic async API (works with any executor)

macOS Version Features

Feature flags enable APIs for specific macOS versions. They are cumulative (enabling macos_15_0 enables all earlier versions).

Feature macOS APIs Enabled
macos_13_0 13.0 Ventura Opacity configuration
macos_14_0 14.0 Sonoma Content picker, clipboard ignore, shadow displays
macos_14_2 14.2 Capture fractions, shadow control, child windows
macos_14_4 14.4 Future features
macos_15_0 15.0 Sequoia Recording output, HDR capture

Version-Specific Example

let mut config = SCStreamConfiguration::build()
    .set_width(1920)?
    .set_height(1080)?;

#[cfg(feature = "macos_13_0")]
{
    config = config.set_should_be_opaque(true)?;
}

#[cfg(feature = "macos_14_2")]
{
    config = config
        .set_ignores_shadows_single_window(true)?
        .set_includes_child_windows(false)?;
}

#[cfg(feature = "macos_15_0")]
{
    use screencapturekit::stream::configuration::stream_properties::SCCaptureDynamicRange;
    config = config.set_capture_dynamic_range(SCCaptureDynamicRange::HDRLocalDisplay)?;
}

๐Ÿ“š API Overview

Core Types

  • SCShareableContent - Query available displays, windows, and applications
  • SCContentFilter - Define what to capture (display/window/app)
  • SCStreamConfiguration - Configure resolution, format, audio, etc.
  • SCStream - Main capture stream with output handlers
  • CMSampleBuffer - Frame data with timing and metadata

Async API (requires async feature)

  • AsyncSCShareableContent - Async content queries
  • AsyncSCStream - Async stream with frame iteration

Display & Window Types

  • SCDisplay - Display information (resolution, ID, etc.)
  • SCWindow - Window information (title, bounds, owner, etc.)
  • SCRunningApplication - Application information (name, PID, etc.)

Media Types

  • CMSampleBuffer - Sample buffer with timing and attachments
  • CMTime - High-precision timestamps
  • IOSurface - GPU-backed pixel buffers
  • CGImage - CoreGraphics images

Configuration Types

  • PixelFormat - ARGB8, YCbCr420, etc.
  • ColorSpace - sRGB, DisplayP3, etc.
  • SCPresenterOverlayAlertSetting - Privacy alert behavior
  • SCCaptureDynamicRange - HDR/SDR modes (macOS 15.0+)

๐Ÿƒ Examples

The examples/ directory contains focused API demonstrations:

Quick Start (Numbered by Complexity)

  1. 01_basic_capture.rs - Simplest screen capture
  2. 02_window_capture.rs - Capture specific windows
  3. 03_audio_capture.rs - Audio + video capture
  4. 04_pixel_access.rs - Read pixel data with std::io::Cursor
  5. 05_screenshot.rs - Single screenshot (macOS 14.0+)
  6. 06_iosurface.rs - Zero-copy GPU buffers
  7. 07_list_content.rs - List available content
  8. 08_async.rs - Async/await API with multiple examples
  9. 09_closure_handlers.rs - Closure-based handlers and delegates
  10. 10_recording_output.rs - Direct video file recording (macOS 15.0+)
  11. 11_content_picker.rs - System UI for content selection (macOS 14.0+)

See examples/README.md for detailed descriptions.

Run an example:

# Basic examples
cargo run --example 01_basic_capture
cargo run --example 09_closure_handlers

# Feature-gated examples
cargo run --example 05_screenshot --features macos_14_0
cargo run --example 08_async --features async
cargo run --example 10_recording_output --features macos_15_0
cargo run --example 11_content_picker --features macos_14_0

๐Ÿงช Testing

Run Tests

# All tests
cargo test

# With features
cargo test --features async
cargo test --all-features

# Specific test
cargo test test_stream_configuration

Linting

cargo clippy --all-features -- -D warnings
cargo fmt --check

๐Ÿ—๏ธ Architecture

Module Organization

screencapturekit/
โ”œโ”€โ”€ cm/                     # Core Media (CMSampleBuffer, CMTime, CVPixelBuffer)
โ”œโ”€โ”€ cg/                     # Core Graphics (CGRect, CGImage)
โ”œโ”€โ”€ stream/                 # Stream management
โ”‚   โ”œโ”€โ”€ configuration/      # SCStreamConfiguration
โ”‚   โ”œโ”€โ”€ content_filter/     # SCContentFilter
โ”‚   โ””โ”€โ”€ sc_stream/          # SCStream
โ”œโ”€โ”€ shareable_content/      # SCShareableContent, SCDisplay, SCWindow
โ”œโ”€โ”€ output/                 # Frame buffers and pixel data
โ”œโ”€โ”€ dispatch_queue/         # Custom dispatch queues
โ”œโ”€โ”€ error/                  # Error types
โ”œโ”€โ”€ screenshot_manager/     # SCScreenshotManager (macOS 14.0+)
โ”œโ”€โ”€ content_sharing_picker/ # SCContentSharingPicker (macOS 14.0+)
โ”œโ”€โ”€ recording_output/       # SCRecordingOutput (macOS 15.0+)
โ”œโ”€โ”€ async_api/              # Async wrappers (feature = "async")
โ”œโ”€โ”€ utils/                  # FFI strings, FourCharCode utilities
โ””โ”€โ”€ prelude/                # Convenience re-exports

Memory Management

  • Reference Counting - Proper CFRetain/CFRelease for all CoreFoundation types
  • RAII - Automatic cleanup in Drop implementations
  • Thread Safety - Safe to share across threads (where supported)
  • Leak Free - Comprehensive leak tests ensure no memory leaks

๐Ÿ”ง Platform Requirements

  • macOS 12.3+ (Monterey) - Base ScreenCaptureKit support
  • macOS 13.0+ (Ventura) - Additional features with macos_13_0
  • macOS 14.0+ (Sonoma) - Content picker, advanced config
  • macOS 15.0+ (Sequoia) - Recording output, HDR capture

๐Ÿค Contributing

Contributions welcome! Please:

  1. Follow existing code patterns (builder pattern with ::build())
  2. Add tests for new functionality
  3. Run cargo test and cargo clippy
  4. Update documentation

๐Ÿ“„ License

Licensed under either of:

at your option.