styx_codec/decoder/raw/
mod.rs1use styx_core::prelude::ColorSpace;
4
5mod bayer;
6mod bgr;
7mod bgra;
8mod i420;
9mod mono;
10mod nv12;
11mod passthrough;
12mod rgb48;
13mod rgba;
14mod yuv;
15mod yuv420p;
16mod yuyv;
17
18pub use bayer::{BayerToRgbDecoder, bayer_decoder_for, bayer_info};
19pub use bgr::BgrToRgbDecoder;
20pub use bgra::BgraToRgbDecoder;
21pub use i420::I420ToRgbDecoder;
22pub use mono::{Mono8ToRgbDecoder, Mono16ToRgbDecoder};
23pub use nv12::{Nv12ToBgrDecoder, Nv12ToRgbDecoder};
24pub use passthrough::PassthroughDecoder;
25pub use rgb48::Rgb48ToRgbDecoder;
26pub use rgba::RgbaToRgbDecoder;
27pub use yuv::{NvToRgbDecoder, Packed422ToRgbDecoder, PlanarYuvToRgbDecoder};
28pub use yuv420p::Yuv420pToRgbDecoder;
29pub use yuyv::{YuyvToLumaDecoder, YuyvToRgbDecoder};
30
31#[derive(Clone, Copy)]
32struct YuvCoeffs {
33 r_v: i32,
34 g_u: i32,
35 g_v: i32,
36 b_u: i32,
37 full_range: bool,
38}
39
40const BT709: YuvCoeffs = YuvCoeffs {
41 r_v: 459,
42 g_u: 55,
43 g_v: 136,
44 b_u: 541,
45 full_range: false,
46};
47
48const BT601_FULL: YuvCoeffs = YuvCoeffs {
50 r_v: 359,
51 g_u: 88,
52 g_v: 183,
53 b_u: 454,
54 full_range: true,
55};
56
57const BT2020: YuvCoeffs = YuvCoeffs {
58 r_v: 430,
59 g_u: 48,
60 g_v: 166,
61 b_u: 549,
62 full_range: false,
63};
64
65#[inline(always)]
67pub(crate) fn yuv_to_rgb(y: i32, u: i32, v: i32, color: ColorSpace) -> (u8, u8, u8) {
68 let coeffs = match color {
69 ColorSpace::Bt709 => BT709,
70 ColorSpace::Bt2020 => BT2020,
71 ColorSpace::Srgb => BT601_FULL,
74 ColorSpace::Unknown => BT709,
76 };
77 let d = u - 128;
78 let e = v - 128;
79 let (c, scale) = if coeffs.full_range {
80 (y.max(0), 256)
81 } else {
82 (y.saturating_sub(16).max(0), 298)
83 };
84 let r = (scale * c + coeffs.r_v * e + 128) >> 8;
85 let g = (scale * c - coeffs.g_u * d - coeffs.g_v * e + 128) >> 8;
86 let b = (scale * c + coeffs.b_u * d + 128) >> 8;
87 (
88 r.clamp(0, 255) as u8,
89 g.clamp(0, 255) as u8,
90 b.clamp(0, 255) as u8,
91 )
92}