Making applications with libobscura

Importing

The main crate of libobscura is libvidi. This crate controls the basic properties of cameras. To include it as a dependency in your application, add this to your Cargo.toml file:

[dependencies]
libvidi = { git = "https://codeberg.org/libobscura/libobscura.git", branch = "master" }

Caution! Libvidi is still developing rapidly and may introduce breaking changes at any time.

Usage

The basic objects in libobscura are:

You need to use them all to get a picture from the camera:

use vidi;
// The tracker is notified about all supported cameras on the system.
let cameras_tracker = vidi::actors::camera_list::spawn()?;

// The list of cameras present at the moment
let cameras = cameras_tracker.cameras();

// The info for the first camera on the list
let camera_info = &cameras[0].0;

// Create a camera device
let camera = cameras_list.create(camera_info.id)
    .unwrap().unwrap();

The operations so far are unlikely to fail under normal circumstances. The next step, though, will fail if some other application is already using the camera:

// Take exclusive ownership of the camera on the entire system.
let mut camera = camera.acquire().unwrap();

Now you're ready to start streaming and receive pictures.

Streams and buffers

Libobscura exposes two APIs to start streaming and get pictures to application developers.

One is easy, but forces you to make a copy if you want to do anything complex: it's the "borrowing" API.

The "owning" API is more powerful: it avoids copies (zero-copy) and lets you send buffers across threads. As a downside, you must re-queue your buffers back in the camera manually, so you can cause dead locks and memory leaks.

Both APIs offer the same configuration options, so choose the appropriate one.

Borrowing

The "decode_frame.rs" example uses the easy Stream API.

// Start capturing
let mut stream = camera.start(
    // Choose your preferred data format
    Config{fourcc: FourCC::new(b"YUYV"), width: 640, height: 480},
    4
).unwrap();

loop {
    // Get next frame
    let (buf, meta, _next) = stream.next().unwrap();

    let mmap = buf.memory_map_ro().unwrap();
    let data = mmap.as_slice();
    // process the raw pixel data here
}

Note that the program will not get to the next frame if you spend too much time processing this one. This will cause frame dropping. The buffer is borrowed and it belongs to the Stream instance, so you can't send it to another thread for processing, either.

A mug with a black chain attached to its handle

Figure: A buffer borrowing API was chosen, among others, to prevent losing buffers.

Owning

The owning API gives you ownership of buffers, and expects you to return them when you're done. Because you own the buffers, you can send them between threads and even lose and leak them – in safe code (leaking is not, strictly speaking, unsafe).

See the example "glium.rs".

A table with a tea set, with a trash bin underneath. There's a spoon in the bin

Figure: The owning API does not attach buffers to the owner (stream), but the user is responsible for returning them to prevent having unuseable resources (leaks).

Examples

There are more examples in the vidi-examples crate.