#[non_exhaustive]#[repr(u32)]pub enum PixelFormat {
Rgb = 1,
Rgba = 2,
Bgra = 3,
Grey = 4,
Yuyv = 5,
Vyuy = 6,
Nv12 = 7,
Nv16 = 8,
PlanarRgb = 9,
PlanarRgba = 10,
Nv24 = 11,
}Expand description
Pixel format identifier.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Rgb = 1
Packed RGB [H, W, 3]
Rgba = 2
Packed RGBA [H, W, 4]
Bgra = 3
Packed BGRA [H, W, 4]
Grey = 4
Grayscale [H, W, 1]
Yuyv = 5
Packed YUV 4:2:2, YUYV byte order [H, W, 2]
Vyuy = 6
Packed YUV 4:2:2, VYUY byte order [H, W, 2]
Nv12 = 7
Semi-planar YUV 4:2:0 [H*3/2, W] or multiplane [H, W] + [H/2, W]
Nv16 = 8
Semi-planar YUV 4:2:2 [H*2, W] or multiplane [H, W] + [H, W]
PlanarRgb = 9
Planar RGB, channels-first [3, H, W]
PlanarRgba = 10
Planar RGBA, channels-first [4, H, W]
Nv24 = 11
Semi-planar YUV 4:4:4, contiguous shape [H*3, W]. Full-resolution
chroma: Y plane (H rows of W bytes) + interleaved Cb/Cr plane (H image
rows of W pairs = 2W bytes/row, laid out as 2H rows of W) → 3H rows
total. Multiplane NV24 is not yet supported (see from_planes). Added
last to keep the existing discriminants (and any serialized values)
stable.
Implementations§
Source§impl PixelFormat
impl PixelFormat
Sourcepub const fn code(self) -> u32
pub const fn code(self) -> u32
The shared code for this variant. Identical on every surface.
const, deliberately: a downstream binding that cannot
write Variant = OtherEnum::Variant.code() in a #[pyclass]
discriminant position (PyO3 requires a literal there) can
still pin that literal to this value with a
const _: () = assert!(...) – a build-time check instead
of a hand-synced comment. See PyTensorMemory/PyPixelFormat
in crates/python-common/src/tensor.rs for the consumer.
Sourcepub fn from_code(code: u32) -> Option<Self>
pub fn from_code(code: u32) -> Option<Self>
Reject an unknown code rather than guessing at one.
Sourcepub fn from_str_code(s: &str) -> Option<Self>
pub fn from_str_code(s: &str) -> Option<Self>
Reject an unknown string rather than guessing at one.
Source§impl PixelFormat
impl PixelFormat
Sourcepub const fn channels(&self) -> usize
pub const fn channels(&self) -> usize
Returns the number of channels for this pixel format.
For semi-planar formats (NV12, NV16), this returns 1 (the luma channel count for the primary plane). For packed formats, this is the total number of interleaved components per pixel.
Sourcepub const fn layout(&self) -> PixelLayout
pub const fn layout(&self) -> PixelLayout
Returns the memory layout category for this pixel format.
Sourcepub fn allocation_shape(
&self,
width: usize,
height: usize,
) -> Option<Vec<usize>>
pub fn allocation_shape( &self, width: usize, height: usize, ) -> Option<Vec<usize>>
The allocation geometry for this format at width×height, or
None if the dimensions are invalid for the format, or the format is
an unsupported semi-planar variant (any SemiPlanar variant other than
Nv12, Nv16, and Nv24).
This is the shape that sizes a buffer. For a subsampled format it is
deliberately not the shape a consumer indexes with — NV12 640×480
allocates [720, 640] here but addresses a [480, 640] luma grid.
Use addressing_shape for the latter, which
is what descriptors, blobs and Tensor.msg carry.
Renamed from image_shape when the two meanings were separated: every
caller of the old name sized an allocation with it (Tensor::image,
import_image, and the two PBO helpers), so a single name called “the
shape” made picking the wrong one the default. There is now no such
name.
Odd dimensions are fully supported. The combined-plane height for NV12
is height + ceil(height / 2) (luma rows + chroma rows), which equals
the classic height * 3 / 2 for even heights and stays exact for odd
ones — e.g. 483 → 725 rows (483 luma + 242 chroma).
For semi-planar formats the shape carries the logical width as-is
(odd widths are preserved, e.g. [720, 789] for a 789×384 NV12).
The row stride recorded separately on the tensor is >= even(width) and
64-byte aligned; it may exceed the logical width. Use
effective_row_stride() to determine the true byte pitch for
mapping and allocation. Allocation byte size = total_h * row_stride,
NOT the shape product.
Sourcepub fn addressing_shape(
&self,
width: usize,
height: usize,
) -> Option<Vec<usize>>
pub fn addressing_shape( &self, width: usize, height: usize, ) -> Option<Vec<usize>>
The addressing grid: how a consumer logically indexes this image.
This is the shape that belongs in a descriptor, a blob, or a
Tensor.msg — never the allocation size. For a subsampled format
product(addressing_shape) * dtype_size is smaller than the buffer:
NV12 640×480 addresses a 640×480 luma grid inside a 460 800-byte
allocation. Buffer extent comes from the plane table, never from here.
Contrast allocation_shape, which is the
buffer geometry every allocating caller must keep using.
The per-format convention is pinned here so producers cannot each
invent one; it matches the merged schemas golden fixtures.
Sourcepub fn plane_table(
&self,
width: usize,
height: usize,
row_stride: usize,
) -> Option<Vec<PlaneGeometry>>
pub fn plane_table( &self, width: usize, height: usize, row_stride: usize, ) -> Option<Vec<PlaneGeometry>>
Where each plane’s bytes live, given the allocation’s row pitch.
row_stride is the byte pitch of a luma/packed row — the value
Tensor::effective_row_stride
reports, which on a DMA backing is 64-byte aligned and may exceed
width * bytes_per_pixel. Planes are laid out contiguously in the
order a consumer expects them (Y then UV; R then G then B).
Returns None for an unsupported semi-planar variant, or if the
geometry overflows u64 — dimensions reaching this from an imported
descriptor are untrusted, and a wrapped size would look small enough
to pass a capacity check it should fail.
Chroma extent is derived from
combined_plane_height rather than
recomputed, so the two cannot drift on odd heights.
Sourcepub const fn combined_plane_height(&self, height: usize) -> Option<usize>
pub const fn combined_plane_height(&self, height: usize) -> Option<usize>
Combined-plane height in physical (stride-wide) rows for a semi-planar format: the Y rows plus the interleaved-UV rows.
- NV12 (4:2:0):
H + ceil(H/2)— exact for odd heights (e.g. 483 → 725 = 483 luma + 242 chroma), equals the classicH*3/2for even. - NV16 (4:2:2):
2H(one full-height chroma row per luma row). - NV24 (4:4:4):
3H(a full-width2W-byte chroma line spans two stride-wide buffer rows, so2Hchroma rows).
Returns None for non-semi-planar formats (and unsupported SemiPlanar
variants). This is the single source of truth for the vertical extent of
the contiguous NV* buffer — allocation_shape, the GL
DMA-BUF/IOSurface imports, the PBO allocator, and the gpu-probe all
derive from it, so the combined-plane height can never drift between them.
Sourcepub fn image_height_from_combined(&self, combined: usize) -> Option<usize>
pub fn image_height_from_combined(&self, combined: usize) -> Option<usize>
The image height whose combined plane height is combined, or None
when no image height produces it (721 for NV12, say) and for every
non-semi-planar format.
The inverse of combined_plane_height,
and verified against it before returning: the forward map is not
surjective, so a shape carrying a combined height nothing produced must
be rejected rather than rounded to a nearby image height.
crate::image_dims_from_shape uses it to recover the logical height
from a semi-planar allocation shape.
Sourcepub const fn chroma_layout(&self) -> Option<ChromaLayout>
pub const fn chroma_layout(&self) -> Option<ChromaLayout>
Per-format semi-planar chroma addressing parameters, shared by the codec
writer (uv_rows_per_luma), the CPU
readers, and both GL shaders so the combined-plane chroma geometry has a
single source of truth. Returns None for non-semi-planar formats.
Sourcepub fn semi_planar_surface_dims(
&self,
width: usize,
height: usize,
bpe: usize,
) -> Option<(usize, usize)>
pub fn semi_planar_surface_dims( &self, width: usize, height: usize, bpe: usize, ) -> Option<(usize, usize)>
Physical GPU-surface dimensions (pitch_width, total_h) in texels for a
semi-planar combined plane bound as one bpe-byte-per-element texture,
or None for non-semi-planar formats.
The width is rounded up to the 64-aligned row pitch (== bytes_per_row)
rather than left at the even logical width. ANGLE (and tiled GPUs in
general) will not address texels beyond a surface’s declared width via
texelFetch, so a surface narrower than its padded bytes_per_row
leaves the padding columns unreachable. That is fatal for NV24 (4:4:4):
its chroma line is 2*W interleaved bytes, which spills past the even
width into those padding columns whenever the row is padded
(bytes_per_row > even_width). Making the surface width equal the pitch
keeps every byte addressable and costs nothing — bytes_per_row is
already this value.
Single source of truth for both IOSurface allocators (the tensor crate’s
IoSurfaceTensor::new_image and the image crate’s ImageLayout), so
they cannot diverge.
Sourcepub const fn is_rgb_or_hsv(&self) -> bool
pub const fn is_rgb_or_hsv(&self) -> bool
Returns true if this is an RGB or HSV pixel format.
This is the is_rgb_or_hsv input of the kernel’s
V4L2_MAP_QUANTIZATION_DEFAULT() macro, which
Colorimetry::from_v4l2 takes to
resolve a DEFAULT quantization: these formats default to full range.
Rgb, Rgba, Bgra, PlanarRgb and PlanarRgba return true.
The YUV formats and Grey return false; the kernel lists greyscale
as a YUV encoding. PixelFormat has no Bayer or HSV formats, which a
V4L2 classifier by fourcc also counts as RGB.
use edgefirst_tensor::PixelFormat;
assert!(PixelFormat::Rgb.is_rgb_or_hsv());
assert!(!PixelFormat::Yuyv.is_rgb_or_hsv());
assert!(!PixelFormat::Grey.is_rgb_or_hsv());Sourcepub const fn to_fourcc(&self) -> u32
pub const fn to_fourcc(&self) -> u32
Returns the V4L2 pixel format code (V4L2_PIX_FMT_*) for this
format, or 0 for formats that have no V4L2 code (e.g., PlanarRgb).
The codes for the four-channel and YUV formats coincide with the DRM
FourCC for the same memory layout; Rgb (RGB3) and Grey (GREY)
are V4L2-only spellings. This is not the PixelFormat::as_str wire
name, nor the Display text.
Sourcepub const fn from_fourcc(fourcc: u32) -> Option<Self>
pub const fn from_fourcc(fourcc: u32) -> Option<Self>
Converts a V4L2 pixel format code (see Self::to_fourcc) to a
PixelFormat, returning None for unrecognized or zero codes.
Trait Implementations§
Source§impl Clone for PixelFormat
impl Clone for PixelFormat
impl Copy for PixelFormat
Source§impl Debug for PixelFormat
impl Debug for PixelFormat
Source§impl<'de> Deserialize<'de> for PixelFormat
impl<'de> Deserialize<'de> for PixelFormat
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl Display for PixelFormat
Human-readable name for messages and logs. Neither the wire name
(PixelFormat::as_str) nor the V4L2 code (PixelFormat::to_fourcc).
impl Display for PixelFormat
Human-readable name for messages and logs. Neither the wire name
(PixelFormat::as_str) nor the V4L2 code (PixelFormat::to_fourcc).
impl Eq for PixelFormat
Source§impl Hash for PixelFormat
impl Hash for PixelFormat
Source§impl PartialEq for PixelFormat
impl PartialEq for PixelFormat
Source§impl Serialize for PixelFormat
impl Serialize for PixelFormat
impl StructuralPartialEq for PixelFormat
Auto Trait Implementations§
impl Freeze for PixelFormat
impl RefUnwindSafe for PixelFormat
impl Send for PixelFormat
impl Sync for PixelFormat
impl Unpin for PixelFormat
impl UnsafeUnpin for PixelFormat
impl UnwindSafe for PixelFormat
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more