Skip to main content

denise_video/
lib.rs

1//! Hardware video decode onto a DRM plane.
2//!
3//! A kiosk playing a promo loop is a set-top box with a different sticker, and
4//! this crate does what a set-top box does: compressed bytes go to the SoC's
5//! decoder over V4L2 memory-to-memory, decoded frames come back as dmabufs,
6//! and each dmabuf is imported as a DRM framebuffer and flipped onto a video
7//! **plane** the display controller composites during scanout. The frame never
8//! passes through `denise-render` at all; the UI keeps painting its own buffer
9//! and the plane sits in the stack with it. Zero copies end to end, no ffmpeg,
10//! no GStreamer, no C library — the same single-static-binary discipline as
11//! `denise-drm`.
12//!
13//! # The format menu
14//!
15//! Two elementary streams, chosen so **every Raspberry Pi hardware-plays at
16//! least one**: H.264 (Constrained Baseline/Main, Annex-B, `.h264`) for Pi
17//! Zero through 4 and most other embedded SoCs, and HEVC (Main, `.h265`) for
18//! Pi 4 and 5. Both yuv420, at most 1080p30. The board picks:
19//! [`Decoders::detect`] asks the hardware, [`Decoders::pick`] applies the
20//! rule, and a kiosk ships both files — two ffmpeg lines at build time
21//! instead of one.
22//!
23//! No container, no demuxer, no seeking: play, loop and stop, which is what a
24//! promo loop is. Audio is a different subsystem and deliberately absent.
25//!
26//! # What runs where
27//!
28//! Everything that talks to `/dev` is Linux-only and `cfg`-gated to nothing
29//! elsewhere. The Annex-B access-unit logic in [`annexb`] is pure and
30//! compiled — and tested — everywhere.
31//!
32//! # Status
33//!
34//! The **stateful** decode path (H.264 via `bcm2835-codec` on the Pi, and its
35//! equivalents on i.MX, Rockchip and Amlogic), verified end to end on a Pi 3A+:
36//! access units in, dmabuf out, imported as a DRM framebuffer and flipped onto
37//! a plane at a paced 29.5 fps over a live UI surface.
38//!
39//! The **stateless** HEVC path for `rpivid` — what the Pi 5 needs, and an order
40//! of magnitude more work: slice parsing, reference management, the media
41//! request API — is [#36](https://github.com/bisand/denise/issues/36).
42//! [`Decoders::detect`] already reports it where the hardware offers it, so a
43//! board with `rpivid` and no `bcm2835-codec` will say so and then decline to
44//! play, which is the honest answer until #36 lands.
45
46// Off Linux, some of the items the documentation above links to are compiled
47// out, so those links resolve to nothing and `cargo doc` fails. CI documents on
48// Ubuntu and never sees it; a developer on a Mac cannot avoid it. Linux stays
49// the platform that checks these links, being the one with the items to check
50// them against.
51#![cfg_attr(not(target_os = "linux"), allow(rustdoc::broken_intra_doc_links))]
52
53pub mod annexb;
54
55#[cfg(target_os = "linux")]
56mod decode;
57#[cfg(target_os = "linux")]
58mod detect;
59#[cfg(target_os = "linux")]
60mod error;
61#[cfg(target_os = "linux")]
62mod plane;
63#[cfg(target_os = "linux")]
64mod player;
65/// The raw uapi layer. Hidden rather than private so the probe example can
66/// narrate each enumeration step — a board where detection fails needs the
67/// errno, not a shrug.
68#[cfg(target_os = "linux")]
69#[doc(hidden)]
70pub mod v4l2;
71
72#[cfg(target_os = "linux")]
73pub use decode::{DecodedFrame, Decoder};
74#[cfg(target_os = "linux")]
75pub use detect::{Asset, DecoderInfo, Decoders};
76#[cfg(target_os = "linux")]
77pub use error::VideoError;
78#[cfg(target_os = "linux")]
79pub use plane::VideoPlane;
80#[cfg(target_os = "linux")]
81pub use player::Player;
82
83/// Compiles the examples in this crate's README, so they cannot drift from the
84/// API they claim to demonstrate. Never built except under `cargo test --doc`.
85#[cfg(doctest)]
86#[doc = include_str!("../README.md")]
87struct Readme;