jxl_frame/data/
lf_group.rs

1use jxl_bitstream::Bitstream;
2use jxl_grid::AllocTracker;
3use jxl_modular::{image::TransformedModularSubimage, MaConfig, Sample};
4use jxl_oxide_common::Bundle;
5use jxl_vardct::{HfMetadata, HfMetadataParams, LfCoeff, LfCoeffParams, Quantizer};
6
7use crate::{
8    filter::{EdgePreservingFilter, EpfParams},
9    header::Encoding,
10    FrameHeader, Result,
11};
12
13#[derive(Debug)]
14pub struct LfGroupParams<'a, 'dest, 'tracker, S: Sample> {
15    pub frame_header: &'a FrameHeader,
16    pub quantizer: Option<&'a Quantizer>,
17    pub global_ma_config: Option<&'a MaConfig>,
18    pub mlf_group: Option<TransformedModularSubimage<'dest, S>>,
19    pub lf_group_idx: u32,
20    pub allow_partial: bool,
21    pub tracker: Option<&'tracker AllocTracker>,
22    pub pool: &'a jxl_threadpool::JxlThreadPool,
23}
24
25#[derive(Debug)]
26pub struct LfGroup<S: Sample> {
27    pub lf_coeff: Option<LfCoeff<S>>,
28    pub hf_meta: Option<HfMetadata>,
29    pub partial: bool,
30}
31
32impl<S: Sample> Bundle<LfGroupParams<'_, '_, '_, S>> for LfGroup<S> {
33    type Error = crate::Error;
34
35    fn parse(bitstream: &mut Bitstream, params: LfGroupParams<S>) -> Result<Self> {
36        let LfGroupParams {
37            frame_header,
38            global_ma_config,
39            mlf_group,
40            lf_group_idx,
41            allow_partial,
42            tracker,
43            pool,
44            ..
45        } = params;
46        let (lf_width, lf_height) = frame_header.lf_group_size_for(lf_group_idx);
47
48        let lf_coeff = (frame_header.encoding == Encoding::VarDct
49            && !frame_header.flags.use_lf_frame())
50        .then(|| {
51            let lf_coeff_params = LfCoeffParams {
52                lf_group_idx,
53                lf_width,
54                lf_height,
55                jpeg_upsampling: frame_header.jpeg_upsampling,
56                bits_per_sample: frame_header.bit_depth.bits_per_sample(),
57                global_ma_config,
58                allow_partial,
59                tracker,
60                pool,
61            };
62            LfCoeff::parse(bitstream, lf_coeff_params)
63        })
64        .transpose()?;
65
66        if let Some(lf_coeff_inner) = &lf_coeff {
67            if lf_coeff_inner.partial {
68                return Ok(Self {
69                    lf_coeff,
70                    hf_meta: None,
71                    partial: true,
72                });
73            }
74        }
75
76        let mut is_mlf_complete = true;
77        if let Some(image) = mlf_group {
78            if !image.is_empty() {
79                let mut subimage = image.recursive(bitstream, global_ma_config, tracker)?;
80                let mut subimage = subimage.prepare_subimage()?;
81                subimage.decode(
82                    bitstream,
83                    1 + frame_header.num_lf_groups() + lf_group_idx,
84                    allow_partial,
85                )?;
86                is_mlf_complete = subimage.finish(pool);
87            }
88        }
89
90        let hf_meta = (frame_header.encoding == Encoding::VarDct && is_mlf_complete)
91            .then(|| {
92                let hf_meta_params = HfMetadataParams {
93                    num_lf_groups: frame_header.num_lf_groups(),
94                    lf_group_idx,
95                    lf_width,
96                    lf_height,
97                    jpeg_upsampling: frame_header.jpeg_upsampling,
98                    bits_per_sample: frame_header.bit_depth.bits_per_sample(),
99                    global_ma_config,
100                    epf: match &frame_header.restoration_filter.epf {
101                        EdgePreservingFilter::Disabled => None,
102                        EdgePreservingFilter::Enabled(EpfParams {
103                            sharp_lut, sigma, ..
104                        }) => Some((sigma.quant_mul, *sharp_lut)),
105                    },
106                    quantizer_global_scale: params.quantizer.unwrap().global_scale,
107                    tracker,
108                    pool,
109                };
110                HfMetadata::parse(bitstream, hf_meta_params)
111            })
112            .transpose();
113        match hf_meta {
114            Err(e) if e.unexpected_eof() && allow_partial => {
115                tracing::debug!("Decoded partial HfMeta");
116                Ok(Self {
117                    lf_coeff,
118                    hf_meta: None,
119                    partial: true,
120                })
121            }
122            Err(e) => Err(e.into()),
123            Ok(hf_meta) => Ok(Self {
124                lf_coeff,
125                hf_meta,
126                partial: !is_mlf_complete,
127            }),
128        }
129    }
130}