dioxus_cameras/lib.rs
1//! Dioxus integration for the [`cameras`] crate.
2//!
3//! This crate owns only the Dioxus-specific glue, the HTTP preview server,
4//! the [`Registry`] backing it, the `<canvas>`-side WebGL2 renderer, and the
5//! hooks consumers plug into their components. Every other primitive
6//! (single-frame capture, pause/resume pump, source abstraction) lives
7//! upstream in [`cameras`] itself so non-Dioxus callers can use it too.
8//!
9//! # What's here
10//!
11//! - [`PreviewServer`] + [`start_preview_server`] + [`register_with`], a
12//! loopback HTTP server that publishes the latest [`Frame`](cameras::Frame)
13//! for each stream id over `/preview/{id}.bin`. The listener thread is torn
14//! down when the last [`PreviewServer`] clone drops.
15//! - [`Registry`] + [`LatestFrame`], shared map of stream id → latest frame.
16//! The server reads from it; pumps publish to it. Cleaned up automatically
17//! when the owning component unmounts.
18//! - [`use_camera_stream`], high-level hook returning [`UseCameraStream`]:
19//! a status signal, an active/paused toggle, and a single-frame `capture_frame`
20//! callback. Wraps [`cameras::pump`] under the hood.
21//! - [`use_devices`] / [`use_streams`], hooks for the camera list and
22//! multi-stream id management.
23//! - [`PreviewScript`] + [`StreamPreview`], components that render live
24//! frames into a `<canvas>` via WebGL2 (NV12, BGRA, or RGBA shaders).
25//!
26//! # Wiring a Dioxus app
27//!
28//! ```no_run
29//! use dioxus_cameras::cameras::{self, CameraSource, PixelFormat, Resolution, StreamConfig};
30//! use dioxus::prelude::*;
31//! use dioxus_cameras::{PreviewScript, StreamPreview, register_with, start_preview_server, use_camera_stream};
32//!
33//! fn main() {
34//! let server = start_preview_server().expect("preview server");
35//! register_with(&server, dioxus::LaunchBuilder::desktop()).launch(app);
36//! }
37//!
38//! fn app() -> Element {
39//! let source = use_signal::<Option<CameraSource>>(|| None);
40//! let config = StreamConfig {
41//! resolution: Resolution { width: 1280, height: 720 },
42//! framerate: 30,
43//! pixel_format: PixelFormat::Bgra8,
44//! };
45//! let stream = use_camera_stream(0, source, config);
46//! rsx! {
47//! StreamPreview { id: 0 }
48//! p { "{stream.status}" }
49//! button {
50//! onclick: move |_| stream.active.clone().set(!*stream.active.read()),
51//! "Toggle preview"
52//! }
53//! button {
54//! onclick: move |_| { let _ = stream.capture_frame.call(()); },
55//! "Take picture"
56//! }
57//! PreviewScript {}
58//! }
59//! }
60//! ```
61
62#![warn(missing_docs)]
63
64pub use cameras;
65
66mod camera_stream;
67mod channel;
68mod component;
69mod devices;
70mod poison;
71mod registry;
72mod server;
73mod streams;
74
75#[cfg(all(feature = "discover", any(target_os = "macos", target_os = "windows")))]
76mod discover;
77
78pub use camera_stream::{StreamStatus, UseCameraStream, use_camera_stream};
79pub use component::{PreviewScript, StreamPreview};
80pub use devices::{UseDevices, use_devices};
81pub use registry::{LatestFrame, Registry, get_or_create_sink, publish_frame, remove_sink};
82pub use server::{PreviewServer, register_with, start_preview_server};
83pub use streams::{UseStreams, use_streams};
84
85#[cfg(all(feature = "discover", any(target_os = "macos", target_os = "windows")))]
86#[cfg_attr(
87 docsrs,
88 doc(cfg(all(feature = "discover", any(target_os = "macos", target_os = "windows"))))
89)]
90pub use discover::{UseDiscovery, use_discovery};
91
92/// The JavaScript blob that drives the WebGL2 preview renderer.
93///
94/// Usually you want the [`PreviewScript`] component instead, it injects this
95/// blob into a `<script>` tag with the right attributes. This raw constant is
96/// exposed for users rendering outside a Dioxus component (for example, in a
97/// custom server-rendered template).
98///
99/// The script scans the DOM for `canvas[data-stream-id]` elements and binds
100/// each one to the URL in its `data-preview-url` attribute. The
101/// [`StreamPreview`] component emits canvases that match this contract.
102pub const PREVIEW_JS: &str = include_str!("../assets/preview.js");