1 | use alloc::boxed::Box; |
2 | use alloc::vec; |
3 | use alloc::vec::Vec; |
4 | use crate::error::{Error, Result, UnsupportedFeature}; |
5 | use crate::parser::Component; |
6 | |
7 | pub struct Upsampler { |
8 | components: Vec<UpsamplerComponent>, |
9 | line_buffer_size: usize |
10 | } |
11 | |
12 | struct UpsamplerComponent { |
13 | upsampler: Box<dyn Upsample + Sync>, |
14 | width: usize, |
15 | height: usize, |
16 | row_stride: usize, |
17 | } |
18 | |
19 | impl 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 | |
66 | struct UpsamplerH1V1; |
67 | struct UpsamplerH2V1; |
68 | struct UpsamplerH1V2; |
69 | struct UpsamplerH2V2; |
70 | |
71 | struct UpsamplerGeneric { |
72 | horizontal_scaling_factor: u8, |
73 | vertical_scaling_factor: u8 |
74 | } |
75 | |
76 | fn 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)] |
108 | trait 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 | |
119 | impl 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 | |
134 | impl 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 | |
165 | impl 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 | |
191 | impl 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 | |
230 | impl 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 | |