Skip to main content

edgefirst_codec/
lib.rs

1// SPDX-FileCopyrightText: Copyright 2026 Au-Zone Technologies
2// SPDX-License-Identifier: Apache-2.0
3
4//! Image codec for decoding JPEG/PNG into pre-allocated EdgeFirst tensors,
5//! and hardware video encoding in [`video`].
6//!
7//! This crate provides the [`ImageDecoder`] struct and [`ImageLoad`] extension
8//! trait for decoding image files directly into existing tensor buffers —
9//! including DMA-BUF tensors with GPU-aligned pitch padding. The core design
10//! goal is **allocate once, decode many**: users create a tensor at the maximum
11//! expected image size during program initialisation, then call
12//! [`ImageLoad::load_image`] in the hot loop with zero per-frame allocations.
13//!
14//! # Quick Start
15//!
16//! ```rust,no_run
17//! use edgefirst_codec::{ImageDecoder, ImageLoad};
18//! use edgefirst_tensor::{CpuAccess, Tensor, TensorTrait, TensorMemory, PixelFormat};
19//!
20//! // Allocate once (at init), sized for the largest expected image. The
21//! // decoder CPU-writes the pixels: declare `CpuAccess::Write`.
22//! let mut tensor = Tensor::<u8>::image(1920, 1080, PixelFormat::Nv12, Some(TensorMemory::Mem),
23//!                                       CpuAccess::Write)
24//!     .expect("allocation");
25//! let mut decoder = ImageDecoder::new();
26//!
27//! // Decode many (in hot loop). The decoder sets the tensor's dimensions and
28//! // native format (JPEG → Nv12/Grey); call `convert()` for RGB.
29//! let jpeg_bytes = std::fs::read("frame.jpg").unwrap();
30//! let info = tensor.load_image(&mut decoder, &jpeg_bytes).expect("decode");
31//! assert!(info.width <= 1920);
32//! assert!(info.height <= 1080);
33//! ```
34//!
35//! # Performance
36//!
37//! For best performance, allocate tensors via
38//! [`ImageProcessor::create_image()`](https://docs.rs/edgefirst-image/latest/edgefirst_image/struct.ImageProcessor.html#method.create_image)
39//! which selects the optimal memory backend (DMA → PBO → Mem) with
40//! GPU-aligned pitch. Free-standing tensors work but cannot use PBO
41//! and may not have aligned pitch.
42//!
43//! # Strided Buffers
44//!
45//! The decoder respects `effective_row_stride()` on the destination tensor.
46//! When a DMA tensor has GPU-aligned pitch padding, decoded pixel rows are
47//! written at the correct stride offsets — no intermediate contiguous buffer
48//! is exposed to the caller.
49
50mod decoder;
51mod error;
52mod exif;
53mod jpeg;
54mod options;
55mod pixel;
56#[cfg(feature = "png")]
57mod png;
58#[cfg(test)]
59mod test_support;
60mod traits;
61pub mod video;
62
63pub use decoder::{peek_info, ChromaUpsample, DctMethod, ImageDecoder};
64pub use error::{CodecError, UnsupportedFeature};
65pub use options::ImageInfo;
66pub use pixel::ImagePixel;
67pub use traits::ImageLoad;
68
69/// Returns `true` when the nvJPEG GPU JPEG decoder is available at runtime —
70/// Linux with CUDA + libnvjpeg loaded **and** opted in via
71/// `EDGEFIRST_ENABLE_NVJPEG` (off by default, so it never silently contends with
72/// CUDA inference). When `true` the codec prefers it over the V4L2/CPU backends
73/// for CUDA-backed destinations. Always `false` on other platforms or when the
74/// `nvjpeg` feature is disabled. Useful for benchmarks and consumers that branch
75/// on backend availability.
76pub fn nvjpeg_available() -> bool {
77    #[cfg(all(target_os = "linux", feature = "nvjpeg"))]
78    {
79        jpeg::nvjpeg_available()
80    }
81    #[cfg(not(all(target_os = "linux", feature = "nvjpeg")))]
82    {
83        false
84    }
85}
86
87/// Returns `true` when a V4L2 memory-to-memory JPEG decoder (e.g. the i.MX
88/// mxc-jpeg block) is present and not opted out via `EDGEFIRST_DISABLE_V4L2`.
89/// Opens and drops the device once; the decode path re-probes lazily and
90/// keeps its own context. Always `false` on other platforms or when the
91/// `v4l2` feature is disabled. Useful for benchmarks and consumers that must
92/// fail fast instead of silently falling back to the CPU decoder.
93pub fn v4l2_available() -> bool {
94    #[cfg(all(target_os = "linux", feature = "v4l2"))]
95    {
96        jpeg::v4l2_available()
97    }
98    #[cfg(not(all(target_os = "linux", feature = "v4l2")))]
99    {
100        false
101    }
102}
103
104/// Result type for codec operations.
105pub type Result<T> = std::result::Result<T, CodecError>;