jxl_vardct/
lf.rs

1use jxl_bitstream::{Bitstream, U};
2use jxl_grid::AllocTracker;
3use jxl_modular::{ChannelShift, MaConfig, Modular, ModularParams, Sample};
4use jxl_oxide_common::{define_bundle, Bundle};
5
6use crate::Result;
7
8define_bundle! {
9    /// Dequantization information for each channel.
10    #[derive(Debug)]
11    pub struct LfChannelDequantization error(crate::Error) {
12        all_default: ty(Bool) default(true),
13        pub m_x_lf: ty(F16) cond(!all_default) default(1.0 / 32.0),
14        pub m_y_lf: ty(F16) cond(!all_default) default(1.0 / 4.0),
15        pub m_b_lf: ty(F16) cond(!all_default) default(1.0 / 2.0),
16    }
17
18    /// Global quantizer multipliers.
19    #[derive(Debug)]
20    pub struct Quantizer error(crate::Error) {
21        pub global_scale: ty(U32(1 + u(11), 2049 + u(11), 4097 + u(12), 8193 + u(16))),
22        pub quant_lf: ty(U32(16, 1 + u(5), 1 + u(8), 1 + u(16))),
23    }
24
25    /// Channel correlation data, used by chroma-from-luma procedure.
26    #[derive(Debug)]
27    pub struct LfChannelCorrelation error(crate::Error) {
28        all_default: ty(Bool) default(true),
29        pub colour_factor: ty(U32(84, 256, 2 + u(8), 258 + u(16))) cond(!all_default) default(84),
30        pub base_correlation_x: ty(F16) cond(!all_default) default(0.0),
31        pub base_correlation_b: ty(F16) cond(!all_default) default(1.0),
32        pub x_factor_lf: ty(u(8)) cond(!all_default) default(128),
33        pub b_factor_lf: ty(u(8)) cond(!all_default) default(128),
34    }
35}
36
37impl LfChannelDequantization {
38    #[inline]
39    pub fn m_x_lf_unscaled(&self) -> f32 {
40        self.m_x_lf / 128.0
41    }
42
43    #[inline]
44    pub fn m_y_lf_unscaled(&self) -> f32 {
45        self.m_y_lf / 128.0
46    }
47
48    #[inline]
49    pub fn m_b_lf_unscaled(&self) -> f32 {
50        self.m_b_lf / 128.0
51    }
52}
53
54/// Context information for the entropy decoder of HF coefficients.
55#[derive(Debug, Default)]
56pub struct HfBlockContext {
57    pub qf_thresholds: Vec<u32>,
58    pub lf_thresholds: [Vec<i32>; 3],
59    pub block_ctx_map: Vec<u8>,
60    pub num_block_clusters: u32,
61}
62
63impl<Ctx> Bundle<Ctx> for HfBlockContext {
64    type Error = crate::Error;
65
66    fn parse(bitstream: &mut Bitstream, _: Ctx) -> crate::Result<Self> {
67        let mut qf_thresholds = Vec::new();
68        let mut lf_thresholds = [Vec::new(), Vec::new(), Vec::new()];
69        let (num_block_clusters, block_ctx_map) = if bitstream.read_bool()? {
70            (
71                15,
72                vec![
73                    0, 1, 2, 2, 3, 3, 4, 5, 6, 6, 6, 6, 6, 7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14,
74                    14, 14, 7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14,
75                ],
76            )
77        } else {
78            let mut bsize = 1;
79            for thr in &mut lf_thresholds {
80                let num_lf_thresholds = bitstream.read_bits(4)?;
81                bsize *= num_lf_thresholds + 1;
82                for _ in 0..num_lf_thresholds {
83                    let t = bitstream.read_u32(U(4), 16 + U(8), 272 + U(16), 65808 + U(32))?;
84                    let t = jxl_bitstream::unpack_signed(t);
85                    thr.push(t);
86                }
87            }
88            let num_qf_thresholds = bitstream.read_bits(4)?;
89            bsize *= num_qf_thresholds + 1;
90            for _ in 0..num_qf_thresholds {
91                let t = bitstream.read_u32(U(2), 4 + U(3), 12 + U(5), 44 + U(8))?;
92                qf_thresholds.push(1 + t);
93            }
94
95            if bsize > 64 {
96                tracing::warn!(bsize, "bsize > 64");
97            }
98
99            let (num_clusters, ctx_map) = jxl_coding::read_clusters(bitstream, bsize * 39)?;
100            if num_clusters > 16 {
101                tracing::warn!(num_clusters, "num_clusters > 16");
102            }
103
104            (num_clusters, ctx_map)
105        };
106
107        Ok(Self {
108            qf_thresholds,
109            lf_thresholds,
110            block_ctx_map,
111            num_block_clusters,
112        })
113    }
114}
115
116/// Paramters for decoding `LfCoeff`.
117#[derive(Debug)]
118pub struct LfCoeffParams<'ma, 'pool, 'tracker> {
119    pub lf_group_idx: u32,
120    pub lf_width: u32,
121    pub lf_height: u32,
122    pub jpeg_upsampling: [u32; 3],
123    pub bits_per_sample: u32,
124    pub global_ma_config: Option<&'ma MaConfig>,
125    pub allow_partial: bool,
126    pub tracker: Option<&'tracker AllocTracker>,
127    pub pool: &'pool jxl_threadpool::JxlThreadPool,
128}
129
130/// Quantized LF image.
131#[derive(Debug)]
132pub struct LfCoeff<S: Sample> {
133    pub extra_precision: u8,
134    pub lf_quant: Modular<S>,
135    pub partial: bool,
136}
137
138impl<S: Sample> Bundle<LfCoeffParams<'_, '_, '_>> for LfCoeff<S> {
139    type Error = crate::Error;
140
141    fn parse(bitstream: &mut Bitstream, params: LfCoeffParams) -> Result<Self> {
142        let LfCoeffParams {
143            lf_group_idx,
144            lf_width,
145            lf_height,
146            jpeg_upsampling,
147            bits_per_sample,
148            global_ma_config,
149            allow_partial,
150            tracker,
151            pool,
152        } = params;
153
154        let extra_precision = bitstream.read_bits(2)? as u8;
155
156        let width = (lf_width + 7) / 8;
157        let height = (lf_height + 7) / 8;
158        let channel_shifts = [1, 0, 2]
159            .into_iter()
160            .map(|idx| ChannelShift::from_jpeg_upsampling(jpeg_upsampling, idx))
161            .collect();
162        let lf_quant_params = ModularParams::new(
163            width,
164            height,
165            0,
166            bits_per_sample,
167            channel_shifts,
168            global_ma_config,
169            tracker,
170        );
171        let mut lf_quant = Modular::parse(bitstream, lf_quant_params)?;
172        let image = lf_quant.image_mut().unwrap();
173        let mut subimage = image.prepare_subimage()?;
174        subimage.decode(bitstream, 1 + lf_group_idx, allow_partial)?;
175        let complete = subimage.finish(pool);
176        Ok(Self {
177            extra_precision,
178            lf_quant,
179            partial: !complete,
180        })
181    }
182}