jxl_frame/data/
lf_group.rs1use 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}