Skip to main content

mediaframe/source/
rgba64.rs

1//! Packed RGBA64 source (`AV_PIX_FMT_RGBA64{LE,BE}`) — 16 bits per channel,
2//! `u16` element order `R, G, B, A`. Stride in u16 elements (≥ `4 * width`).
3//!
4//! The marker carries `<const BE: bool = false>`: `Rgba64` (= `Rgba64<false>`)
5//! is the LE source; `Rgba64<true>` is the BE source. The walker
6//! [`rgba64_to::<BE>`] propagates `BE` from [`Rgba64Frame<'_, BE>`] into the
7//! sinker dispatch.
8//!
9//! Outputs (Tier 8 finish):
10//! - `with_rgb`      — drop alpha, narrow each R/G/B channel `>> 8`, pack as R, G, B.
11//! - `with_rgba`     — all four channels narrowed `>> 8`; source alpha passed through.
12//! - `with_rgb_u16`  — drop alpha, native u16 passthrough (R, G, B order).
13//! - `with_rgba_u16` — all four channels passed through as-is; source alpha preserved.
14//! - `with_luma`     — Y′ from R/G/B after narrowing to u8 (alpha ignored).
15//! - `with_luma_u16` — Y′ computed at u8 precision (matching `with_luma`'s
16//!   output) and zero-extended to u16; alpha ignored. Same convention as
17//!   the 8-bit-source family; not native 16-bit luma precision.
18//! - `with_hsv`      — HSV via u8 RGB staging (alpha ignored).
19
20use crate::frame::Rgba64Frame;
21
22walker! {
23  packed_be {
24    /// Zero-sized marker for the packed **RGBA64** source format
25    /// (`AV_PIX_FMT_RGBA64{LE,BE}`). `<const BE: bool>` defaults to `false`
26    /// (LE); the alias `Rgba64` resolves to `Rgba64<false>`.
27    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
28    marker: Rgba64,
29    frame: Rgba64Frame,
30    row: Rgba64Row,
31    sink: Rgba64Sink,
32    walker: rgba64_to,
33    walker_endian: rgba64_to_endian,
34    buf_field: rgba64,
35    elem_type: u16,
36    row_elems: |w| w * 4,
37    row_doc: "One row of an [`Rgba64`] source — `width * 4` u16 elements \
38              (`R, G, B, A` per pixel, each channel 16 bits; alpha is real). \
39              Endianness is recorded on the parent [`Rgba64Frame<'_, BE>`] / \
40              sinker, not on the Row itself.",
41    walker_doc: "Walks an [`Rgba64Frame<'_, BE>`] row by row into the sink. \
42                 Propagates `<const BE: bool>` from the frame into \
43                 [`Rgba64Sink<BE>`].",
44  }
45}
46
47#[cfg(all(test, feature = "std"))]
48mod tests {
49  use super::*;
50  use crate::{PixelSink, color::Matrix, frame::Rgba64Frame};
51  use core::convert::Infallible;
52
53  struct CountingSink {
54    rows_seen: usize,
55    last_width: usize,
56    last_row_idx: usize,
57  }
58  impl PixelSink for CountingSink {
59    type Input<'r> = Rgba64Row<'r>;
60    type Error = Infallible;
61    fn begin_frame(&mut self, _w: u32, _h: u32) -> Result<(), Infallible> {
62      Ok(())
63    }
64    fn process(&mut self, row: Rgba64Row<'_>) -> Result<(), Infallible> {
65      self.rows_seen += 1;
66      self.last_width = row.rgba64().len();
67      self.last_row_idx = row.row();
68      Ok(())
69    }
70  }
71  impl Rgba64Sink for CountingSink {}
72
73  #[test]
74  fn rgba64_walker_visits_every_row_once() {
75    // width=4, stride=16 (4*4), height=4 → plane needs 64 u16 elements
76    let buf = std::vec![0u16; 16 * 4];
77    let frame = Rgba64Frame::new(&buf, 4, 4, 16);
78    let mut sink = CountingSink {
79      rows_seen: 0,
80      last_width: 0,
81      last_row_idx: 0,
82    };
83    rgba64_to(&frame, true, Matrix::Bt709, &mut sink).unwrap();
84    assert_eq!(sink.rows_seen, 4);
85    assert_eq!(sink.last_width, 16); // width * 4 u16 elements per row
86    assert_eq!(sink.last_row_idx, 3);
87  }
88}