| Crates.io | dxgi-capture-rs |
| lib.rs | dxgi-capture-rs |
| version | 1.1.7 |
| created_at | 2025-07-08 22:29:22.915098+00 |
| updated_at | 2025-07-09 23:49:44.913211+00 |
| description | High-performance screen capturing with DXGI Desktop Duplication API for Windows in Rust |
| homepage | |
| repository | https://github.com/RobbyV2/dxgi-capture-rs |
| max_upload_size | |
| id | 1743669 |
| size | 145,384 |
High-performance screen capturing with DXGI Desktop Duplication API for Windows in Rust.
This library provides a high-performance Rust interface to the Windows DXGI Desktop Duplication API, allowing you to capture screen content efficiently. It's designed for applications that need real-time screen capture capabilities with minimal performance overhead.
use dxgi_capture_rs::{DXGIManager, CaptureError};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new DXGI manager with 1000ms timeout
let mut manager = DXGIManager::new(1000)?;
// Get screen dimensions
let (width, height) = manager.geometry();
println!("Screen: {}x{}", width, height);
// Capture a frame
match manager.capture_frame() {
Ok((pixels, (frame_width, frame_height))) => {
println!("Captured {}x{} frame with {} pixels",
frame_width, frame_height, pixels.len());
// Process your pixel data here
// pixels is Vec<BGRA8> where each pixel has b, g, r, a components
}
Err(CaptureError::Timeout) => {
println!("Capture timed out - no new frame available");
}
Err(e) => {
eprintln!("Capture failed: {:?}", e);
}
}
Ok(())
}
The library provides detailed frame metadata including dirty rectangles and moved rectangles, which is crucial for optimizing streaming and remote desktop applications. This allows you to only process and transmit the parts of the screen that have actually changed.
use dxgi_capture_rs::{DXGIManager, CaptureError};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut manager = DXGIManager::new(1000)?;
match manager.capture_frame_with_metadata() {
Ok((pixels, (width, height), metadata)) => {
// Only process frame if there are actual changes
if metadata.has_updates() {
println!("Frame has {} dirty rects and {} move rects",
metadata.dirty_rects.len(), metadata.move_rects.len());
// Process moved rectangles first (as per Microsoft recommendation)
for move_rect in &metadata.move_rects {
let (src_x, src_y) = move_rect.source_point;
let (dst_left, dst_top, dst_right, dst_bottom) = move_rect.destination_rect;
// Copy pixels from source to destination
// This is much more efficient than re-encoding the entire area
println!("Content moved from ({}, {}) to ({}, {}, {}, {})",
src_x, src_y, dst_left, dst_top, dst_right, dst_bottom);
}
// Then process dirty rectangles
for &(left, top, right, bottom) in &metadata.dirty_rects {
let width = (right - left) as usize;
let height = (bottom - top) as usize;
// Only encode/transmit the changed region
println!("Dirty region: ({}, {}) to ({}, {}) [{}x{}]",
left, top, right, bottom, width, height);
}
}
// Check for mouse cursor updates
if metadata.has_mouse_updates() {
if let Some((x, y)) = metadata.pointer_position {
println!("Mouse cursor at ({}, {}), visible: {}", x, y, metadata.pointer_visible);
}
}
// Access timing information
if metadata.accumulated_frames > 1 {
println!("This frame accumulated {} updates", metadata.accumulated_frames);
}
}
Err(CaptureError::Timeout) => {
println!("No new frame available");
}
Err(e) => {
eprintln!("Capture failed: {:?}", e);
}
}
Ok(())
}
The main interface for screen capture operations.
new(timeout_ms: u32) -> Result<DXGIManager, &'static str> - Create a new managergeometry() -> (usize, usize) - Get screen dimensionscapture_frame() -> Result<(Vec<BGRA8>, (usize, usize)), CaptureError> - Capture a framecapture_frame_components() -> Result<(Vec<u8>, (usize, usize)), CaptureError> - Capture raw componentscapture_frame_with_metadata() -> Result<(Vec<BGRA8>, (usize, usize), FrameMetadata), CaptureError> - Capture with metadatacapture_frame_components_with_metadata() -> Result<(Vec<u8>, (usize, usize), FrameMetadata), CaptureError> - Capture raw components with metadataset_capture_source_index(index: usize) - Select capture source (monitor)set_timeout_ms(timeout_ms: u32) - Update capture timeoutCaptureError::AccessDenied - Could not duplicate output (protected content)CaptureError::AccessLost - Output duplication was lost (mode change)CaptureError::RefreshFailure - Could not refresh after failureCaptureError::Timeout - AcquireNextFrame timed outCaptureError::Fail(msg) - General failure with descriptionContains frame information and change detection data:
dirty_rects: Vec<(i32, i32, i32, i32)> - Changed screen regions (left, top, right, bottom)move_rects: Vec<MoveRect> - Moved screen regionspointer_position: Option<(i32, i32)> - Mouse cursor position if visiblepointer_visible: bool - Whether mouse cursor is visiblelast_present_time: i64 - Windows performance counter timestamplast_mouse_update_time: i64 - Last mouse update timestampaccumulated_frames: u32 - Number of frames accumulated since last processedrects_coalesced: bool - Whether rectangles were merged by the systemprotected_content_masked_out: bool - Whether protected content was hiddenhas_updates() -> bool - Returns true if frame has any changeshas_mouse_updates() -> bool - Returns true if mouse cursor was updatedtotal_change_count() -> usize - Returns total number of changed regionsRepresents content moved from one location to another:
source_point: (i32, i32) - Source location (x, y)destination_rect: (i32, i32, i32, i32) - Destination rectangle (left, top, right, bottom)let mut manager = DXGIManager::new(1000)?;
// Capture from primary monitor (index 0)
manager.set_capture_source_index(0);
// Capture from secondary monitor (index 1, if available)
manager.set_capture_source_index(1);
capture_frame_components() if you need raw byte datagit clone https://github.com/RobbyV2/dxgi-capture-rs.git
cd dxgi-capture-rs
cargo build --release
This will build both the main library and the example application. You can also build just the library:
cargo build --release --package dxgi-capture-rs
The repository includes a complete example application that demonstrates real-time desktop streaming using egui. This example shows how to:
To run the example:
cargo run --package example-stream
The example application captures your desktop and displays it in a window with the following features:
Note: The example requires an active desktop session and may not work in headless environments.
cargo test
Note: Tests may not run properly in headless environments (CI) as they require an active desktop session.
This project is licensed under the MIT License.
See LICENSE for details.
This is a Cargo workspace containing:
dxgi-capture-rs - The main library crate (published to crates.io)example-stream - Example application demonstrating real-time desktop streaming with egui (development only)The workspace is configured so that: