| Crates.io | ccap-rs |
| lib.rs | ccap-rs |
| version | 1.5.1 |
| created_at | 2026-01-11 12:43:57.918626+00 |
| updated_at | 2026-01-12 17:35:25.437478+00 |
| description | Rust bindings for ccap — high-performance, cross-platform webcam/camera capture with hardware-accelerated pixel format conversion (DirectShow/AVFoundation/V4L2), including common RGB/YUV workflows and video file input/playback support |
| homepage | https://ccap.work |
| repository | https://github.com/wysaid/CameraCapture |
| max_upload_size | |
| id | 2035760 |
| size | 706,545 |
Safe Rust bindings for CameraCapture (ccap) — a high-performance, lightweight, cross-platform webcam/camera capture library with hardware-accelerated pixel format conversion (Windows DirectShow, macOS/iOS AVFoundation, Linux V4L2).
Note: The published package name on crates.io is
ccap-rs, but the crate name in code isccap.
Option A (simple):
cargo add ccap-rs
Option B (recommended): keep the crate name as ccap in your code:
[dependencies]
ccap = { package = "ccap-rs", version = "<latest>" }
Tip: Replace
<latest>with the latest version shown on https://crates.io/crates/ccap-rs
use ccap::{Provider, Result};
fn main() -> Result<()> {
// Create a camera provider
let mut provider = Provider::new()?;
// Find available cameras
let devices = provider.find_device_names()?;
println!("Found {} cameras:", devices.len());
for (i, device) in devices.iter().enumerate() {
println!(" [{}] {}", i, device);
}
// Open the first camera
if !devices.is_empty() {
provider.open_device(Some(&devices[0]), true)?;
println!("Camera opened successfully!");
// Capture a frame (with 3 second timeout)
if let Some(frame) = provider.grab_frame(3000)? {
let info = frame.info()?;
println!("Captured frame: {}x{}, format: {:?}",
info.width, info.height, info.pixel_format);
// Access frame data
let data = frame.data()?;
println!("Frame data size: {} bytes", data.len());
}
}
Ok(())
}
The crate includes several examples:
# List available cameras and their info
cargo run --example print_camera
# Minimal capture example
cargo run --example minimal_example
# Capture frames using grab mode
cargo run --example capture_grab
# Capture frames using callback mode
cargo run --example capture_callback
This crate supports two build modes:
build-source — Builds the native C/C++ implementation via the cc crate (intended for crates.io users).static-link — Links against a pre-built native library from a CameraCapture checkout (e.g. build/Debug/libccap.a) (intended for developing this repository).If you are using development mode (static-link), you need to build the native library first:
# From the root of the CameraCapture project
./scripts/build_and_install.sh
Or manually:
mkdir -p build/Debug
cd build/Debug
cmake ../.. -DCMAKE_BUILD_TYPE=Debug
make -j$(nproc)
# From bindings/rust directory
cargo build
cargo test
static-link)# Link against pre-built build/Debug or build/Release from the repo
cargo build --no-default-features --features static-link
cargo test --no-default-features --features static-link
static-linkThe CameraCapture repo's test scripts may build the native library with ASan enabled (e.g. Debug functional tests).
An ASan-instrumented libccap.a requires the ASan runtime at link/run time.
static-link, build.rs will only link the ASan runtime if it detects ASan symbols inside the prebuilt libccap.a.build-source).CCAP_RUST_NO_ASAN_LINK=1.build-source (default): build the C/C++ ccap sources during cargo build (best for crates.io usage).static-link: link against a pre-built static library from a CameraCapture checkout (best for development). If you use this mode, make sure you have built the C/C++ project first, and set CCAP_SOURCE_DIR when needed.Provider: Main camera capture interfaceVideoFrame: Represents a captured video frameDeviceInfo: Camera device informationPixelFormat: Supported pixel formats (RGB24, BGR24, NV12, I420, etc.)Resolution: Frame resolution specificationAll operations return Result<T, CcapError> for comprehensive error handling.
For frame capture, grab_frame(timeout_ms) returns Result<Option<VideoFrame>, CcapError>:
match provider.grab_frame(3000) { // 3 second timeout
Ok(Some(frame)) => { /* process frame */ },
Ok(None) => println!("No frame available"),
Err(e) => eprintln!("Capture error: {:?}", e),
}
VideoFrame implements Send so frames can be moved across threads (e.g. processed/dropped on a worker thread)Provider implements Send but the underlying C++ API is not thread-safe
Provider from a single thread, or wrap it with Arc<Mutex<Provider>> for multi-threaded accessVideoFrame is droppedNote: The C++ layer's thread-safety is based on code inspection. If you encounter issues with cross-thread frame usage, please report them.
| Platform | Backend | Status |
|---|---|---|
| Windows | DirectShow | ✅ Supported |
| macOS | AVFoundation | ✅ Supported |
| iOS | AVFoundation | ✅ Supported |
| Linux | V4L2 | ✅ Supported |
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.