{"id":21954102,"url":"https://github.com/doom-fish/screencapturekit-rs","last_synced_at":"2025-12-12T14:21:21.442Z","repository":{"id":189673340,"uuid":"681074582","full_name":"doom-fish/screencapturekit-rs","owner":"doom-fish","description":"Rust crate for Apple's ScreenCaptureKit","archived":false,"fork":false,"pushed_at":"2025-12-10T15:26:35.000Z","size":2324,"stargazers_count":159,"open_issues_count":1,"forks_count":36,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-12-10T16:46:44.620Z","etag":null,"topics":["macos","screencapture","screencapturekit"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doom-fish.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-08-21T07:54:28.000Z","updated_at":"2025-12-10T15:19:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"d10e651c-951f-459f-8206-e7ee48e8bd6a","html_url":"https://github.com/doom-fish/screencapturekit-rs","commit_stats":null,"previous_names":["svtlabs/screencapturekit-rs","doom-fish/screencapturekit-rs"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/doom-fish/screencapturekit-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom-fish%2Fscreencapturekit-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom-fish%2Fscreencapturekit-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom-fish%2Fscreencapturekit-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom-fish%2Fscreencapturekit-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doom-fish","download_url":"https://codeload.github.com/doom-fish/screencapturekit-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom-fish%2Fscreencapturekit-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27684586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["macos","screencapture","screencapturekit"],"created_at":"2024-11-29T07:15:34.656Z","updated_at":"2025-12-12T14:21:21.434Z","avatar_url":"https://github.com/doom-fish.png","language":"Rust","funding_links":[],"categories":["Libraries"],"sub_categories":["Video"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003eScreenCaptureKit-rs\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cp\u003e\n    \u003ca href=\"https://crates.io/crates/screencapturekit\"\u003e\u003cimg alt=\"Crates.io\" src=\"https://img.shields.io/crates/v/screencapturekit?style=for-the-badge\u0026logo=rust\u0026color=C9CBFF\u0026logoColor=D9E0EE\u0026labelColor=302D41\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://doom-fish.github.io/screencapturekit-rs/screencapturekit/\"\u003e\u003cimg alt=\"Documentation\" src=\"https://img.shields.io/badge/docs-GitHub%20Pages-blue?style=for-the-badge\u0026logo=gitbook\u0026color=8bd5ca\u0026logoColor=D9E0EE\u0026labelColor=302D41\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/doom-fish/screencapturekit-rs#license\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/crates/l/screencapturekit?style=for-the-badge\u0026logo=apache\u0026color=ee999f\u0026logoColor=D9E0EE\u0026labelColor=302D41\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/doom-fish/screencapturekit-rs/actions\"\u003e\u003cimg alt=\"Build Status\" src=\"https://img.shields.io/github/actions/workflow/status/doom-fish/screencapturekit-rs/ci.yml?branch=main\u0026style=for-the-badge\u0026logo=github\u0026color=c69ff5\u0026logoColor=D9E0EE\u0026labelColor=302D41\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/doom-fish/screencapturekit-rs/stargazers\"\u003e\u003cimg alt=\"Stars\" src=\"https://img.shields.io/github/stars/doom-fish/screencapturekit-rs?style=for-the-badge\u0026logo=starship\u0026color=F5E0DC\u0026logoColor=D9E0EE\u0026labelColor=302D41\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\u003c/div\u003e\n\n\u003e **💼 Looking for a hosted desktop recording API?**  \n\u003e Check out [Recall.ai](https://www.recall.ai/product/desktop-recording-sdk?utm_source=github\u0026utm_medium=sponsorship\u0026utm_campaign=screencapturekit-rs) - an API for recording Zoom, Google Meet, Microsoft Teams, in-person meetings, and more.\n\nSafe, idiomatic Rust bindings for Apple's [ScreenCaptureKit](https://developer.apple.com/documentation/screencapturekit) framework.\n\nCapture screen content, windows, and applications with high performance and low overhead on macOS 12.3+.\n\n\n\n\n## 📑 Table of Contents\n\n- [Features](#-features)\n- [Installation](#-installation)\n- [Quick Start](#-quick-start)\n- [Key Concepts](#-key-concepts)\n- [Feature Flags](#-feature-flags)\n- [API Overview](#-api-overview)\n- [Examples](#-examples)\n- [Testing](#-testing)\n- [Architecture](#-architecture)\n- [Troubleshooting](#-troubleshooting)\n- [Platform Requirements](#-platform-requirements)\n- [Contributing](#-contributing)\n- [License](#-license)\n\n## ✨ Features\n\n- 🎥 **Screen \u0026 Window Capture** - Capture displays, windows, or specific applications\n- 🔊 **Audio Capture** - Capture system audio and microphone input\n- ⚡ **Real-time Processing** - High-performance frame callbacks with custom dispatch queues\n- 🏗️ **Builder Pattern API** - Clean, type-safe configuration with `::builder()`\n- 🔄 **Async Support** - Runtime-agnostic async API (works with Tokio, async-std, smol, etc.)\n- 🎨 **IOSurface Access** - Zero-copy GPU texture access for Metal/OpenGL\n- 🛡️ **Memory Safe** - Proper reference counting and leak-free by design\n- 📦 **Zero Dependencies** - No runtime dependencies (only dev dependencies for examples)\n\n\n\nhttps://github.com/user-attachments/assets/8a272c48-7ec3-4132-9111-4602b4fa991d\n\n## 📦 Installation\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\nscreencapturekit = \"1\"\n```\n\nFor async support:\n\n```toml\n[dependencies]\nscreencapturekit = { version = \"1\", features = [\"async\"] }\n```\n\nFor latest macOS features:\n\n```toml\n[dependencies]\nscreencapturekit = { version = \"1\", features = [\"macos_26_0\"] }\n```\n\n## 🚀 Quick Start\n\n### Basic Screen Capture\n\n```rust\nuse screencapturekit::prelude::*;\n\nstruct Handler;\n\nimpl SCStreamOutputTrait for Handler {\n    fn did_output_sample_buffer(\u0026self, sample: CMSampleBuffer, _type: SCStreamOutputType) {\n        println!(\"📹 Received frame at {:?}\", sample.presentation_timestamp());\n    }\n}\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    // Get available displays\n    let content = SCShareableContent::get()?;\n    let display = \u0026content.displays()[0];\n    \n    // Configure capture\n    let filter = SCContentFilter::builder()\n        .display(display)\n        .exclude_windows(\u0026[])\n        .build();\n    \n    let config = SCStreamConfiguration::new()\n        .with_width(1920)\n        .with_height(1080)\n        .with_pixel_format(PixelFormat::BGRA);\n    \n    // Start streaming\n    let mut stream = SCStream::new(\u0026filter, \u0026config);\n    stream.add_output_handler(Handler, SCStreamOutputType::Screen);\n    stream.start_capture()?;\n    \n    // Capture runs in background...\n    std::thread::sleep(std::time::Duration::from_secs(5));\n    \n    stream.stop_capture()?;\n    Ok(())\n}\n```\n\n### Async Capture\n\n```rust\nuse screencapturekit::async_api::{AsyncSCShareableContent, AsyncSCStream};\nuse screencapturekit::prelude::*;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    // Get content asynchronously\n    let content = AsyncSCShareableContent::get().await?;\n    let display = \u0026content.displays()[0];\n    \n    // Create filter and config\n    let filter = SCContentFilter::builder()\n        .display(display)\n        .exclude_windows(\u0026[])\n        .build();\n    \n    let config = SCStreamConfiguration::new()\n        .with_width(1920)\n        .with_height(1080);\n    \n    // Create async stream with frame buffer\n    let stream = AsyncSCStream::new(\u0026filter, \u0026config, 30, SCStreamOutputType::Screen);\n    stream.start_capture()?;\n    \n    // Capture frames asynchronously\n    for _ in 0..10 {\n        if let Some(frame) = stream.next().await {\n            println!(\"📹 Got frame!\");\n        }\n    }\n    \n    stream.stop_capture()?;\n    Ok(())\n}\n```\n\n### Window Capture with Audio\n\n```rust\nuse screencapturekit::prelude::*;\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let content = SCShareableContent::get()?;\n    \n    // Find a specific window\n    let window = content.windows()\n        .iter()\n        .find(|w| w.title().as_deref() == Some(\"Safari\"))\n        .ok_or(\"Safari window not found\")?;\n    \n    // Capture window with audio\n    let filter = SCContentFilter::builder()\n        .window(window)\n        .build();\n    \n    let config = SCStreamConfiguration::new()\n        .with_width(1920)\n        .with_height(1080)\n        .with_captures_audio(true)\n        .with_sample_rate(48000)\n        .with_channel_count(2);\n    \n    let mut stream = SCStream::new(\u0026filter, \u0026config);\n    // Add handlers...\n    stream.start_capture()?;\n    \n    Ok(())\n}\n```\n\n### Content Picker (macOS 14.0+)\n\nUse the system picker UI to let users choose what to capture:\n\n```rust\nuse screencapturekit::content_sharing_picker::*;\nuse screencapturekit::prelude::*;\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let config = SCContentSharingPickerConfiguration::new();\n    \n    // Show picker - callback receives result when user selects or cancels\n    SCContentSharingPicker::show(\u0026config, |outcome| {\n        match outcome {\n            SCPickerOutcome::Picked(result) =\u003e {\n                // Get dimensions from the picked content\n                let (width, height) = result.pixel_size();\n                println!(\"Selected: {}x{} (scale: {})\", width, height, result.scale());\n                \n                let stream_config = SCStreamConfiguration::new()\n                    .with_width(width)\n                    .with_height(height);\n                \n                // Get filter for streaming\n                let filter = result.filter();\n                let mut stream = SCStream::new(\u0026filter, \u0026stream_config);\n                // ...\n            }\n            SCPickerOutcome::Cancelled =\u003e println!(\"User cancelled\"),\n            SCPickerOutcome::Error(e) =\u003e eprintln!(\"Error: {}\", e),\n        }\n    });\n    \n    Ok(())\n}\n```\n\n### Async Content Picker (macOS 14.0+)\n\nUse the async version in async contexts to avoid blocking:\n\n```rust\nuse screencapturekit::async_api::AsyncSCContentSharingPicker;\nuse screencapturekit::content_sharing_picker::*;\nuse screencapturekit::prelude::*;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let config = SCContentSharingPickerConfiguration::new();\n    \n    // Async picker - doesn't block the executor\n    match AsyncSCContentSharingPicker::show(\u0026config).await {\n        SCPickerOutcome::Picked(result) =\u003e {\n            let (width, height) = result.pixel_size();\n            println!(\"Selected: {}x{}\", width, height);\n            \n            let filter = result.filter();\n            // Use filter with stream...\n        }\n        SCPickerOutcome::Cancelled =\u003e println!(\"User cancelled\"),\n        SCPickerOutcome::Error(e) =\u003e eprintln!(\"Error: {}\", e),\n    }\n    \n    Ok(())\n}\n```\n\n## 🎯 Key Concepts\n\n### Builder Pattern\n\nDifferent types use slightly different patterns:\n\n```rust\n// Content filters use .builder() with .build()\nlet filter = SCContentFilter::builder()\n    .display(\u0026display)\n    .exclude_windows(\u0026windows)\n    .build();\n\n// Stream configuration uses ::new() with .with_*() chainable methods\nlet config = SCStreamConfiguration::new()\n    .with_width(1920)\n    .with_height(1080)\n    .with_pixel_format(PixelFormat::BGRA)\n    .with_captures_audio(true);\n\n// Options for content retrieval\nlet content = SCShareableContent::with_options()\n    .on_screen_windows_only(true)\n    .exclude_desktop_windows(true)\n    .get()?;\n```\n\n### Custom Dispatch Queues\n\nControl callback threading with custom dispatch queues:\n\n```rust\nuse screencapturekit::dispatch_queue::{DispatchQueue, DispatchQoS};\n\nlet queue = DispatchQueue::new(\"com.myapp.capture\", DispatchQoS::UserInteractive);\n\nstream.add_output_handler_with_queue(\n    my_handler,\n    SCStreamOutputType::Screen,\n    Some(\u0026queue)\n);\n```\n\n**QoS Levels:**\n- `Background` - Maintenance tasks\n- `Utility` - Long-running tasks\n- `Default` - Standard priority\n- `UserInitiated` - User-initiated tasks\n- `UserInteractive` - UI updates (highest priority)\n\n### IOSurface Access\n\nZero-copy GPU texture access:\n\n```rust\nimpl SCStreamOutputTrait for Handler {\n    fn did_output_sample_buffer(\u0026self, sample: CMSampleBuffer, _type: SCStreamOutputType) {\n        if let Some(pixel_buffer) = sample.image_buffer() {\n            if let Some(surface) = pixel_buffer.iosurface() {\n                let width = surface.width();\n                let height = surface.height();\n                \n                // Use with Metal/OpenGL...\n                println!(\"IOSurface: {}x{}\", width, height);\n            }\n        }\n    }\n}\n```\n\n### Metal Integration\n\nBuilt-in Metal types for hardware-accelerated rendering without external crates:\n\n```rust\nuse screencapturekit::output::metal::{\n    MetalDevice, MetalLayer, MetalRenderPassDescriptor, MetalRenderPipelineDescriptor,\n    MTLLoadAction, MTLStoreAction, MTLPrimitiveType, MTLPixelFormat,\n    Uniforms, SHADER_SOURCE,\n};\nuse screencapturekit::output::CVPixelBufferIOSurface;\n\n// Get the system default Metal device\nlet device = MetalDevice::system_default().expect(\"No Metal device\");\nlet command_queue = device.create_command_queue().unwrap();\n\n// Compile built-in shaders (supports BGRA, YCbCr, UI overlays)\nlet library = device.create_library_with_source(SHADER_SOURCE)?;\n\n// Create render pipeline for textured rendering\nlet vert_fn = library.get_function(\"vertex_fullscreen\").unwrap();\nlet frag_fn = library.get_function(\"fragment_textured\").unwrap();\nlet pipeline_desc = MetalRenderPipelineDescriptor::new();\npipeline_desc.set_vertex_function(\u0026vert_fn);\npipeline_desc.set_fragment_function(\u0026frag_fn);\npipeline_desc.set_color_attachment_pixel_format(0, MTLPixelFormat::BGRA8Unorm);\nlet pipeline = device.create_render_pipeline_state(\u0026pipeline_desc).unwrap();\n\n// In your frame handler - create textures and render\nimpl SCStreamOutputTrait for Handler {\n    fn did_output_sample_buffer(\u0026self, sample: CMSampleBuffer, _type: SCStreamOutputType) {\n        if let Some(pixel_buffer) = sample.image_buffer() {\n            if let Some(surface) = pixel_buffer.iosurface() {\n                // Zero-copy texture creation from IOSurface\n                if let Some(textures) = surface.create_metal_textures(\u0026device) {\n                    // Create uniforms for aspect-ratio-preserving rendering\n                    let uniforms = Uniforms::from_captured_textures(\n                        viewport_width, viewport_height, \u0026textures\n                    );\n                    let uniform_buffer = device.create_buffer_with_data(\u0026uniforms).unwrap();\n                    \n                    // Render to a CAMetalLayer drawable\n                    let drawable = layer.next_drawable().unwrap();\n                    let cmd_buffer = command_queue.command_buffer().unwrap();\n                    \n                    let render_pass = MetalRenderPassDescriptor::new();\n                    render_pass.set_color_attachment_texture(0, \u0026drawable.texture());\n                    render_pass.set_color_attachment_load_action(0, MTLLoadAction::Clear);\n                    render_pass.set_color_attachment_store_action(0, MTLStoreAction::Store);\n                    \n                    let encoder = cmd_buffer.render_command_encoder(\u0026render_pass).unwrap();\n                    encoder.set_render_pipeline_state(\u0026pipeline);\n                    encoder.set_vertex_buffer(\u0026uniform_buffer, 0, 0);\n                    encoder.set_fragment_texture(\u0026textures.plane0, 0);\n                    if let Some(ref plane1) = textures.plane1 {\n                        encoder.set_fragment_texture(plane1, 1);  // CbCr for YCbCr\n                    }\n                    encoder.draw_primitives(MTLPrimitiveType::TriangleStrip, 0, 4);\n                    encoder.end_encoding();\n                    \n                    cmd_buffer.present_drawable(\u0026drawable);\n                    cmd_buffer.commit();\n                }\n            }\n        }\n    }\n}\n```\n\n**Built-in Shader Functions:**\n- `vertex_fullscreen` - Aspect-ratio-preserving fullscreen quad\n- `fragment_textured` - BGRA/L10R single-texture rendering\n- `fragment_ycbcr` - YCbCr biplanar (420v/420f) to RGB conversion\n- `vertex_colored` / `fragment_colored` - UI overlay rendering\n\n**Metal Types:**\n- `MetalDevice`, `MetalCommandQueue`, `MetalCommandBuffer`\n- `MetalTexture`, `MetalBuffer`, `MetalLayer`, `MetalDrawable`\n- `MetalRenderPipelineState`, `MetalRenderPassDescriptor`\n- `CapturedTextures\u003cT\u003e` - Multi-plane texture container (Y + CbCr for YCbCr formats)\n\n## 🎛️ Feature Flags\n\n### Core Features\n\n| Feature | Description |\n|---------|-------------|\n| `async` | Runtime-agnostic async API (works with any executor) |\n\n### macOS Version Features\n\nFeature flags enable APIs for specific macOS versions. They are cumulative (enabling `macos_15_0` enables all earlier versions).\n\n| Feature | macOS | APIs Enabled |\n|---------|-------|--------------|\n| `macos_13_0` | 13.0 Ventura | Audio capture, synchronization clock |\n| `macos_14_0` | 14.0 Sonoma | Content picker, screenshots, content info |\n| `macos_14_2` | 14.2 | Menu bar capture, child windows, presenter overlay |\n| `macos_14_4` | 14.4 | Current process shareable content |\n| `macos_15_0` | 15.0 Sequoia | Recording output, HDR capture, microphone |\n| `macos_15_2` | 15.2 | Screenshot in rect, stream active/inactive delegates |\n| `macos_26_0` | 26.0 | Advanced screenshot config, HDR screenshot output |\n\n### Version-Specific Example\n\n```rust\nlet mut config = SCStreamConfiguration::new()\n    .with_width(1920)\n    .with_height(1080);\n\n#[cfg(feature = \"macos_13_0\")]\nconfig.set_should_be_opaque(true);\n\n#[cfg(feature = \"macos_14_2\")]\n{\n    config.set_ignores_shadows_single_window(true);\n    config.set_includes_child_windows(false);\n}\n```\n\n## 📚 API Overview\n\n### Core Types\n\n| Type | Description |\n|------|-------------|\n| [`SCShareableContent`] | Query available displays, windows, and applications |\n| [`SCContentFilter`] | Define what to capture (display/window/app) |\n| [`SCStreamConfiguration`] | Configure resolution, format, audio, etc. |\n| [`SCStream`] | Main capture stream with output handlers |\n| [`CMSampleBuffer`] | Frame data with timing and metadata |\n\n[`SCShareableContent`]: https://doom-fish.github.io/screencapturekit-rs/screencapturekit/shareable_content/struct.SCShareableContent.html\n[`SCContentFilter`]: https://doom-fish.github.io/screencapturekit-rs/screencapturekit/stream/content_filter/struct.SCContentFilter.html\n[`SCStreamConfiguration`]: https://doom-fish.github.io/screencapturekit-rs/screencapturekit/stream/configuration/struct.SCStreamConfiguration.html\n[`SCStream`]: https://doom-fish.github.io/screencapturekit-rs/screencapturekit/stream/sc_stream/struct.SCStream.html\n[`CMSampleBuffer`]: https://doom-fish.github.io/screencapturekit-rs/screencapturekit/cm/struct.CMSampleBuffer.html\n\n### Async API (requires `async` feature)\n\n| Type | Description |\n|------|-------------|\n| `AsyncSCShareableContent` | Async content queries |\n| `AsyncSCStream` | Async stream with frame iteration |\n| `AsyncSCScreenshotManager` | Async screenshot capture (macOS 14.0+) |\n| `AsyncSCContentSharingPicker` | Async content picker UI (macOS 14.0+) |\n\n### Display \u0026 Window Types\n\n| Type | Description |\n|------|-------------|\n| `SCDisplay` | Display information (resolution, ID, frame) |\n| `SCWindow` | Window information (title, bounds, owner, layer) |\n| `SCRunningApplication` | Application information (name, bundle ID, PID) |\n\n### Media Types\n\n| Type | Description |\n|------|-------------|\n| `CMSampleBuffer` | Sample buffer with timing and attachments |\n| `CMTime` | High-precision timestamps with timescale |\n| `IOSurface` | GPU-backed pixel buffers for zero-copy access |\n| `CGImage` | Core Graphics images for screenshots |\n| `CVPixelBuffer` | Core Video pixel buffer with lock guards |\n\n### Metal Types (`metal` module)\n\n| Type | Description |\n|------|-------------|\n| `MetalDevice` | Metal GPU device wrapper |\n| `MetalTexture` | Metal texture with automatic retain/release |\n| `MetalBuffer` | Vertex/uniform buffer |\n| `MetalCommandQueue` / `MetalCommandBuffer` | Command submission |\n| `MetalLayer` | `CAMetalLayer` for window rendering |\n| `MetalRenderPipelineState` | Compiled render pipeline |\n| `CapturedTextures\u003cT\u003e` | Multi-plane texture container (Y + CbCr for YCbCr) |\n| `Uniforms` | Shader uniform structure matching `SHADER_SOURCE` |\n\n### Configuration Types\n\n| Type | Description |\n|------|-------------|\n| `PixelFormat` | BGRA, YCbCr420v, YCbCr420f, l10r (10-bit) |\n| `SCPresenterOverlayAlertSetting` | Privacy alert behavior |\n| `SCCaptureDynamicRange` | HDR/SDR modes (macOS 15.0+) |\n| `SCScreenshotConfiguration` | Advanced screenshot config (macOS 26.0+) |\n| `SCScreenshotDynamicRange` | SDR/HDR screenshot output (macOS 26.0+) |\n\n## 🏃 Examples\n\nThe [`examples/`](examples/) directory contains focused API demonstrations:\n\n### Quick Start (Numbered by Complexity)\n1. **`01_basic_capture.rs`** - Simplest screen capture\n2. **`02_window_capture.rs`** - Capture specific windows\n3. **`03_audio_capture.rs`** - Audio + video capture\n4. **`04_pixel_access.rs`** - Read pixel data with `std::io::Cursor`\n5. **`05_screenshot.rs`** - Single screenshot, HDR capture (macOS 14.0+, 26.0+)\n6. **`06_iosurface.rs`** - Zero-copy GPU buffers\n7. **`07_list_content.rs`** - List available content\n8. **`08_async.rs`** - Async/await API with multiple examples\n9. **`09_closure_handlers.rs`** - Closure-based handlers and delegates\n10. **`10_recording_output.rs`** - Direct video file recording (macOS 15.0+)\n11. **`11_content_picker.rs`** - System UI for content selection (macOS 14.0+)\n12. **`12_stream_updates.rs`** - Dynamic config/filter updates\n13. **`13_advanced_config.rs`** - HDR, presets, microphone (macOS 15.0+)\n14. **`14_app_capture.rs`** - Application-based filtering\n15. **`15_memory_leak_check.rs`** - Memory leak detection with `leaks`\n16. **`16_full_metal_app/`** - Full Metal GUI application (macOS 14.0+)\n17. **`17_metal_textures.rs`** - Metal texture creation from IOSurface\n\nSee [`examples/README.md`](examples/README.md) for detailed descriptions.\n\nRun an example:\n\n```bash\n# Basic examples\ncargo run --example 01_basic_capture\ncargo run --example 09_closure_handlers\ncargo run --example 12_stream_updates\ncargo run --example 14_app_capture\ncargo run --example 17_metal_textures\n\n# Feature-gated examples\ncargo run --example 05_screenshot --features macos_14_0\ncargo run --example 08_async --features async\ncargo run --example 10_recording_output --features macos_15_0\ncargo run --example 11_content_picker --features macos_14_0\ncargo run --example 13_advanced_config --features macos_15_0\ncargo run --example 16_full_metal_app --features macos_14_0\n```\n\n## 🧪 Testing\n\n### Run Tests\n\n```bash\n# All tests\ncargo test\n\n# With features\ncargo test --features async\ncargo test --all-features\n\n# Specific test\ncargo test test_stream_configuration\n```\n\n### Linting\n\n```bash\ncargo clippy --all-features -- -D warnings\ncargo fmt --check\n```\n\n## 🏗️ Architecture\n\n### Module Organization\n\n```\nscreencapturekit/\n├── cm/                     # Core Media (CMSampleBuffer, CMTime, CVPixelBuffer)\n├── cg/                     # Core Graphics (CGRect, CGImage)\n├── stream/                 # Stream management\n│   ├── configuration/      # SCStreamConfiguration\n│   ├── content_filter/     # SCContentFilter\n│   └── sc_stream/          # SCStream\n├── shareable_content/      # SCShareableContent, SCDisplay, SCWindow\n├── output/                 # Frame buffers and pixel data\n├── dispatch_queue/         # Custom dispatch queues\n├── error/                  # Error types\n├── screenshot_manager/     # SCScreenshotManager (macOS 14.0+)\n├── content_sharing_picker/ # SCContentSharingPicker (macOS 14.0+)\n├── recording_output/       # SCRecordingOutput (macOS 15.0+)\n├── async_api/              # Async wrappers (feature = \"async\")\n├── utils/                  # FFI strings, FourCharCode utilities\n└── prelude/                # Convenience re-exports\n```\n\n### Memory Management\n\n- **Reference Counting** - Proper CFRetain/CFRelease for all CoreFoundation types\n- **RAII** - Automatic cleanup in Drop implementations\n- **Thread Safety** - Safe to share across threads (where supported)\n- **Leak Free** - Comprehensive leak tests ensure no memory leaks\n\n## ❓ Troubleshooting\n\n### Permission Denied / No Displays Found\n\n**Problem**: `SCShareableContent::get()` returns an error or empty lists.\n\n**Solution**: Grant screen recording permission:\n1. Open **System Preferences** → **Privacy \u0026 Security** → **Screen Recording**\n2. Add your app or Terminal to the list\n3. Restart your application\n\nFor development, you may need to add Terminal.app to the allowed list.\n\n### Entitlements for App Store / Notarization\n\n**Problem**: App crashes or permissions fail after notarization.\n\n**Solution**: Add required entitlements to your `entitlements.plist`:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n\u003cdict\u003e\n    \u003ckey\u003ecom.apple.security.app-sandbox\u003c/key\u003e\n    \u003ctrue/\u003e\n    \u003ckey\u003ecom.apple.security.screen-capture\u003c/key\u003e\n    \u003ctrue/\u003e\n\u003c/dict\u003e\n\u003c/plist\u003e\n```\n\n### Black Frames / No Video Data\n\n**Problem**: Frames are received but contain no visible content.\n\n**Solutions**:\n1. Ensure the captured window/display is visible (not minimized)\n2. Check that `pixel_format` matches your processing expectations\n3. Verify the content filter includes the correct display/window\n4. On Apple Silicon, ensure proper GPU access\n\n### Audio Capture Not Working\n\n**Problem**: Audio samples not received or empty.\n\n**Solutions**:\n1. Enable audio capture: `.with_captures_audio(true)`\n2. Add an audio output handler: `stream.add_output_handler(handler, SCStreamOutputType::Audio)`\n3. Verify `sample_rate` and `channel_count` are set correctly\n\n### Build Errors\n\n**Problem**: Compilation fails with Swift bridge errors.\n\n**Solutions**:\n1. Ensure Xcode Command Line Tools are installed: `xcode-select --install`\n2. Clean and rebuild: `cargo clean \u0026\u0026 cargo build`\n3. Check that you're on macOS (this crate is macOS-only)\n\n## 🔧 Platform Requirements\n\n- **macOS 12.3+** (Monterey) - Base ScreenCaptureKit support\n- **macOS 13.0+** (Ventura) - Audio capture, synchronization clock\n- **macOS 14.0+** (Sonoma) - Content picker, screenshots, content info\n- **macOS 15.0+** (Sequoia) - Recording output, HDR capture, microphone\n- **macOS 26.0+** (Tahoe) - Advanced screenshot config, HDR screenshot output\n\n### Screen Recording Permission\n\nScreen recording requires explicit user permission. For development:\n- Terminal/IDE must be in **System Preferences** → **Privacy \u0026 Security** → **Screen Recording**\n\nFor distribution:\n- Add `NSScreenCaptureUsageDescription` to your `Info.plist`\n- Sign with appropriate entitlements for notarization\n\n## 🤝 Contributing\n\nContributions welcome! Please:\n\n1. Follow existing code patterns (builder pattern with `::new()` and `.with_*()` methods)\n2. Add tests for new functionality\n3. Run `cargo test` and `cargo clippy`\n4. Update documentation\n\n## 👥 Contributors\n\nThanks to everyone who has contributed to this project!\n\n- [Per Johansson](https://github.com/doom-fish) - Maintainer\n- [Iason Paraskevopoulos](https://github.com/iasparaskev)\n- [Kris Krolak](https://github.com/kriskrolak)\n- [Tokuhiro Matsuno](https://github.com/tokuhirom)\n- [Pranav Joglekar](https://github.com/pranavj1001)\n- [Alex Jiao](https://github.com/uohzxela)\n- [Charles](https://github.com/aizukanne)\n- [bigduu](https://github.com/bigduu)\n\n## 📄 License\n\nLicensed under either of:\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n- MIT License ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoom-fish%2Fscreencapturekit-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoom-fish%2Fscreencapturekit-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoom-fish%2Fscreencapturekit-rs/lists"}