mediaframe/source/
gbrapf16.rs1use crate::{
14 PixelSink, SourceFormat,
15 frame::{Gbrapf16Frame, Gbrapf16LeFrame},
16 source::sealed::Sealed,
17};
18
19#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
22pub struct Gbrapf16<const BE: bool = false>;
23
24impl<const BE: bool> Sealed for Gbrapf16<BE> {}
25impl<const BE: bool> SourceFormat for Gbrapf16<BE> {}
26
27#[derive(Debug, Clone, Copy)]
31pub struct Gbrapf16Row<'a> {
32 g: &'a [half::f16],
33 b: &'a [half::f16],
34 r: &'a [half::f16],
35 a: &'a [half::f16],
36 row: usize,
37}
38
39impl<'a> Gbrapf16Row<'a> {
40 #[cfg_attr(not(tarpaulin), inline(always))]
41 pub(crate) fn new(
42 g: &'a [half::f16],
43 b: &'a [half::f16],
44 r: &'a [half::f16],
45 a: &'a [half::f16],
46 row: usize,
47 ) -> Self {
48 Self { g, b, r, a, row }
49 }
50
51 #[cfg_attr(not(tarpaulin), inline(always))]
53 pub fn g(&self) -> &'a [half::f16] {
54 self.g
55 }
56 #[cfg_attr(not(tarpaulin), inline(always))]
58 pub fn b(&self) -> &'a [half::f16] {
59 self.b
60 }
61 #[cfg_attr(not(tarpaulin), inline(always))]
63 pub fn r(&self) -> &'a [half::f16] {
64 self.r
65 }
66 #[cfg_attr(not(tarpaulin), inline(always))]
68 pub fn a(&self) -> &'a [half::f16] {
69 self.a
70 }
71 #[cfg_attr(not(tarpaulin), inline(always))]
73 pub const fn row(&self) -> usize {
74 self.row
75 }
76}
77
78pub trait Gbrapf16Sink<const BE: bool = false>:
81 for<'a> PixelSink<Input<'a> = Gbrapf16Row<'a>>
82{
83}
84
85pub fn gbrapf16_to_endian<S, const BE: bool>(
90 src: &Gbrapf16Frame<'_, BE>,
91 sink: &mut S,
92) -> Result<(), S::Error>
93where
94 S: Gbrapf16Sink<BE>,
95{
96 sink.begin_frame(src.width(), src.height())?;
97
98 let w = src.width() as usize;
99 let h = src.height() as usize;
100 let g_plane = src.g();
101 let b_plane = src.b();
102 let r_plane = src.r();
103 let a_plane = src.a();
104 let g_stride = src.g_stride() as usize;
105 let b_stride = src.b_stride() as usize;
106 let r_stride = src.r_stride() as usize;
107 let a_stride = src.a_stride() as usize;
108
109 for row in 0..h {
110 let g = &g_plane[row * g_stride..row * g_stride + w];
111 let b = &b_plane[row * b_stride..row * b_stride + w];
112 let r = &r_plane[row * r_stride..row * r_stride + w];
113 let a = &a_plane[row * a_stride..row * a_stride + w];
114 sink.process(Gbrapf16Row::new(g, b, r, a, row))?;
115 }
116 Ok(())
117}
118
119#[cfg_attr(not(tarpaulin), inline(always))]
129pub fn gbrapf16_to<S>(src: &Gbrapf16LeFrame<'_>, sink: &mut S) -> Result<(), S::Error>
130where
131 S: Gbrapf16Sink<false>,
132{
133 gbrapf16_to_endian::<S, false>(src, sink)
134}
135
136#[cfg(all(test, feature = "std"))]
137mod tests {
138 use super::*;
139 use crate::PixelSink;
140 use core::convert::Infallible;
141
142 struct CountingSink {
143 rows_seen: usize,
144 last_a_len: usize,
145 last_row_idx: usize,
146 }
147
148 impl PixelSink for CountingSink {
149 type Input<'r> = Gbrapf16Row<'r>;
150 type Error = Infallible;
151 fn begin_frame(&mut self, _w: u32, _h: u32) -> Result<(), Infallible> {
152 Ok(())
153 }
154 fn process(&mut self, row: Gbrapf16Row<'_>) -> Result<(), Infallible> {
155 self.rows_seen += 1;
156 self.last_a_len = row.a().len();
157 self.last_row_idx = row.row();
158 Ok(())
159 }
160 }
161
162 impl Gbrapf16Sink for CountingSink {}
163
164 #[test]
168 fn gbrapf16_to_explicit_turbofish_one_generic_compiles() {
169 #[allow(clippy::type_complexity)]
170 fn _check<S: Gbrapf16Sink>() {
171 let _: fn(&Gbrapf16LeFrame<'_>, &mut S) -> Result<(), S::Error> = gbrapf16_to::<S>;
172 }
173 }
174
175 #[test]
176 fn gbrapf16_walker_visits_every_row_once() {
177 let buf = std::vec![half::f16::ONE; 4 * 4];
178 let frame = Gbrapf16LeFrame::try_new(&buf, &buf, &buf, &buf, 4, 4, 4, 4, 4, 4).unwrap();
179 let mut sink = CountingSink {
180 rows_seen: 0,
181 last_a_len: 0,
182 last_row_idx: 0,
183 };
184 gbrapf16_to(&frame, &mut sink).unwrap();
185 assert_eq!(sink.rows_seen, 4);
186 assert_eq!(sink.last_a_len, 4);
187 assert_eq!(sink.last_row_idx, 3);
188 }
189}