dioxus-cameras 0.1.3

Dioxus integration for the cameras crate. Provides a preview server, frame registry, camera pump, a use_camera_stream hook, and a StreamPreview component for rendering live camera frames inside a Dioxus desktop app via WebGL2.
docs.rs failed to build dioxus-cameras-0.1.3
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.
Visit the last successful build: dioxus-cameras-0.3.1

dioxus-cameras is the Dioxus integration for cameras, a cross-platform camera library for Rust. It owns the glue between a cameras::Camera and a <canvas> element: a loopback HTTP preview server, a WebGL2 renderer, a Registry that shares frames between the camera pump and the webview, and a handful of hooks that expose the stream lifecycle as Dioxus signals.

Every generic primitive (pause/resume pump, single-frame capture, unified CameraSource) lives upstream in cameras itself and is re-exported as dioxus_cameras::cameras, so non-Dioxus callers can use those primitives directly and Dioxus callers only need a single dependency.

Quick Start

[dependencies]
dioxus = { version = "0.7", features = ["desktop"] }
dioxus-cameras = "0.1"
use dioxus_cameras::cameras::{self, CameraSource, PixelFormat, Resolution, StreamConfig};
use dioxus::prelude::*;
use dioxus_cameras::{
    PreviewScript, StreamPreview, register_with, start_preview_server, use_camera_stream,
};

fn main() {
    let server = start_preview_server().expect("preview server");
    register_with(&server, dioxus::LaunchBuilder::desktop()).launch(App);
}

fn App() -> Element {
    let source = use_signal::<Option<CameraSource>>(|| None);
    let config = StreamConfig {
        resolution: Resolution { width: 1280, height: 720 },
        framerate: 30,
        pixel_format: PixelFormat::Bgra8,
    };
    let stream = use_camera_stream(0, source, config);

    rsx! {
        StreamPreview { id: 0 }
        p { "{stream.status}" }
        button {
            onclick: move |_| stream.active.clone().set(!*stream.active.read()),
            "Toggle preview"
        }
        button {
            onclick: move |_| { let _ = stream.capture_frame.call(()); },
            "Take picture"
        }
        PreviewScript {}
    }
}

register_with injects the preview server's Registry and port into the Dioxus context so every StreamPreview and use_camera_stream call downstream can find them.

What's in the box

Hooks

Hook Returns Purpose
use_camera_stream(id, source, config) UseCameraStream { status, active, capture_frame } Opens the camera, runs the pump, publishes frames to the preview, surfaces lifecycle as signals.
use_devices() UseDevices { devices, ready, refresh } Keeps a Signal<Vec<Device>> populated off a worker thread; refresh on demand.
use_streams() UseStreams { ids, add, remove } Manages a dynamic list of stream ids for multi-stream apps; monotonic, safe as Dioxus keys.

All returned handles are Copy + Clone + PartialEq data structs with public fields (no methods, no hidden state).

Components

Component Purpose
StreamPreview { id } A <canvas> bound to the preview server's /preview/{id}.bin URL; WebGL2-renders the live stream.
PreviewScript {} Injects the WebGL2 driver script once per page. Render it as the last child of your root.

Helpers

Function Purpose
start_preview_server() Binds a loopback HTTP server on an ephemeral port; returns a PreviewServer.
register_with(&server, launch) Injects registry + port + keep-alive into a LaunchBuilder.
get_or_create_sink(&registry, id) Returns the LatestFrame slot for id; used when running your own pump.
remove_sink(&registry, id) Drops the slot for id. Normally handled automatically on unmount.
publish_frame(&sink, frame) Writes a frame into a LatestFrame; used when running your own pump.

Live preview + take-picture

The hook returns both operations on one handle.

let stream = use_camera_stream(id, source, config);

// Pause the pump while the user is on another tab (no per-frame Rust work;
// camera stays open so capture stays fast):
stream.active.clone().set(false);

// Grab a fresh frame whether streaming or paused:
if let Some(frame) = stream.capture_frame.call(()) {
    // save, toast, upload, etc.
}

// Resume streaming:
stream.active.clone().set(true);

capture_frame is sync-blocking on the calling thread until the pump worker replies (typically one frame interval, plus up to 20ms of wake latency if paused). That's fine from an onclick; for rapid back-to-back captures, dispatch from a std::thread::spawn'd worker or a Dioxus spawn task.

Versioning

dioxus-cameras pins a specific minor version of cameras via pub use cameras;, so installing dioxus-cameras = "0.1" gives you a compatible cameras automatically.

Features

Feature Default Description
rtsp off Forwards to cameras/rtsp; enables CameraSource::Rtsp on macOS and Windows.

Enable with dioxus-cameras = { version = "0.1", features = ["rtsp"] }.

Source separation

The crate deliberately splits responsibilities:

  • cameras owns the camera-side primitives: Camera, CameraSource, pump::Pump, etc. No Dioxus dependency.
  • dioxus-cameras owns the UI-side glue: the preview server, Registry, hooks, and components. Depends on dioxus and cameras.

If you're integrating cameras into a non-Dioxus app (a CLI, a Tauri shell, a custom renderer), you do not need this crate. Use cameras::pump directly for the pause + snapshot pattern.

Example

A runnable example lives at apps/dioxus-demo in the repository: multi-stream grid, per-cell USB or RTSP source, live-preview toggle, take-picture button, add/remove streams, device refresh.

Dependency surface

  • dioxus 0.7 with desktop feature
  • cameras 0.1
  • futures-timer 3 (runtime-agnostic timer; keeps the crate from pinning tokio)
  • bytes 1

License

Licensed under either of

at your option.