1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
//! SIMD-dispatched per-row color-conversion kernels for the FFmpeg
//! `AVPixelFormat` space.
//!
//! # Design
//!
//! Every source pixel format has its own kernel (`yuv420p_to`,
//! `nv12_to`, `bgr24_to`, …) that walks the source row by row and hands
//! each row to a caller-supplied [`PixelSink`]. The Sink decides what
//! to derive — luma only, RGB only, HSV only, all three, or something
//! custom — and writes into whatever buffers it owns.
//!
//! The row the Sink receives (`Self::Input<'_>`) has a shape that
//! reflects the source format: [`source::Yuv420pRow`] carries Y / U / V
//! slices plus matrix / range metadata; packed‑RGB row types
//! (e.g. [`source::Rgb24Row`], [`source::Bgr24Row`]) carry a single
//! packed slice; etc.
//! Each source family declares a subtrait
//! (`Yuv420pSink: PixelSink<Input<'_> = Yuv420pRow<'_>>`) so kernel
//! signatures stay sharp.
//!
//! For the common case — "give me RGB / Luma / HSV or any subset" —
//! the crate ships [`sinker::MixedSinker`], configured via
//! [`with_rgb`](sinker::MixedSinker::with_rgb) /
//! [`with_luma`](sinker::MixedSinker::with_luma) /
//! [`with_hsv`](sinker::MixedSinker::with_hsv) to select which channels
//! to derive.
//!
//! # Supported source formats
//!
//! Shipped (4:1:1, 4:2:0, 4:2:2, 4:4:0, and 4:4:4 subsampling):
//!
//! | Family | Bit depth | Subsampling | Packing | FFmpeg name |
//! | ---------------- | --------- | ----------- | ------------------------ | --------------------- |
//! | [`Yuv411p`] | 8 | 4:1:1 | planar (DV-NTSC legacy) | `yuv411p` |
//! | [`Yuv420p`] | 8 | 4:2:0 | planar | `yuv420p` |
//! | [`Yuv422p`] | 8 | 4:2:2 | planar | `yuv422p` |
//! | [`Yuv440p`] | 8 | 4:4:0 | planar | `yuv440p` |
//! | [`Yuv444p`] | 8 | 4:4:4 | planar | `yuv444p` |
//! | [`Nv12`] | 8 | 4:2:0 | semi-planar UV | `nv12` |
//! | [`Nv21`] | 8 | 4:2:0 | semi-planar VU | `nv21` |
//! | [`Nv16`] | 8 | 4:2:2 | semi-planar UV | `nv16` |
//! | [`Nv24`] | 8 | 4:4:4 | semi-planar UV | `nv24` |
//! | [`Nv42`] | 8 | 4:4:4 | semi-planar VU | `nv42` |
//! | [`Yuv420p9`] | 9 | 4:2:0 | planar, low-packed | `yuv420p9le` |
//! | [`Yuv420p10`] | 10 | 4:2:0 | planar, low-packed | `yuv420p10le` |
//! | [`Yuv420p12`] | 12 | 4:2:0 | planar, low-packed | `yuv420p12le` |
//! | [`Yuv420p14`] | 14 | 4:2:0 | planar, low-packed | `yuv420p14le` |
//! | [`Yuv420p16`] | 16 | 4:2:0 | planar | `yuv420p16le` |
//! | [`Yuv422p9`] | 9 | 4:2:2 | planar, low-packed | `yuv422p9le` |
//! | [`Yuv422p10`] | 10 | 4:2:2 | planar, low-packed | `yuv422p10le` |
//! | [`Yuv422p12`] | 12 | 4:2:2 | planar, low-packed | `yuv422p12le` |
//! | [`Yuv422p14`] | 14 | 4:2:2 | planar, low-packed | `yuv422p14le` |
//! | [`Yuv422p16`] | 16 | 4:2:2 | planar | `yuv422p16le` |
//! | [`Yuv440p10`] | 10 | 4:4:0 | planar, low-packed | `yuv440p10le` |
//! | [`Yuv440p12`] | 12 | 4:4:0 | planar, low-packed | `yuv440p12le` |
//! | [`Yuv444p9`] | 9 | 4:4:4 | planar, low-packed | `yuv444p9le` |
//! | [`Yuv444p10`] | 10 | 4:4:4 | planar, low-packed | `yuv444p10le` |
//! | [`Yuv444p12`] | 12 | 4:4:4 | planar, low-packed | `yuv444p12le` |
//! | [`Yuv444p14`] | 14 | 4:4:4 | planar, low-packed | `yuv444p14le` |
//! | [`Yuv444p16`] | 16 | 4:4:4 | planar | `yuv444p16le` |
//! | [`P010`] | 10 | 4:2:0 | semi-planar, high-packed | `p010le` |
//! | [`P012`] | 12 | 4:2:0 | semi-planar, high-packed | `p012le` |
//! | [`P016`] | 16 | 4:2:0 | semi-planar | `p016le` |
//! | [`P210`] | 10 | 4:2:2 | semi-planar, high-packed | `p210le` |
//! | [`P212`] | 12 | 4:2:2 | semi-planar, high-packed | `p212le` |
//! | [`P216`] | 16 | 4:2:2 | semi-planar | `p216le` |
//! | [`P410`] | 10 | 4:4:4 | semi-planar, high-packed | `p410le` |
//! | [`P412`] | 12 | 4:4:4 | semi-planar, high-packed | `p412le` |
//! | [`P416`] | 16 | 4:4:4 | semi-planar | `p416le` |
//! | [`V210`] | 10 | 4:2:2 | packed (3 x 10-bit/u32) | `v210` |
//! | [`Y210`] | 10 | 4:2:2 | packed, MSB-aligned u16 | `y210le` |
//! | [`Y212`] | 12 | 4:2:2 | packed, MSB-aligned u16 | `y212le` |
//! | [`Y216`] | 16 | 4:2:2 | packed, full-range u16 | `y216le` |
//! | [`V410`] | 10 | 4:4:4 | packed (one 32-bit word) | `v410` |
//! | [`V30X`] | 10 | 4:4:4 | packed (one 32-bit word) | `v30xle` |
//! | [`Xv36`] | 12 | 4:4:4 | packed u16 quadruple | `xv36le` |
//! | [`Vuya`] | 8 | 4:4:4 | packed byte quadruple, source α | `vuya` |
//! | [`Vuyx`] | 8 | 4:4:4 | packed byte quadruple, α-as-padding | `vuyx` |
//! | [`Ayuv64`] | 16 | 4:4:4 | packed u16 quadruple, source α | `ayuv64le` |
//! | [`Gbrp`] | 8 | 4:4:4 | planar GBR (3 planes) | `gbrp` |
//! | [`Gbrap`] | 8 | 4:4:4 | planar GBR + A (4 planes, source α) | `gbrap` |
//! | [`Xyz12`](crate::source::Xyz12) | 12 | 4:4:4 | packed CIE XYZ (3 x u16, high-bit-packed: bits `[15:4]`) | `xyz12le` / `xyz12be` |
//!
//! [`Xyz12`](crate::source::Xyz12) is the **DCP / digital-cinema** source format. Decoding
//! it requires a SMPTE ST 428-1 §8 inverse OETF, a 3x3 matrix to one
//! of three target gamuts ([`DcpTargetGamut::DciP3`] /
//! [`DcpTargetGamut::Rec709`] / [`DcpTargetGamut::Rec2020`]), then a
//! sRGB-shape forward OETF and integer narrow. Every backend is
//! native SIMD; the OETFs run scalar per lane to preserve the 0-ULP
//! scalar↔SIMD parity contract.
//!
//! ## RAW (Bayer) sources
//!
//! [`raw::Bayer`] (8-bit) and [`raw::Bayer16<BITS>`] (10/12/14/16-bit
//! low-packed `u16`, range `[0, (1 << BITS) - 1]`) feed bilinear
//! demosaic + white balance + 3x3
//! color-correction in a single per-row kernel. Caller supplies
//! [`raw::BayerPattern`] (BGGR / RGGB / GRBG / GBRG),
//! [`raw::WhiteBalance`] gains, and a [`raw::ColorCorrectionMatrix`].
//! See [`raw`] for the full design and parameter docs.
//!
//! Scope: `colconv` covers demosaic onwards. Producing the Bayer
//! plane itself is the upstream pipeline's job — vendor-SDK
//! camera-RAW decoders (R3D / BRAW / NRAW) for compressed
//! camera bitstreams, or FFmpeg's `AV_PIX_FMT_BAYER_*` pixel
//! formats / `bayer_*` decoders for already-uncompressed Bayer
//! sources. Once you have a `BayerFrame` / `BayerFrame16`, hand it
//! to [`raw::bayer_to`] / [`raw::bayer16_to`] with your sink of
//! choice.
//!
//! ## YUVA sources (alpha-drop)
//!
//! Every shipped 4:2:0 / 4:2:2 / 4:4:4 planar family also covers its
//! `yuva*` alpha variant by **alpha-drop**: the caller hands the
//! Y / U / V slices from a 4-plane YUVA buffer to the matching
//! `Yuv*p*Frame` constructor and ignores the alpha plane. This works
//! today for `yuva420p`, `yuva420p9le`, `yuva420p10le`,
//! `yuva420p16le`, `yuva422p`, `yuva422p9le`, `yuva422p10le`,
//! `yuva422p16le`, `yuva444p`, `yuva444p9le`, `yuva444p10le`, and
//! `yuva444p16le` (the full set of YUVA pixel formats FFmpeg
//! produces). RGBA pass-through (preserving the alpha channel into
//! the output) is the dedicated **Ship 8** work item — it adds
//! `with_rgba` / `with_rgba_u16` accessors on `MixedSinker` plus
//! native YUVA frame types.
//!
//! # Kernel families
//!
//! - **Q15 i32 family** — 8-bit kernels (`yuv_420_to_rgb_row`,
//! `yuv_444_to_rgb_row`, `nv12_to_rgb_row`, `nv24_to_rgb_row` etc.)
//! and 10/12/14-bit kernels (`yuv_420p_n_to_rgb_*<BITS>`,
//! `yuv_444p_n_to_rgb_*<BITS>`, `p_n_to_rgb_*<BITS>`). Native SIMD
//! on every backend (NEON / SSE4.1 / AVX2 / AVX-512 / wasm
//! simd128). [`Yuv422p`] (and the [`Yuv422p10`] / [`Yuv422p12`] /
//! [`Yuv422p14`] family) reuses [`Yuv420p`]'s per-row kernels
//! (4:2:2 differs only in the vertical walker); same for
//! [`Nv16`] ↔ [`Nv12`]. [`Yuv444p`] and [`Yuv444p10`] /
//! [`Yuv444p12`] / [`Yuv444p14`] use a dedicated 4:4:4 kernel
//! family (no horizontal chroma duplication step); [`Nv24`] and
//! [`Nv42`] share a 4:4:4 kernel family via a `SWAP_UV` const
//! generic.
//! - **16-bit family** — dedicated `yuv_420p16_to_rgb_*`,
//! `yuv444p16_to_rgb_*`, `p16_to_rgb_*`. [`Yuv422p16`] reuses the
//! 4:2:0 16-bit kernels by shape equivalence. The **u8-output**
//! kernels stay on i32 (output-range scaling keeps `coeff x u_d`
//! within i32). The **u16-output** kernels widen the chroma matrix
//! multiply-add to i64 to avoid the ~2.31·10⁹ chroma-channel sum
//! overflowing i32 at `BITS == 16`; the Y path also widens to i64
//! to handle limited-range unclamped samples.
//!
//! # SIMD coverage
//!
//! Every format above has a native SIMD backend for each supported
//! target (NEON on aarch64; SSE4.1 / AVX2 / AVX-512 on x86_64; wasm
//! simd128). Every u8-output and u16-output path has a native
//! implementation on every backend — including the 16-bit u16-output
//! paths for `Yuv420p16`, `P016`, and `Yuv444p16`, which use the
//! backend-native i64 arithmetic (native `_mm512_srai_epi64` on
//! AVX-512 and `i64x2_shr` on wasm; `srai64_15` bias trick on SSE4.1
//! and AVX2 because those ISAs lack native i64 arithmetic right
//! shift).
//!
//! # Not yet shipped (follow-up)
//!
//! - **Bayer SIMD backends** — Tier 14 currently dispatches to the
//! scalar reference path on every target; NEON / SSE4.1 / AVX2 /
//! AVX-512 / wasm simd128 follow-ups will land per the established
//! backend-symmetry pattern.
//! - **Cinema-camera RAW source formats** — vendor-decoded sensor RGB
//! in camera-native log + gamut (LogC4 / S-Log3 / REDLog3G10 /
//! Canon Log 2/3 / BMD Film Gen 5 / V-Log / F-Log) → working-space
//! conversion via inverse-OETF + 3x3 matrix + sRGB OETF. Roadmap
//! tracked in `docs/superpowers/plans/2026-05-07-be-rollout-tracking.md`
//! under "Cinema Camera RAW Support Roadmap". Mirrors the Tier 12
//! ([`source::Xyz12`]) shape: per-vendor source format, full
//! `MixedSinker` output coverage, polynomial OETF, 5 SIMD backends.
//! - **Higher-quality Bayer demosaic** — current scalar Bayer kernel
//! does bilinear demosaic; AHD / Malvar / DCB are quality levers
//! for cinema-grade proxies (CinemaDNG / DJI Inspire workflows).
//! - **3D LUT (`.cube`) row kernel** — for OCIO-style color management
//! in cinema pipelines.
//!
//! See [`source`] for the per-format module-level breakdown and
//! [`frame`] for the validated frame types plus the `BITS` const
//! generic on the high-bit-depth families (`Yuv420pFrame16<BITS>`
//! and `PnFrame<BITS>`).
//!
//! [`Yuv420p`]: crate::source::Yuv420p
//! [`Yuv422p`]: crate::source::Yuv422p
//! [`Yuv440p`]: crate::source::Yuv440p
//! [`Yuv444p`]: crate::source::Yuv444p
//! [`Nv12`]: crate::source::Nv12
//! [`Nv16`]: crate::source::Nv16
//! [`Nv21`]: crate::source::Nv21
//! [`Nv24`]: crate::source::Nv24
//! [`Nv42`]: crate::source::Nv42
//! [`Yuv420p9`]: crate::source::Yuv420p9
//! [`Yuv420p10`]: crate::source::Yuv420p10
//! [`Yuv420p12`]: crate::source::Yuv420p12
//! [`Yuv420p14`]: crate::source::Yuv420p14
//! [`Yuv420p16`]: crate::source::Yuv420p16
//! [`Yuv422p9`]: crate::source::Yuv422p9
//! [`Yuv422p10`]: crate::source::Yuv422p10
//! [`Yuv422p12`]: crate::source::Yuv422p12
//! [`Yuv422p14`]: crate::source::Yuv422p14
//! [`Yuv422p16`]: crate::source::Yuv422p16
//! [`Yuv440p10`]: crate::source::Yuv440p10
//! [`Yuv440p12`]: crate::source::Yuv440p12
//! [`Yuv444p9`]: crate::source::Yuv444p9
//! [`Yuv444p10`]: crate::source::Yuv444p10
//! [`Yuv444p12`]: crate::source::Yuv444p12
//! [`Yuv444p14`]: crate::source::Yuv444p14
//! [`Yuv444p16`]: crate::source::Yuv444p16
//! [`P010`]: crate::source::P010
//! [`P012`]: crate::source::P012
//! [`P016`]: crate::source::P016
//! [`P210`]: crate::source::P210
//! [`P212`]: crate::source::P212
//! [`P216`]: crate::source::P216
//! [`P410`]: crate::source::P410
//! [`P412`]: crate::source::P412
//! [`P416`]: crate::source::P416
//! [`V210`]: crate::source::V210
//! [`Y210`]: crate::source::Y210
//! [`Y212`]: crate::source::Y212
//! [`Y216`]: crate::source::Y216
//! [`V410`]: crate::source::V410
//! [`V30X`]: crate::source::V30X
//! [`Xv36`]: crate::source::Xv36
//! [`Vuya`]: crate::source::Vuya
//! [`Vuyx`]: crate::source::Vuyx
//! [`Ayuv64`]: crate::source::Ayuv64
//! [`Gbrp`]: crate::source::Gbrp
//! [`Gbrap`]: crate::source::Gbrap
extern crate alloc as std;
extern crate std;
pub use ;
pub use ;
pub use ;