| 1 | use crate::formats::*; |
| 2 | use super::*; |
| 3 | use super::kernel::Kernel; |
| 4 | |
| 5 | fn convert_depth(val: u32, indepth: u8, outdepth: u8) -> u32 { |
| 6 | if indepth >= outdepth { |
| 7 | val >> (indepth - outdepth) |
| 8 | } else { |
| 9 | let mut val2 = val << (outdepth - indepth); |
| 10 | let mut shift = outdepth - indepth; |
| 11 | while shift >= indepth { |
| 12 | shift -= indepth; |
| 13 | val2 |= val << shift; |
| 14 | } |
| 15 | if shift > 0 { |
| 16 | val2 |= val >> (indepth - shift); |
| 17 | } |
| 18 | val2 |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | #[derive(Default)] |
| 23 | struct PackKernel { |
| 24 | shifts: [u8; MAX_CHROMATONS], |
| 25 | depths: [u8; MAX_CHROMATONS], |
| 26 | ncomps: usize, |
| 27 | osize: [u8; MAX_CHROMATONS], |
| 28 | ooff: [usize; MAX_CHROMATONS], |
| 29 | } |
| 30 | |
| 31 | impl PackKernel { |
| 32 | fn new() -> Self { Self::default() } |
| 33 | } |
| 34 | |
| 35 | impl Kernel for PackKernel { |
| 36 | fn init(&mut self, in_fmt: &ScaleInfo, dest_fmt: &ScaleInfo, _options: &[(String, String)]) -> ScaleResult<NABufferType> { |
| 37 | self.ncomps = in_fmt.fmt.components.min(dest_fmt.fmt.components) as usize; |
| 38 | for i in 0..self.ncomps { |
| 39 | let ichr = in_fmt.fmt.comp_info[i].unwrap(); |
| 40 | let ochr = dest_fmt.fmt.comp_info[i].unwrap(); |
| 41 | self.shifts[i] = ochr.shift; |
| 42 | self.osize[i] = ochr.depth; |
| 43 | self.depths[i] = ichr.depth; |
| 44 | self.ooff[i] = ochr.comp_offs as usize; |
| 45 | } |
| 46 | let res = alloc_video_buffer(NAVideoInfo::new(in_fmt.width, in_fmt.height, false, dest_fmt.fmt), 3); |
| 47 | if res.is_err() { return Err(ScaleError::AllocError); } |
| 48 | Ok(res.unwrap()) |
| 49 | } |
| 50 | fn process(&mut self, pic_in: &NABufferType, pic_out: &mut NABufferType) { |
| 51 | if let Some(ref buf) = pic_in.get_vbuf() { |
| 52 | if let Some(ref mut dbuf) = pic_out.get_vbuf() { |
| 53 | let dstride = dbuf.get_stride(0); |
| 54 | for comp in 0..self.ncomps { |
| 55 | let ioff = buf.get_offset(comp); |
| 56 | let istride = buf.get_stride(comp); |
| 57 | let step = dbuf.get_info().get_format().get_chromaton(comp).unwrap().get_step() as usize; |
| 58 | let (w, h) = dbuf.get_dimensions(comp); |
| 59 | let sdata = buf.get_data(); |
| 60 | let sdata = &sdata[ioff..]; |
| 61 | let ddata = dbuf.get_data_mut().unwrap(); |
| 62 | for (src, dst) in sdata.chunks(istride).zip(ddata.chunks_mut(dstride)).take(h) { |
| 63 | for x in 0..w { |
| 64 | dst[x * step + self.ooff[comp]] = convert_depth(u32::from(src[x]), self.depths[comp], self.osize[comp]) as u8; |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | } else if let Some(ref mut dbuf) = pic_out.get_vbuf16() { |
| 69 | let (w, h) = dbuf.get_dimensions(0); |
| 70 | let dstride = dbuf.get_stride(0); |
| 71 | let ddata = dbuf.get_data_mut().unwrap(); |
| 72 | let src = buf.get_data(); |
| 73 | let mut ioff: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 74 | let mut istride: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 75 | for comp in 0..self.ncomps { |
| 76 | ioff[comp] = buf.get_offset(comp); |
| 77 | istride[comp] = buf.get_stride(comp); |
| 78 | } |
| 79 | for dst in ddata.chunks_mut(dstride).take(h) { |
| 80 | for x in 0..w { |
| 81 | let mut elem: u32 = 0; |
| 82 | for comp in 0..self.ncomps { |
| 83 | let c = u32::from(src[ioff[comp] + x]); |
| 84 | elem |= convert_depth(c, self.depths[comp], self.osize[comp]) << self.shifts[comp]; |
| 85 | } |
| 86 | dst[x] = elem as u16; |
| 87 | } |
| 88 | for comp in 0..self.ncomps { |
| 89 | ioff[comp] += istride[comp]; |
| 90 | } |
| 91 | } |
| 92 | } else { |
| 93 | unimplemented!(); |
| 94 | } |
| 95 | } else if let Some(ref _buf) = pic_in.get_vbuf16() { |
| 96 | unimplemented!(); |
| 97 | } else if let Some(ref _buf) = pic_in.get_vbuf32() { |
| 98 | unimplemented!(); |
| 99 | } else { |
| 100 | unreachable!(); |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | pub fn create_pack() -> Box<dyn Kernel> { |
| 106 | Box::new(PackKernel::new()) |
| 107 | } |
| 108 | |
| 109 | #[derive(Default)] |
| 110 | struct UnpackKernel { |
| 111 | shifts: [u8; MAX_CHROMATONS], |
| 112 | masks: [u32; MAX_CHROMATONS], |
| 113 | depths: [u8; MAX_CHROMATONS], |
| 114 | ncomps: usize, |
| 115 | osize: [u8; MAX_CHROMATONS], |
| 116 | } |
| 117 | |
| 118 | impl UnpackKernel { |
| 119 | fn new() -> Self { Self::default() } |
| 120 | } |
| 121 | |
| 122 | impl Kernel for UnpackKernel { |
| 123 | fn init(&mut self, in_fmt: &ScaleInfo, dest_fmt: &ScaleInfo, options: &[(String, String)]) -> ScaleResult<NABufferType> { |
| 124 | let mut debug = false; |
| 125 | for (name, value) in options.iter() { |
| 126 | match (name.as_str(), value.as_str()) { |
| 127 | ("debug", "") => { debug = true; }, |
| 128 | ("debug", "true") => { debug = true; }, |
| 129 | _ => {}, |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | self.ncomps = in_fmt.fmt.components.min(dest_fmt.fmt.components) as usize; |
| 134 | let mut chr: Vec<Option<NAPixelChromaton>> = Vec::with_capacity(MAX_CHROMATONS); |
| 135 | for i in 0..self.ncomps { |
| 136 | let ichr = in_fmt.fmt.comp_info[i].unwrap(); |
| 137 | let ochr = dest_fmt.fmt.comp_info[i].unwrap(); |
| 138 | self.shifts[i] = ichr.shift; |
| 139 | self.masks[i] = (1 << ichr.depth) - 1; |
| 140 | if ochr.depth > ichr.depth { |
| 141 | self.osize[i] = ochr.depth; |
| 142 | } else { |
| 143 | self.osize[i] = (ichr.depth + 7) & !7; |
| 144 | } |
| 145 | self.depths[i] = ichr.depth; |
| 146 | let mut dchr = ichr; |
| 147 | dchr.packed = false; |
| 148 | dchr.depth = self.osize[i]; |
| 149 | dchr.shift = 0; |
| 150 | dchr.comp_offs = 0; |
| 151 | dchr.next_elem = 0; |
| 152 | chr.push(Some(dchr)); |
| 153 | } |
| 154 | let mut df = in_fmt.fmt; |
| 155 | df.comp_info[..self.ncomps].clone_from_slice(&chr[..self.ncomps]); |
| 156 | df.components = self.ncomps as u8; |
| 157 | df.palette = false; |
| 158 | if debug { |
| 159 | println!(" [intermediate format {}]", df); |
| 160 | } |
| 161 | let res = alloc_video_buffer(NAVideoInfo::new(in_fmt.width, in_fmt.height, false, df), 3); |
| 162 | if res.is_err() { return Err(ScaleError::AllocError); } |
| 163 | Ok(res.unwrap()) |
| 164 | } |
| 165 | fn process(&mut self, pic_in: &NABufferType, pic_out: &mut NABufferType) { |
| 166 | if let Some(ref buf) = pic_in.get_vbuf() { |
| 167 | let step = buf.get_info().get_format().elem_size as usize; |
| 168 | let mut soff: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 169 | for i in 0..self.ncomps { |
| 170 | soff[i] = buf.get_info().get_format().get_chromaton(i).unwrap().get_offset() as usize; |
| 171 | } |
| 172 | let (w, h) = buf.get_dimensions(0); |
| 173 | let ioff = buf.get_offset(0); |
| 174 | let istride = buf.get_stride(0); |
| 175 | let sdata1 = buf.get_data(); |
| 176 | let sdata = &sdata1[ioff..]; |
| 177 | let ychr = buf.get_info().get_format().get_chromaton(0).unwrap(); |
| 178 | if let Some(ref mut dbuf) = pic_out.get_vbuf() { |
| 179 | let mut ostride: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 180 | let mut offs: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 181 | for i in 0..self.ncomps { |
| 182 | ostride[i] = dbuf.get_stride(i); |
| 183 | offs[i] = dbuf.get_offset(i); |
| 184 | } |
| 185 | let dst = dbuf.get_data_mut().unwrap(); |
| 186 | if ychr.next_elem == 0 || usize::from(ychr.next_elem) == step { |
| 187 | for src in sdata.chunks(istride).take(h) { |
| 188 | for x in 0..w { |
| 189 | for i in 0..self.ncomps { |
| 190 | dst[offs[i] + x] = src[x * step + soff[i]]; |
| 191 | } |
| 192 | } |
| 193 | for i in 0..self.ncomps { offs[i] += ostride[i]; } |
| 194 | } |
| 195 | } else { |
| 196 | let mut steps: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 197 | for i in 0..self.ncomps { |
| 198 | steps[i] = buf.get_info().get_format().get_chromaton(i).unwrap().next_elem as usize; |
| 199 | } |
| 200 | |
| 201 | for src in sdata.chunks(istride).take(h) { |
| 202 | let mut x = offs; |
| 203 | for piece in src.chunks(step) { |
| 204 | for i in 0..self.ncomps { |
| 205 | let mut co = soff[i]; |
| 206 | while co < step { |
| 207 | dst[x[i]] = piece[co]; |
| 208 | x[i] += 1; |
| 209 | co += steps[i]; |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | for i in 0..self.ncomps { offs[i] += ostride[i]; } |
| 214 | } |
| 215 | } |
| 216 | } else { |
| 217 | unimplemented!(); |
| 218 | } |
| 219 | } else if let Some(ref buf) = pic_in.get_vbuf16() { |
| 220 | let (w, h) = buf.get_dimensions(0); |
| 221 | let ioff = buf.get_offset(0); |
| 222 | let istride = buf.get_stride(0); |
| 223 | let sdata1 = buf.get_data(); |
| 224 | let sdata = &sdata1[ioff..]; |
| 225 | if let Some(ref mut dbuf) = pic_out.get_vbuf() { |
| 226 | let mut ostride: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 227 | let mut offs: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 228 | for i in 0..self.ncomps { |
| 229 | ostride[i] = dbuf.get_stride(i); |
| 230 | offs[i] = dbuf.get_offset(i); |
| 231 | } |
| 232 | let dst = dbuf.get_data_mut().unwrap(); |
| 233 | for src in sdata.chunks(istride).take(h) { |
| 234 | for x in 0..w { |
| 235 | let elem = u32::from(src[x]); |
| 236 | for i in 0..self.ncomps { |
| 237 | dst[offs[i] + x] = convert_depth((elem >> self.shifts[i]) & self.masks[i], self.depths[i], self.osize[i]) as u8; |
| 238 | } |
| 239 | } |
| 240 | for i in 0..self.ncomps { offs[i] += ostride[i]; } |
| 241 | } |
| 242 | } else { |
| 243 | unimplemented!(); |
| 244 | } |
| 245 | } else if let Some(ref _buf) = pic_in.get_vbuf32() { |
| 246 | unimplemented!(); |
| 247 | } else { |
| 248 | unreachable!(); |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | pub fn create_unpack() -> Box<dyn Kernel> { |
| 254 | Box::new(UnpackKernel::new()) |
| 255 | } |
| 256 | |
| 257 | #[derive(Default)] |
| 258 | struct DepalKernel { |
| 259 | depths: [u8; MAX_CHROMATONS], |
| 260 | coffs: [usize; MAX_CHROMATONS], |
| 261 | ncomps: usize, |
| 262 | palstep: usize, |
| 263 | } |
| 264 | |
| 265 | impl DepalKernel { |
| 266 | fn new() -> Self { Self::default() } |
| 267 | } |
| 268 | |
| 269 | impl Kernel for DepalKernel { |
| 270 | fn init(&mut self, in_fmt: &ScaleInfo, _dest_fmt: &ScaleInfo, options: &[(String, String)]) -> ScaleResult<NABufferType> { |
| 271 | let mut debug = false; |
| 272 | for (name, value) in options.iter() { |
| 273 | match (name.as_str(), value.as_str()) { |
| 274 | ("debug", "") => { debug = true; }, |
| 275 | ("debug", "true") => { debug = true; }, |
| 276 | _ => {}, |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | //todo select output more fitting for dest_fmt if possible |
| 281 | self.ncomps = in_fmt.fmt.components as usize; |
| 282 | let mut chr: Vec<Option<NAPixelChromaton>> = Vec::with_capacity(MAX_CHROMATONS); |
| 283 | self.palstep = in_fmt.fmt.elem_size as usize; |
| 284 | for i in 0..self.ncomps { |
| 285 | let ichr = in_fmt.fmt.comp_info[i].unwrap(); |
| 286 | self.coffs[i] = ichr.comp_offs as usize; |
| 287 | self.depths[i] = ichr.depth; |
| 288 | let mut dchr = ichr; |
| 289 | dchr.packed = false; |
| 290 | dchr.depth = 8; |
| 291 | dchr.shift = 0; |
| 292 | dchr.comp_offs = i as u8; |
| 293 | dchr.next_elem = 0; |
| 294 | chr.push(Some(dchr)); |
| 295 | } |
| 296 | let mut df = in_fmt.fmt; |
| 297 | df.palette = false; |
| 298 | df.comp_info[..self.ncomps].clone_from_slice(&chr[..self.ncomps]); |
| 299 | if debug { |
| 300 | println!(" [intermediate format {}]", df); |
| 301 | } |
| 302 | let res = alloc_video_buffer(NAVideoInfo::new(in_fmt.width, in_fmt.height, false, df), 3); |
| 303 | if res.is_err() { return Err(ScaleError::AllocError); } |
| 304 | Ok(res.unwrap()) |
| 305 | } |
| 306 | fn process(&mut self, pic_in: &NABufferType, pic_out: &mut NABufferType) { |
| 307 | if let (Some(ref sbuf), Some(ref mut dbuf)) = (pic_in.get_vbuf(), pic_out.get_vbuf()) { |
| 308 | let ioff = sbuf.get_offset(0); |
| 309 | let paloff = sbuf.get_offset(1); |
| 310 | let (w, h) = sbuf.get_dimensions(0); |
| 311 | let istride = sbuf.get_stride(0); |
| 312 | let sdata1 = sbuf.get_data(); |
| 313 | let sdata = &sdata1[ioff..]; |
| 314 | let pal = &sdata1[paloff..]; |
| 315 | |
| 316 | let mut ostride: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 317 | let mut offs: [usize; MAX_CHROMATONS] = [0; MAX_CHROMATONS]; |
| 318 | for i in 0..self.ncomps { |
| 319 | ostride[i] = dbuf.get_stride(i); |
| 320 | offs[i] = dbuf.get_offset(i); |
| 321 | } |
| 322 | let dst = dbuf.get_data_mut().unwrap(); |
| 323 | for src in sdata.chunks(istride).take(h) { |
| 324 | for x in 0..w { |
| 325 | let palidx = src[x] as usize; |
| 326 | for i in 0..self.ncomps { |
| 327 | let elem = u32::from(pal[palidx * self.palstep + self.coffs[i]]); |
| 328 | dst[offs[i] + x] = convert_depth(elem, self.depths[i], 8) as u8; |
| 329 | } |
| 330 | } |
| 331 | for i in 0..self.ncomps { offs[i] += ostride[i]; } |
| 332 | } |
| 333 | } else { |
| 334 | unreachable!(); |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | pub fn create_depal() -> Box<dyn Kernel> { |
| 340 | Box::new(DepalKernel::new()) |
| 341 | } |