Skip to main content

ithmb_core/enc/
uyvy.rs

1// SPDX-License-Identifier: MIT
2// Encoder: UYVY — YUV 4:2:2 packed, 2 bytes per pixel
3
4use crate::enc::helpers::{bt601_cb, bt601_cr, bt601_y};
5use crate::pixel_utils::clamp_u8;
6
7/// Encode BGRA pixels to UYVY (YUV 4:2:2 packed, 2 bytes per pixel).
8///
9/// Layout per 2-pixel pair: `[Cb_avg, Y0, Cr_avg, Y1]`.
10/// Chroma values are averaged across the pair. Uses BT.601 colour conversion.
11#[must_use]
12pub fn encode_uyvy(bgra: &[u8], w: i32, h: i32) -> Vec<u8> {
13    let wu = w as usize;
14    let hu = h as usize;
15    let n = wu * hu;
16    // Each pair of pixels produces 4 bytes.  Allocate for ceil(w/2) pairs per row.
17    let pairs_per_row = wu.div_ceil(2);
18    let total_pairs = pairs_per_row * hu;
19    let mut out = vec![0u8; total_pairs * 4];
20
21    let mut px_i = 0;
22    let mut o_i = 0;
23    while px_i < n {
24        let px = px_i * 4;
25        let r0 = i32::from(bgra[px + 2]);
26        let g0 = i32::from(bgra[px + 1]);
27        let b0 = i32::from(bgra[px]);
28        let y0 = clamp_u8(bt601_y(r0, g0, b0));
29        let cb0 = bt601_cb(r0, g0, b0);
30        let cr0 = bt601_cr(r0, g0, b0);
31
32        if px_i + 1 < n {
33            // Full pair: average chroma
34            let px2 = (px_i + 1) * 4;
35            let r1 = i32::from(bgra[px2 + 2]);
36            let g1 = i32::from(bgra[px2 + 1]);
37            let b1 = i32::from(bgra[px2]);
38            let y1 = clamp_u8(bt601_y(r1, g1, b1));
39            let cb1 = bt601_cb(r1, g1, b1);
40            let cr1 = bt601_cr(r1, g1, b1);
41
42            let cb_avg = clamp_u8(cb0.midpoint(cb1));
43            let cr_avg = clamp_u8(cr0.midpoint(cr1));
44
45            out[o_i] = cb_avg;
46            out[o_i + 1] = y0;
47            out[o_i + 2] = cr_avg;
48            out[o_i + 3] = y1;
49        } else {
50            // Trailing pixel (odd width): use its own chroma
51            out[o_i] = clamp_u8(cb0);
52            out[o_i + 1] = y0;
53            out[o_i + 2] = clamp_u8(cr0);
54            out[o_i + 3] = 0;
55        }
56
57        px_i += 2;
58        o_i += 4;
59    }
60
61    out
62}