1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use crate::error::{Error, Result, UnsupportedFeature};
5use crate::parser::Component;
6
7pub struct Upsampler {
8 components: Vec<UpsamplerComponent>,
9 line_buffer_size: usize
10}
11
12struct UpsamplerComponent {
13 upsampler: Box<dyn Upsample + Sync>,
14 width: usize,
15 height: usize,
16 row_stride: usize,
17}
18
19impl Upsampler {
20 pub fn new(components: &[Component], output_width: u16, output_height: u16) -> Result<Upsampler> {
21 let h_max = components.iter().map(|c| c.horizontal_sampling_factor).max().unwrap();
22 let v_max = components.iter().map(|c| c.vertical_sampling_factor).max().unwrap();
23 let mut upsampler_components = Vec::with_capacity(components.len());
24
25 for component in components {
26 let upsampler = choose_upsampler((component.horizontal_sampling_factor,
27 component.vertical_sampling_factor),
28 (h_max, v_max),
29 output_width,
30 output_height)?;
31 upsampler_components.push(UpsamplerComponent {
32 upsampler,
33 width: component.size.width as usize,
34 height: component.size.height as usize,
35 row_stride: component.block_size.width as usize * component.dct_scale,
36 });
37 }
38
39 let buffer_size = components.iter().map(|c| c.size.width).max().unwrap() as usize * h_max as usize;
40
41 Ok(Upsampler {
42 components: upsampler_components,
43 line_buffer_size: buffer_size
44 })
45 }
46
47 pub fn upsample_and_interleave_row(&self, component_data: &[Vec<u8>], row: usize, output_width: usize, output: &mut [u8], color_convert: fn(&[Vec<u8>], &mut [u8])) {
48 let component_count = component_data.len();
49 let mut line_buffers = vec![vec![0u8; self.line_buffer_size]; component_count];
50
51 debug_assert_eq!(component_count, self.components.len());
52
53 for (i, component) in self.components.iter().enumerate() {
54 component.upsampler.upsample_row(&component_data[i],
55 component.width,
56 component.height,
57 component.row_stride,
58 row,
59 output_width,
60 &mut line_buffers[i]);
61 }
62 color_convert(&line_buffers, output);
63 }
64}
65
66struct UpsamplerH1V1;
67struct UpsamplerH2V1;
68struct UpsamplerH1V2;
69struct UpsamplerH2V2;
70
71struct UpsamplerGeneric {
72 horizontal_scaling_factor: u8,
73 vertical_scaling_factor: u8
74}
75
76fn choose_upsampler(sampling_factors: (u8, u8),
77 max_sampling_factors: (u8, u8),
78 output_width: u16,
79 output_height: u16) -> Result<Box<dyn Upsample + Sync>> {
80 let h1 = sampling_factors.0 == max_sampling_factors.0 || output_width == 1;
81 let v1 = sampling_factors.1 == max_sampling_factors.1 || output_height == 1;
82 let h2 = sampling_factors.0 * 2 == max_sampling_factors.0;
83 let v2 = sampling_factors.1 * 2 == max_sampling_factors.1;
84
85 if h1 && v1 {
86 Ok(Box::new(UpsamplerH1V1))
87 } else if h2 && v1 {
88 Ok(Box::new(UpsamplerH2V1))
89 } else if h1 && v2 {
90 Ok(Box::new(UpsamplerH1V2))
91 } else if h2 && v2 {
92 Ok(Box::new(UpsamplerH2V2))
93 } else if max_sampling_factors.0 % sampling_factors.0 != 0
94 || max_sampling_factors.1 % sampling_factors.1 != 0
95 {
96 Err(Error::Unsupported(
97 UnsupportedFeature::NonIntegerSubsamplingRatio,
98 ))
99 } else {
100 Ok(Box::new(UpsamplerGeneric {
101 horizontal_scaling_factor: max_sampling_factors.0 / sampling_factors.0,
102 vertical_scaling_factor: max_sampling_factors.1 / sampling_factors.1,
103 }))
104 }
105}
106
107#[allow(clippy::too_many_arguments)]
108trait Upsample {
109 fn upsample_row(&self,
110 input: &[u8],
111 input_width: usize,
112 input_height: usize,
113 row_stride: usize,
114 row: usize,
115 output_width: usize,
116 output: &mut [u8]);
117}
118
119impl Upsample for UpsamplerH1V1 {
120 fn upsample_row(&self,
121 input: &[u8],
122 _input_width: usize,
123 _input_height: usize,
124 row_stride: usize,
125 row: usize,
126 output_width: usize,
127 output: &mut [u8]) {
128 let input: &[u8] = &input[row * row_stride ..];
129
130 output[..output_width].copy_from_slice(&input[..output_width]);
131 }
132}
133
134impl Upsample for UpsamplerH2V1 {
135 fn upsample_row(&self,
136 input: &[u8],
137 input_width: usize,
138 _input_height: usize,
139 row_stride: usize,
140 row: usize,
141 _output_width: usize,
142 output: &mut [u8]) {
143 let input = &input[row * row_stride ..];
144
145 if input_width == 1 {
146 output[0] = input[0];
147 output[1] = input[0];
148 return;
149 }
150
151 output[0] = input[0];
152 output[1] = ((input[0] as u32 * 3 + input[1] as u32 + 2) >> 2) as u8;
153
154 for i in 1 .. input_width - 1 {
155 let sample = 3 * input[i] as u32 + 2;
156 output[i * 2] = ((sample + input[i - 1] as u32) >> 2) as u8;
157 output[i * 2 + 1] = ((sample + input[i + 1] as u32) >> 2) as u8;
158 }
159
160 output[(input_width - 1) * 2] = ((input[input_width - 1] as u32 * 3 + input[input_width - 2] as u32 + 2) >> 2) as u8;
161 output[(input_width - 1) * 2 + 1] = input[input_width - 1];
162 }
163}
164
165impl Upsample for UpsamplerH1V2 {
166 fn upsample_row(&self,
167 input: &[u8],
168 _input_width: usize,
169 input_height: usize,
170 row_stride: usize,
171 row: usize,
172 output_width: usize,
173 output: &mut [u8]) {
174 let row_near = row as f32 / 2.0;
175 // If row_near's fractional is 0.0 we want row_far to be the previous row and if it's 0.5 we
176 // want it to be the next row.
177 let row_far = (row_near + row_near.fract() * 3.0 - 0.25).min((input_height - 1) as f32);
178
179 let input_near = &input[row_near as usize * row_stride ..];
180 let input_far = &input[row_far as usize * row_stride ..];
181
182 let output = &mut output[..output_width];
183 let input_near = &input_near[..output_width];
184 let input_far = &input_far[..output_width];
185 for i in 0..output_width {
186 output[i] = ((3 * input_near[i] as u32 + input_far[i] as u32 + 2) >> 2) as u8;
187 }
188 }
189}
190
191impl Upsample for UpsamplerH2V2 {
192 fn upsample_row(&self,
193 input: &[u8],
194 input_width: usize,
195 input_height: usize,
196 row_stride: usize,
197 row: usize,
198 _output_width: usize,
199 output: &mut [u8]) {
200 let row_near = row as f32 / 2.0;
201 // If row_near's fractional is 0.0 we want row_far to be the previous row and if it's 0.5 we
202 // want it to be the next row.
203 let row_far = (row_near + row_near.fract() * 3.0 - 0.25).min((input_height - 1) as f32);
204
205 let input_near = &input[row_near as usize * row_stride ..];
206 let input_far = &input[row_far as usize * row_stride ..];
207
208 if input_width == 1 {
209 let value = ((3 * input_near[0] as u32 + input_far[0] as u32 + 2) >> 2) as u8;
210 output[0] = value;
211 output[1] = value;
212 return;
213 }
214
215 let mut t1 = 3 * input_near[0] as u32 + input_far[0] as u32;
216 output[0] = ((t1 + 2) >> 2) as u8;
217
218 for i in 1 .. input_width {
219 let t0 = t1;
220 t1 = 3 * input_near[i] as u32 + input_far[i] as u32;
221
222 output[i * 2 - 1] = ((3 * t0 + t1 + 8) >> 4) as u8;
223 output[i * 2] = ((3 * t1 + t0 + 8) >> 4) as u8;
224 }
225
226 output[input_width * 2 - 1] = ((t1 + 2) >> 2) as u8;
227 }
228}
229
230impl Upsample for UpsamplerGeneric {
231 // Uses nearest neighbor sampling
232 fn upsample_row(&self,
233 input: &[u8],
234 input_width: usize,
235 _input_height: usize,
236 row_stride: usize,
237 row: usize,
238 _output_width: usize,
239 output: &mut [u8]) {
240 let mut index: usize = 0;
241 let start: usize = (row / self.vertical_scaling_factor as usize) * row_stride;
242 let input: &[u8] = &input[start..(start + input_width)];
243 for val: &u8 in input {
244 for _ in 0..self.horizontal_scaling_factor {
245 output[index] = *val;
246 index += 1;
247 }
248 }
249 }
250}
251