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