mediaframe/source/
gbrapf32.rs1use crate::{
14 PixelSink, SourceFormat,
15 frame::{Gbrapf32Frame, Gbrapf32LeFrame},
16 source::sealed::Sealed,
17};
18
19#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
22pub struct Gbrapf32<const BE: bool = false>;
23
24impl<const BE: bool> Sealed for Gbrapf32<BE> {}
25impl<const BE: bool> SourceFormat for Gbrapf32<BE> {}
26
27#[derive(Debug, Clone, Copy)]
31pub struct Gbrapf32Row<'a> {
32 g: &'a [f32],
33 b: &'a [f32],
34 r: &'a [f32],
35 a: &'a [f32],
36 row: usize,
37}
38
39impl<'a> Gbrapf32Row<'a> {
40 #[cfg_attr(not(tarpaulin), inline(always))]
41 pub(crate) fn new(g: &'a [f32], b: &'a [f32], r: &'a [f32], a: &'a [f32], row: usize) -> Self {
42 Self { g, b, r, a, row }
43 }
44
45 #[cfg_attr(not(tarpaulin), inline(always))]
47 pub fn g(&self) -> &'a [f32] {
48 self.g
49 }
50 #[cfg_attr(not(tarpaulin), inline(always))]
52 pub fn b(&self) -> &'a [f32] {
53 self.b
54 }
55 #[cfg_attr(not(tarpaulin), inline(always))]
57 pub fn r(&self) -> &'a [f32] {
58 self.r
59 }
60 #[cfg_attr(not(tarpaulin), inline(always))]
62 pub fn a(&self) -> &'a [f32] {
63 self.a
64 }
65 #[cfg_attr(not(tarpaulin), inline(always))]
67 pub const fn row(&self) -> usize {
68 self.row
69 }
70}
71
72pub trait Gbrapf32Sink<const BE: bool = false>:
75 for<'a> PixelSink<Input<'a> = Gbrapf32Row<'a>>
76{
77}
78
79pub fn gbrapf32_to_endian<S, const BE: bool>(
84 src: &Gbrapf32Frame<'_, BE>,
85 sink: &mut S,
86) -> Result<(), S::Error>
87where
88 S: Gbrapf32Sink<BE>,
89{
90 sink.begin_frame(src.width(), src.height())?;
91
92 let w = src.width() as usize;
93 let h = src.height() as usize;
94 let g_plane = src.g();
95 let b_plane = src.b();
96 let r_plane = src.r();
97 let a_plane = src.a();
98 let g_stride = src.g_stride() as usize;
99 let b_stride = src.b_stride() as usize;
100 let r_stride = src.r_stride() as usize;
101 let a_stride = src.a_stride() as usize;
102
103 for row in 0..h {
104 let g = &g_plane[row * g_stride..row * g_stride + w];
105 let b = &b_plane[row * b_stride..row * b_stride + w];
106 let r = &r_plane[row * r_stride..row * r_stride + w];
107 let a = &a_plane[row * a_stride..row * a_stride + w];
108 sink.process(Gbrapf32Row::new(g, b, r, a, row))?;
109 }
110 Ok(())
111}
112
113#[cfg_attr(not(tarpaulin), inline(always))]
123pub fn gbrapf32_to<S>(src: &Gbrapf32LeFrame<'_>, sink: &mut S) -> Result<(), S::Error>
124where
125 S: Gbrapf32Sink<false>,
126{
127 gbrapf32_to_endian::<S, false>(src, sink)
128}
129
130#[cfg(all(test, feature = "std"))]
131mod tests {
132 use super::*;
133 use crate::PixelSink;
134 use core::convert::Infallible;
135
136 struct CountingSink {
137 rows_seen: usize,
138 last_a_len: usize,
139 last_row_idx: usize,
140 }
141
142 impl PixelSink for CountingSink {
143 type Input<'r> = Gbrapf32Row<'r>;
144 type Error = Infallible;
145 fn begin_frame(&mut self, _w: u32, _h: u32) -> Result<(), Infallible> {
146 Ok(())
147 }
148 fn process(&mut self, row: Gbrapf32Row<'_>) -> Result<(), Infallible> {
149 self.rows_seen += 1;
150 self.last_a_len = row.a().len();
151 self.last_row_idx = row.row();
152 Ok(())
153 }
154 }
155
156 impl Gbrapf32Sink for CountingSink {}
157
158 #[test]
162 fn gbrapf32_to_explicit_turbofish_one_generic_compiles() {
163 #[allow(clippy::type_complexity)]
164 fn _check<S: Gbrapf32Sink>() {
165 let _: fn(&Gbrapf32LeFrame<'_>, &mut S) -> Result<(), S::Error> = gbrapf32_to::<S>;
166 }
167 }
168
169 #[test]
170 fn gbrapf32_walker_visits_every_row_once() {
171 let buf = std::vec![1.0f32; 4 * 4];
172 let frame = Gbrapf32LeFrame::try_new(&buf, &buf, &buf, &buf, 4, 4, 4, 4, 4, 4).unwrap();
173 let mut sink = CountingSink {
174 rows_seen: 0,
175 last_a_len: 0,
176 last_row_idx: 0,
177 };
178 gbrapf32_to(&frame, &mut sink).unwrap();
179 assert_eq!(sink.rows_seen, 4);
180 assert_eq!(sink.last_a_len, 4);
181 assert_eq!(sink.last_row_idx, 3);
182 }
183}