1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software;
5 *
6 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7 */
89//! This module exports a single struct to store information about
10//! JPEG image components
11//!
12//! The data is extracted from a SOF header.
1314use alloc::vec::Vec;
15use alloc::{format, vec};
1617use zune_core::log::trace;
1819use crate::decoder::MAX_COMPONENTS;
20use crate::errors::DecodeErrors;
21use crate::upsampler::upsample_no_op;
2223/// Represents an up-sampler function, this function will be called to upsample
24/// a down-sampled image
2526pub type UpSampler = fn(
27 input: &[i16],
28 in_near: &[i16],
29 in_far: &[i16],
30 scratch_space: &mut [i16],
31 output: &mut [i16]
32);
3334/// Component Data from start of frame
35#[derive(Clone)]
36pub(crate) struct Components {
37/// The type of component that has the metadata below, can be Y,Cb or Cr
38pub component_id: ComponentID,
39/// Sub-sampling ratio of this component in the x-plane
40pub vertical_sample: usize,
41/// Sub-sampling ratio of this component in the y-plane
42pub horizontal_sample: usize,
43/// DC huffman table position
44pub dc_huff_table: usize,
45/// AC huffman table position for this element.
46pub ac_huff_table: usize,
47/// Quantization table number
48pub quantization_table_number: u8,
49/// Specifies quantization table to use with this component
50pub quantization_table: [i32; 64],
51/// dc prediction for the component
52pub dc_pred: i32,
53/// An up-sampling function, can be basic or SSE, depending
54 /// on the platform
55pub up_sampler: UpSampler,
56/// How pixels do we need to go to get to the next line?
57pub width_stride: usize,
58/// Component ID for progressive
59pub id: u8,
60/// Whether we need to decode this image component.
61pub needed: bool,
62/// Upsample scanline
63pub raw_coeff: Vec<i16>,
64/// Upsample destination, stores a scanline worth of sub sampled data
65pub upsample_dest: Vec<i16>,
66/// previous row, used to handle MCU boundaries
67pub row_up: Vec<i16>,
68/// current row, used to handle MCU boundaries again
69pub row: Vec<i16>,
70pub first_row_upsample_dest: Vec<i16>,
71pub idct_pos: usize,
72pub x: usize,
73pub w2: usize,
74pub y: usize,
75pub sample_ratio: SampleRatios,
76// a very annoying bug
77pub fix_an_annoying_bug: usize
78}
7980impl Components {
81/// Create a new instance from three bytes from the start of frame
82#[inline]
83pub fn from(a: [u8; 3], pos: u8) -> Result<Components, DecodeErrors> {
84// it's a unique identifier.
85 // doesn't have to be ascending
86 // see tests/inputs/huge_sof_number
87 //
88 // For such cases, use the position of the component
89 // to determine width
9091let id = match pos {
920 => ComponentID::Y,
931 => ComponentID::Cb,
942 => ComponentID::Cr,
953 => ComponentID::Q,
96_ => {
97return Err(DecodeErrors::Format(format!(
98"Unknown component id found,{pos}, expected value between 1 and 4"
99)))
100 }
101 };
102103let horizontal_sample = (a[1] >> 4) as usize;
104let vertical_sample = (a[1] & 0x0f) as usize;
105let quantization_table_number = a[2];
106// confirm quantization number is between 0 and MAX_COMPONENTS
107if usize::from(quantization_table_number) >= MAX_COMPONENTS {
108return Err(DecodeErrors::Format(format!(
109"Too large quantization number :{quantization_table_number}, expected value between 0 and {MAX_COMPONENTS}"
110)));
111 }
112// check that upsampling ratios are powers of two
113 // if these fail, it's probably a corrupt image.
114if !horizontal_sample.is_power_of_two() {
115return Err(DecodeErrors::Format(format!(
116"Horizontal sample is not a power of two({horizontal_sample}) cannot decode"
117)));
118 }
119120if !vertical_sample.is_power_of_two() {
121return Err(DecodeErrors::Format(format!(
122"Vertical sub-sample is not power of two({vertical_sample}) cannot decode"
123)));
124 }
125126trace!(
127"Component ID:{:?} \tHS:{} VS:{} QT:{}",
128 id,
129 horizontal_sample,
130 vertical_sample,
131 quantization_table_number
132 );
133134Ok(Components {
135 component_id: id,
136 vertical_sample,
137 horizontal_sample,
138 quantization_table_number,
139 first_row_upsample_dest: vec![],
140// These two will be set with sof marker
141dc_huff_table: 0,
142 ac_huff_table: 0,
143 quantization_table: [0; 64],
144 dc_pred: 0,
145 up_sampler: upsample_no_op,
146// set later
147width_stride: horizontal_sample,
148 id: a[0],
149 needed: true,
150 raw_coeff: vec![],
151 upsample_dest: vec![],
152 row_up: vec![],
153 row: vec![],
154 idct_pos: 0,
155 x: 0,
156 y: 0,
157 w2: 0,
158 sample_ratio: SampleRatios::None,
159 fix_an_annoying_bug: 1
160})
161 }
162/// Setup space for upsampling
163 ///
164 /// During upsample, we need a reference of the last row so that upsampling can
165 /// proceed correctly,
166 /// so we store the last line of every scanline and use it for the next upsampling procedure
167 /// to store this, but since we don't need it for 1v1 upsampling,
168 /// we only call this for routines that need upsampling
169 ///
170 /// # Requirements
171 /// - width stride of this element is set for the component.
172pub fn setup_upsample_scanline(&mut self) {
173self.row = vec![0; self.width_stride * self.vertical_sample];
174self.row_up = vec![0; self.width_stride * self.vertical_sample];
175self.first_row_upsample_dest =
176vec![128; self.vertical_sample * self.width_stride * self.sample_ratio.sample()];
177self.upsample_dest =
178vec![0; self.width_stride * self.sample_ratio.sample() * self.fix_an_annoying_bug * 8];
179 }
180}
181182/// Component ID's
183#[derive(Copy, Debug, Clone, PartialEq, Eq)]
184pub enum ComponentID {
185/// Luminance channel
186Y,
187/// Blue chrominance
188Cb,
189/// Red chrominance
190Cr,
191/// Q or fourth component
192Q
193}
194195#[derive(Copy, Debug, Clone, PartialEq, Eq)]
196pub enum SampleRatios {
197 HV,
198 V,
199 H,
200None
201}
202203impl SampleRatios {
204pub fn sample(self) -> usize {
205match self {
206 SampleRatios::HV => 4,
207 SampleRatios::V | SampleRatios::H => 2,
208 SampleRatios::None => 1
209}
210 }
211}