| 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 | |