/rust/registry/src/index.crates.io-6f17d22bba15001f/v_frame-0.3.9/src/plane.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2017-2021, The rav1e contributors. All rights reserved |
2 | | // |
3 | | // This source code is subject to the terms of the BSD 2 Clause License and |
4 | | // the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
5 | | // was not distributed with this source code in the LICENSE file, you can |
6 | | // obtain it at www.aomedia.org/license/software. If the Alliance for Open |
7 | | // Media Patent License 1.0 was not distributed with this source code in the |
8 | | // PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
9 | | |
10 | | use std::fmt::{Debug, Display, Formatter}; |
11 | | use std::iter::{self, FusedIterator}; |
12 | | use std::marker::PhantomData; |
13 | | use std::mem::size_of; |
14 | | use std::ops::{Index, IndexMut, Range}; |
15 | | |
16 | | use aligned_vec::{ABox, AVec, ConstAlign}; |
17 | | |
18 | | use crate::math::*; |
19 | | use crate::pixel::*; |
20 | | |
21 | | #[cfg(feature = "serialize")] |
22 | | use serde::{Deserialize, Serialize}; |
23 | | |
24 | | /// Plane-specific configuration. |
25 | | #[derive(Debug, Clone, PartialEq, Eq)] |
26 | | #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] |
27 | | pub struct PlaneConfig { |
28 | | /// Data stride. |
29 | | pub stride: usize, |
30 | | /// Allocated height in pixels. |
31 | | pub alloc_height: usize, |
32 | | /// Width in pixels. |
33 | | pub width: usize, |
34 | | /// Height in pixels. |
35 | | pub height: usize, |
36 | | /// Decimator along the X axis. |
37 | | /// |
38 | | /// For example, for chroma planes in a 4:2:0 configuration this would be 1. |
39 | | pub xdec: usize, |
40 | | /// Decimator along the Y axis. |
41 | | /// |
42 | | /// For example, for chroma planes in a 4:2:0 configuration this would be 1. |
43 | | pub ydec: usize, |
44 | | /// Number of padding pixels on the right. |
45 | | pub xpad: usize, |
46 | | /// Number of padding pixels on the bottom. |
47 | | pub ypad: usize, |
48 | | /// X where the data starts. |
49 | | pub xorigin: usize, |
50 | | /// Y where the data starts. |
51 | | pub yorigin: usize, |
52 | | } |
53 | | |
54 | | impl PlaneConfig { |
55 | | /// Stride alignment in bytes. |
56 | | const STRIDE_ALIGNMENT_LOG2: usize = 6; |
57 | | |
58 | | #[inline] |
59 | 0 | pub fn new( |
60 | 0 | width: usize, |
61 | 0 | height: usize, |
62 | 0 | xdec: usize, |
63 | 0 | ydec: usize, |
64 | 0 | xpad: usize, |
65 | 0 | ypad: usize, |
66 | 0 | type_size: usize, |
67 | 0 | ) -> Self { |
68 | 0 | let xorigin = xpad.align_power_of_two(Self::STRIDE_ALIGNMENT_LOG2 + 1 - type_size); |
69 | 0 | let yorigin = ypad; |
70 | 0 | let stride = (xorigin + width + xpad) |
71 | 0 | .align_power_of_two(Self::STRIDE_ALIGNMENT_LOG2 + 1 - type_size); |
72 | 0 | let alloc_height = yorigin + height + ypad; |
73 | 0 |
|
74 | 0 | PlaneConfig { |
75 | 0 | stride, |
76 | 0 | alloc_height, |
77 | 0 | width, |
78 | 0 | height, |
79 | 0 | xdec, |
80 | 0 | ydec, |
81 | 0 | xpad, |
82 | 0 | ypad, |
83 | 0 | xorigin, |
84 | 0 | yorigin, |
85 | 0 | } |
86 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneConfig>::new Unexecuted instantiation: <v_frame::plane::PlaneConfig>::new Unexecuted instantiation: <v_frame::plane::PlaneConfig>::new |
87 | | } |
88 | | |
89 | | /// Absolute offset in pixels inside a plane |
90 | | #[derive(Clone, Copy, Debug, Default)] |
91 | | pub struct PlaneOffset { |
92 | | pub x: isize, |
93 | | pub y: isize, |
94 | | } |
95 | | |
96 | | /// Backing buffer for the Plane data |
97 | | /// |
98 | | /// The buffer is padded and aligned according to the architecture-specific |
99 | | /// SIMD constraints. |
100 | | #[derive(Debug, Clone, PartialEq, Eq)] |
101 | | #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] |
102 | | pub struct PlaneData<T: Pixel> { |
103 | | #[cfg(not(target_arch = "wasm32"))] |
104 | | data: ABox<[T], ConstAlign<{ 1 << 6 }>>, |
105 | | #[cfg(target_arch = "wasm32")] |
106 | | data: ABox<[T], ConstAlign<{ 1 << 3 }>>, |
107 | | } |
108 | | |
109 | | unsafe impl<T: Pixel + Send> Send for PlaneData<T> {} |
110 | | unsafe impl<T: Pixel + Sync> Sync for PlaneData<T> {} |
111 | | |
112 | | impl<T: Pixel> std::ops::Deref for PlaneData<T> { |
113 | | type Target = [T]; |
114 | | |
115 | 0 | fn deref(&self) -> &[T] { |
116 | 0 | self.data.as_ref() |
117 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneData<u16> as core::ops::deref::Deref>::deref Unexecuted instantiation: <v_frame::plane::PlaneData<u8> as core::ops::deref::Deref>::deref Unexecuted instantiation: <v_frame::plane::PlaneData<_> as core::ops::deref::Deref>::deref |
118 | | } |
119 | | |
120 | | impl<T: Pixel> std::ops::DerefMut for PlaneData<T> { |
121 | 0 | fn deref_mut(&mut self) -> &mut [T] { |
122 | 0 | self.data.as_mut() |
123 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneData<u8> as core::ops::deref::DerefMut>::deref_mut Unexecuted instantiation: <v_frame::plane::PlaneData<u16> as core::ops::deref::DerefMut>::deref_mut Unexecuted instantiation: <v_frame::plane::PlaneData<_> as core::ops::deref::DerefMut>::deref_mut |
124 | | } |
125 | | |
126 | | impl<T: Pixel> PlaneData<T> { |
127 | | #[cfg(target_arch = "wasm32")] |
128 | | // FIXME: wasm32 allocator fails for alignment larger than 3 |
129 | | const DATA_ALIGNMENT: usize = 1 << 3; |
130 | | #[cfg(not(target_arch = "wasm32"))] |
131 | | const DATA_ALIGNMENT: usize = 1 << 6; |
132 | | |
133 | 0 | pub fn new(len: usize) -> Self { |
134 | 0 | Self { |
135 | 0 | data: AVec::from_iter( |
136 | 0 | Self::DATA_ALIGNMENT, |
137 | 0 | iter::repeat(T::cast_from(128)).take(len), |
138 | 0 | ) |
139 | 0 | .into_boxed_slice(), |
140 | 0 | } |
141 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneData<u8>>::new Unexecuted instantiation: <v_frame::plane::PlaneData<u16>>::new Unexecuted instantiation: <v_frame::plane::PlaneData<_>>::new |
142 | | |
143 | 0 | fn from_slice(data: &[T]) -> Self { |
144 | 0 | Self { |
145 | 0 | data: AVec::from_slice(Self::DATA_ALIGNMENT, data).into_boxed_slice(), |
146 | 0 | } |
147 | 0 | } |
148 | | } |
149 | | |
150 | | /// One data plane of a frame. |
151 | | /// |
152 | | /// For example, a plane can be a Y luma plane or a U or V chroma plane. |
153 | | #[derive(Clone, PartialEq, Eq)] |
154 | | #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] |
155 | | pub struct Plane<T: Pixel> { |
156 | | // TODO: it is used by encoder to copy by plane and by tiling, make it |
157 | | // private again once tiling is moved and a copy_plane fn is added. |
158 | | // |
159 | | pub data: PlaneData<T>, |
160 | | /// Plane configuration. |
161 | | pub cfg: PlaneConfig, |
162 | | } |
163 | | |
164 | | impl<T: Pixel> Debug for Plane<T> |
165 | | where |
166 | | T: Display, |
167 | | { |
168 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
169 | 0 | write!( |
170 | 0 | f, |
171 | 0 | "Plane {{ data: [{}, ...], cfg: {:?} }}", |
172 | 0 | self.data[0], self.cfg |
173 | 0 | ) |
174 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u8> as core::fmt::Debug>::fmt Unexecuted instantiation: <v_frame::plane::Plane<_> as core::fmt::Debug>::fmt |
175 | | } |
176 | | |
177 | | impl<T: Pixel> Plane<T> { |
178 | | /// Allocates and returns a new plane. |
179 | 0 | pub fn new( |
180 | 0 | width: usize, |
181 | 0 | height: usize, |
182 | 0 | xdec: usize, |
183 | 0 | ydec: usize, |
184 | 0 | xpad: usize, |
185 | 0 | ypad: usize, |
186 | 0 | ) -> Self { |
187 | 0 | let cfg = PlaneConfig::new(width, height, xdec, ydec, xpad, ypad, size_of::<T>()); |
188 | 0 | let data = PlaneData::new(cfg.stride * cfg.alloc_height); |
189 | 0 |
|
190 | 0 | Plane { data, cfg } |
191 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u8>>::new Unexecuted instantiation: <v_frame::plane::Plane<u16>>::new Unexecuted instantiation: <v_frame::plane::Plane<_>>::new |
192 | | |
193 | | /// # Panics |
194 | | /// |
195 | | /// - If `len` is not a multiple of `stride` |
196 | 0 | pub fn from_slice(data: &[T], stride: usize) -> Self { |
197 | 0 | let len = data.len(); |
198 | 0 |
|
199 | 0 | assert!(len % stride == 0); |
200 | | |
201 | 0 | Self { |
202 | 0 | data: PlaneData::from_slice(data), |
203 | 0 | cfg: PlaneConfig { |
204 | 0 | stride, |
205 | 0 | alloc_height: len / stride, |
206 | 0 | width: stride, |
207 | 0 | height: len / stride, |
208 | 0 | xdec: 0, |
209 | 0 | ydec: 0, |
210 | 0 | xpad: 0, |
211 | 0 | ypad: 0, |
212 | 0 | xorigin: 0, |
213 | 0 | yorigin: 0, |
214 | 0 | }, |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | 0 | pub fn pad(&mut self, w: usize, h: usize) { |
219 | 0 | let xorigin = self.cfg.xorigin; |
220 | 0 | let yorigin = self.cfg.yorigin; |
221 | 0 | let stride = self.cfg.stride; |
222 | 0 | let alloc_height = self.cfg.alloc_height; |
223 | 0 | let width = (w + self.cfg.xdec) >> self.cfg.xdec; |
224 | 0 | let height = (h + self.cfg.ydec) >> self.cfg.ydec; |
225 | 0 |
|
226 | 0 | if xorigin > 0 { |
227 | 0 | for y in 0..height { |
228 | 0 | let base = (yorigin + y) * stride; |
229 | 0 | let fill_val = self.data[base + xorigin]; |
230 | 0 | for val in &mut self.data[base..base + xorigin] { |
231 | 0 | *val = fill_val; |
232 | 0 | } |
233 | | } |
234 | 0 | } |
235 | | |
236 | 0 | if xorigin + width < stride { |
237 | 0 | for y in 0..height { |
238 | 0 | let base = (yorigin + y) * stride + xorigin + width; |
239 | 0 | let fill_val = self.data[base - 1]; |
240 | 0 | for val in &mut self.data[base..base + stride - (xorigin + width)] { |
241 | 0 | *val = fill_val; |
242 | 0 | } |
243 | | } |
244 | 0 | } |
245 | | |
246 | 0 | if yorigin > 0 { |
247 | 0 | let (top, bottom) = self.data.split_at_mut(yorigin * stride); |
248 | 0 | let src = &bottom[..stride]; |
249 | 0 | for y in 0..yorigin { |
250 | 0 | let dst = &mut top[y * stride..(y + 1) * stride]; |
251 | 0 | dst.copy_from_slice(src); |
252 | 0 | } |
253 | 0 | } |
254 | | |
255 | 0 | if yorigin + height < self.cfg.alloc_height { |
256 | 0 | let (top, bottom) = self.data.split_at_mut((yorigin + height) * stride); |
257 | 0 | let src = &top[(yorigin + height - 1) * stride..]; |
258 | 0 | for y in 0..alloc_height - (yorigin + height) { |
259 | 0 | let dst = &mut bottom[y * stride..(y + 1) * stride]; |
260 | 0 | dst.copy_from_slice(src); |
261 | 0 | } |
262 | 0 | } |
263 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::pad Unexecuted instantiation: <v_frame::plane::Plane<u8>>::pad Unexecuted instantiation: <v_frame::plane::Plane<_>>::pad |
264 | | |
265 | | /// Minimally test that the plane has been padded. |
266 | 0 | pub fn probe_padding(&self, w: usize, h: usize) -> bool { |
267 | 0 | let PlaneConfig { |
268 | 0 | xorigin, |
269 | 0 | yorigin, |
270 | 0 | stride, |
271 | 0 | alloc_height, |
272 | 0 | xdec, |
273 | 0 | ydec, |
274 | 0 | .. |
275 | 0 | } = self.cfg; |
276 | 0 | let width = (w + xdec) >> xdec; |
277 | 0 | let height = (h + ydec) >> ydec; |
278 | 0 | let corner = (yorigin + height - 1) * stride + xorigin + width - 1; |
279 | 0 | let corner_value = self.data[corner]; |
280 | 0 |
|
281 | 0 | self.data[(yorigin + height) * stride - 1] == corner_value |
282 | 0 | && self.data[(alloc_height - 1) * stride + xorigin + width - 1] == corner_value |
283 | 0 | && self.data[alloc_height * stride - 1] == corner_value |
284 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::probe_padding Unexecuted instantiation: <v_frame::plane::Plane<u8>>::probe_padding Unexecuted instantiation: <v_frame::plane::Plane<_>>::probe_padding |
285 | | |
286 | 0 | pub fn slice(&self, po: PlaneOffset) -> PlaneSlice<'_, T> { |
287 | 0 | PlaneSlice { |
288 | 0 | plane: self, |
289 | 0 | x: po.x, |
290 | 0 | y: po.y, |
291 | 0 | } |
292 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::slice Unexecuted instantiation: <v_frame::plane::Plane<u8>>::slice Unexecuted instantiation: <v_frame::plane::Plane<_>>::slice |
293 | | |
294 | 0 | pub fn mut_slice(&mut self, po: PlaneOffset) -> PlaneMutSlice<'_, T> { |
295 | 0 | PlaneMutSlice { |
296 | 0 | plane: self, |
297 | 0 | x: po.x, |
298 | 0 | y: po.y, |
299 | 0 | } |
300 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::mut_slice Unexecuted instantiation: <v_frame::plane::Plane<u8>>::mut_slice Unexecuted instantiation: <v_frame::plane::Plane<_>>::mut_slice |
301 | | |
302 | | #[inline] |
303 | 0 | fn index(&self, x: usize, y: usize) -> usize { |
304 | 0 | (y + self.cfg.yorigin) * self.cfg.stride + (x + self.cfg.xorigin) |
305 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::index Unexecuted instantiation: <v_frame::plane::Plane<u8>>::index Unexecuted instantiation: <v_frame::plane::Plane<_>>::index |
306 | | |
307 | | /// This version of the function crops off the padding on the right side of the image |
308 | | #[inline] |
309 | 0 | pub fn row_range_cropped(&self, x: isize, y: isize) -> Range<usize> { |
310 | 0 | debug_assert!(self.cfg.yorigin as isize + y >= 0); |
311 | 0 | debug_assert!(self.cfg.xorigin as isize + x >= 0); |
312 | 0 | let base_y = (self.cfg.yorigin as isize + y) as usize; |
313 | 0 | let base_x = (self.cfg.xorigin as isize + x) as usize; |
314 | 0 | let base = base_y * self.cfg.stride + base_x; |
315 | 0 | let width = (self.cfg.width as isize - x) as usize; |
316 | 0 | base..base + width |
317 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::row_range_cropped Unexecuted instantiation: <v_frame::plane::Plane<u8>>::row_range_cropped Unexecuted instantiation: <v_frame::plane::Plane<_>>::row_range_cropped |
318 | | |
319 | | /// This version of the function includes the padding on the right side of the image |
320 | | #[inline] |
321 | 0 | pub fn row_range(&self, x: isize, y: isize) -> Range<usize> { |
322 | 0 | debug_assert!(self.cfg.yorigin as isize + y >= 0); |
323 | 0 | debug_assert!(self.cfg.xorigin as isize + x >= 0); |
324 | 0 | let base_y = (self.cfg.yorigin as isize + y) as usize; |
325 | 0 | let base_x = (self.cfg.xorigin as isize + x) as usize; |
326 | 0 | let base = base_y * self.cfg.stride + base_x; |
327 | 0 | let width = self.cfg.stride - base_x; |
328 | 0 | base..base + width |
329 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::row_range Unexecuted instantiation: <v_frame::plane::Plane<u8>>::row_range Unexecuted instantiation: <v_frame::plane::Plane<_>>::row_range |
330 | | |
331 | | /// Returns the pixel at the given coordinates. |
332 | 0 | pub fn p(&self, x: usize, y: usize) -> T { |
333 | 0 | self.data[self.index(x, y)] |
334 | 0 | } |
335 | | |
336 | | /// Returns plane data starting from the origin. |
337 | 0 | pub fn data_origin(&self) -> &[T] { |
338 | 0 | &self.data[self.index(0, 0)..] |
339 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::data_origin Unexecuted instantiation: <v_frame::plane::Plane<u8>>::data_origin Unexecuted instantiation: <v_frame::plane::Plane<_>>::data_origin |
340 | | |
341 | | /// Returns mutable plane data starting from the origin. |
342 | 0 | pub fn data_origin_mut(&mut self) -> &mut [T] { |
343 | 0 | let i = self.index(0, 0); |
344 | 0 | &mut self.data[i..] |
345 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u8>>::data_origin_mut Unexecuted instantiation: <v_frame::plane::Plane<_>>::data_origin_mut |
346 | | |
347 | | /// Copies data into the plane from a pixel array. |
348 | | /// |
349 | | /// # Panics |
350 | | /// |
351 | | /// - If `source_bytewidth` does not match the generic `T` of `Plane` |
352 | 0 | pub fn copy_from_raw_u8( |
353 | 0 | &mut self, |
354 | 0 | source: &[u8], |
355 | 0 | source_stride: usize, |
356 | 0 | source_bytewidth: usize, |
357 | 0 | ) { |
358 | 0 | let stride = self.cfg.stride; |
359 | 0 |
|
360 | 0 | assert!(stride != 0); |
361 | 0 | assert!(source_stride != 0); |
362 | | |
363 | 0 | for (self_row, source_row) in self |
364 | 0 | .data_origin_mut() |
365 | 0 | .chunks_exact_mut(stride) |
366 | 0 | .zip(source.chunks_exact(source_stride)) |
367 | | { |
368 | 0 | match source_bytewidth { |
369 | | 1 => { |
370 | 0 | for (self_pixel, source_pixel) in self_row.iter_mut().zip(source_row.iter()) { |
371 | 0 | *self_pixel = T::cast_from(*source_pixel); |
372 | 0 | } |
373 | | } |
374 | | 2 => { |
375 | 0 | assert!( |
376 | 0 | size_of::<T>() == 2, |
377 | 0 | "source bytewidth ({}) cannot fit in Plane<u8>", |
378 | | source_bytewidth |
379 | | ); |
380 | | |
381 | 0 | debug_assert!(T::type_enum() == PixelType::U16); |
382 | | |
383 | | // SAFETY: because of the assert it is safe to assume that T == u16 |
384 | 0 | let self_row: &mut [u16] = unsafe { std::mem::transmute(self_row) }; |
385 | 0 | // SAFETY: we reinterpret the slice of bytes as a slice of elements of |
386 | 0 | // [u8; 2] to allow for more efficient codegen with from_le_bytes |
387 | 0 | let source_row: &[[u8; 2]] = unsafe { |
388 | 0 | std::slice::from_raw_parts(source_row.as_ptr().cast(), source_row.len() / 2) |
389 | | }; |
390 | | |
391 | 0 | for (self_pixel, bytes) in self_row.iter_mut().zip(source_row) { |
392 | 0 | *self_pixel = u16::from_le_bytes(*bytes); |
393 | 0 | } |
394 | | } |
395 | | |
396 | 0 | _ => {} |
397 | | } |
398 | | } |
399 | 0 | } |
400 | | |
401 | | /// Copies data from a plane into a pixel array. |
402 | | /// |
403 | | /// # Panics |
404 | | /// |
405 | | /// - If `dest_bytewidth` does not match the generic `T` of `Plane` |
406 | 0 | pub fn copy_to_raw_u8(&self, dest: &mut [u8], dest_stride: usize, dest_bytewidth: usize) { |
407 | 0 | let stride = self.cfg.stride; |
408 | 0 | for (self_row, dest_row) in self |
409 | 0 | .data_origin() |
410 | 0 | .chunks_exact(stride) |
411 | 0 | .zip(dest.chunks_exact_mut(dest_stride)) |
412 | | { |
413 | 0 | match dest_bytewidth { |
414 | | 1 => { |
415 | 0 | for (self_pixel, dest_pixel) in |
416 | 0 | self_row[..self.cfg.width].iter().zip(dest_row.iter_mut()) |
417 | 0 | { |
418 | 0 | *dest_pixel = u8::cast_from(*self_pixel); |
419 | 0 | } |
420 | | } |
421 | | 2 => { |
422 | 0 | assert!( |
423 | 0 | size_of::<T>() >= 2, |
424 | 0 | "dest bytewidth ({}) cannot fit in Plane<u8>", |
425 | | dest_bytewidth |
426 | | ); |
427 | | |
428 | | // SAFETY: we reinterpret the slice of bytes as a slice |
429 | | // of [u8; 2] with half the elements |
430 | 0 | let dest_row: &mut [[u8; 2]] = unsafe { |
431 | 0 | std::slice::from_raw_parts_mut( |
432 | 0 | dest_row.as_mut_ptr().cast(), |
433 | 0 | dest_row.len() / 2, |
434 | 0 | ) |
435 | | }; |
436 | | |
437 | 0 | for (self_pixel, bytes) in self_row[..self.cfg.width].iter().zip(dest_row) { |
438 | 0 | *bytes = u16::cast_from(*self_pixel).to_le_bytes(); |
439 | 0 | } |
440 | | } |
441 | | |
442 | 0 | _ => {} |
443 | | } |
444 | | } |
445 | 0 | } |
446 | | |
447 | | /// Returns plane with half the resolution for width and height. |
448 | | /// Downscaled with 2x2 box filter. |
449 | | /// Padded to dimensions with `frame_width` and `frame_height`. |
450 | | /// |
451 | | /// # Panics |
452 | | /// |
453 | | /// - If the requested width and height are > half the input width or height |
454 | 0 | pub fn downsampled(&self, frame_width: usize, frame_height: usize) -> Plane<T> { |
455 | 0 | let src = self; |
456 | 0 | let mut new = Plane::new( |
457 | 0 | (src.cfg.width + 1) / 2, |
458 | 0 | (src.cfg.height + 1) / 2, |
459 | 0 | src.cfg.xdec + 1, |
460 | 0 | src.cfg.ydec + 1, |
461 | 0 | src.cfg.xpad / 2, |
462 | 0 | src.cfg.ypad / 2, |
463 | 0 | ); |
464 | 0 |
|
465 | 0 | let width = new.cfg.width; |
466 | 0 | let height = new.cfg.height; |
467 | 0 |
|
468 | 0 | assert!(width * 2 <= src.cfg.stride - src.cfg.xorigin); |
469 | 0 | assert!(height * 2 <= src.cfg.alloc_height - src.cfg.yorigin); |
470 | | |
471 | 0 | let data_origin = src.data_origin(); |
472 | 0 | for (row_idx, dst_row) in new |
473 | 0 | .mut_slice(PlaneOffset::default()) |
474 | 0 | .rows_iter_mut() |
475 | 0 | .enumerate() |
476 | 0 | .take(height) |
477 | | { |
478 | 0 | let src_top_row = &data_origin[(src.cfg.stride * row_idx * 2)..][..(2 * width)]; |
479 | 0 | let src_bottom_row = |
480 | 0 | &data_origin[(src.cfg.stride * (row_idx * 2 + 1))..][..(2 * width)]; |
481 | | |
482 | 0 | for ((dst, a), b) in dst_row |
483 | 0 | .iter_mut() |
484 | 0 | .zip(src_top_row.chunks_exact(2)) |
485 | 0 | .zip(src_bottom_row.chunks_exact(2)) |
486 | 0 | { |
487 | 0 | let sum = u32::cast_from(a[0]) |
488 | 0 | + u32::cast_from(a[1]) |
489 | 0 | + u32::cast_from(b[0]) |
490 | 0 | + u32::cast_from(b[1]); |
491 | 0 | let avg = (sum + 2) >> 2; |
492 | 0 | *dst = T::cast_from(avg); |
493 | 0 | } |
494 | | } |
495 | | |
496 | 0 | new.pad(frame_width, frame_height); |
497 | 0 | new |
498 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downsampled Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downsampled Unexecuted instantiation: <v_frame::plane::Plane<_>>::downsampled |
499 | | |
500 | | /// Returns a plane downscaled from the source plane by a factor of `scale` (not padded) |
501 | 0 | pub fn downscale<const SCALE: usize>(&self) -> Plane<T> { |
502 | 0 | let mut new_plane = Plane::new(self.cfg.width / SCALE, self.cfg.height / SCALE, 0, 0, 0, 0); |
503 | 0 |
|
504 | 0 | self.downscale_in_place::<SCALE>(&mut new_plane); |
505 | 0 |
|
506 | 0 | new_plane |
507 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<16> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<32> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<2> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<4> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<8> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<16> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<32> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<2> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<4> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<8> Unexecuted instantiation: <v_frame::plane::Plane<_>>::downscale::<_> |
508 | | |
509 | | /// Downscales the source plane by a factor of `scale`, writing the result to `in_plane` (not padded) |
510 | | /// |
511 | | /// # Panics |
512 | | /// |
513 | | /// - If the current plane's width and height are not at least `SCALE` times the `in_plane`'s |
514 | | #[cfg_attr(feature = "profiling", profiling::function(downscale_in_place))] |
515 | 0 | pub fn downscale_in_place<const SCALE: usize>(&self, in_plane: &mut Plane<T>) { |
516 | 0 | let stride = in_plane.cfg.stride; |
517 | 0 | let width = in_plane.cfg.width; |
518 | 0 | let height = in_plane.cfg.height; |
519 | 0 |
|
520 | 0 | if stride == 0 || self.cfg.stride == 0 { |
521 | 0 | panic!("stride cannot be 0"); |
522 | 0 | } |
523 | 0 |
|
524 | 0 | assert!(width * SCALE <= self.cfg.stride - self.cfg.xorigin); |
525 | 0 | assert!(height * SCALE <= self.cfg.alloc_height - self.cfg.yorigin); |
526 | | |
527 | | // SAFETY: Bounds checks have been removed for performance reasons |
528 | | unsafe { |
529 | 0 | let src = self; |
530 | 0 | let box_pixels = SCALE * SCALE; |
531 | 0 | let half_box_pixels = box_pixels as u32 / 2; // Used for rounding int division |
532 | 0 |
|
533 | 0 | let data_origin = src.data_origin(); |
534 | 0 | let plane_data_mut_slice = &mut *in_plane.data; |
535 | | |
536 | | // Iter dst rows |
537 | 0 | for row_idx in 0..height { |
538 | 0 | let dst_row = plane_data_mut_slice.get_unchecked_mut(row_idx * stride..); |
539 | | // Iter dst cols |
540 | 0 | for (col_idx, dst) in dst_row.get_unchecked_mut(..width).iter_mut().enumerate() { |
541 | | macro_rules! generate_inner_loop { |
542 | | ($x:ty) => { |
543 | | let mut sum = half_box_pixels as $x; |
544 | | // Sum box of size scale * scale |
545 | | |
546 | | // Iter src row |
547 | | for y in 0..SCALE { |
548 | | let src_row_idx = row_idx * SCALE + y; |
549 | | let src_row = |
550 | | data_origin.get_unchecked((src_row_idx * src.cfg.stride)..); |
551 | | |
552 | | // Iter src col |
553 | | for x in 0..SCALE { |
554 | | let src_col_idx = col_idx * SCALE + x; |
555 | | sum += <$x>::cast_from(*src_row.get_unchecked(src_col_idx)); |
556 | | } |
557 | | } |
558 | | |
559 | | // Box average |
560 | | let avg = sum as usize / box_pixels; |
561 | | *dst = T::cast_from(avg); |
562 | | }; |
563 | | } |
564 | | |
565 | | // Use 16 bit precision if overflow would not happen |
566 | 0 | if T::type_enum() == PixelType::U8 |
567 | 0 | && SCALE as u128 * SCALE as u128 * (u8::MAX as u128) |
568 | 0 | + half_box_pixels as u128 |
569 | 0 | <= u16::MAX as u128 |
570 | | { |
571 | 0 | generate_inner_loop!(u16); |
572 | | } else { |
573 | 0 | generate_inner_loop!(u32); |
574 | | } |
575 | | } |
576 | | } |
577 | | } |
578 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<16> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<32> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<2> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<4> Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<8> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<16> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<32> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<2> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<4> Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<8> Unexecuted instantiation: <v_frame::plane::Plane<_>>::downscale_in_place::<_> |
579 | | |
580 | | /// Iterates over the pixels in the plane, skipping the padding. |
581 | 0 | pub fn iter(&self) -> PlaneIter<'_, T> { |
582 | 0 | PlaneIter::new(self) |
583 | 0 | } |
584 | | |
585 | | /// Iterates over the lines of the plane |
586 | 0 | pub fn rows_iter(&self) -> RowsIter<'_, T> { |
587 | 0 | RowsIter { |
588 | 0 | plane: self, |
589 | 0 | x: 0, |
590 | 0 | y: 0, |
591 | 0 | } |
592 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::rows_iter Unexecuted instantiation: <v_frame::plane::Plane<u8>>::rows_iter Unexecuted instantiation: <v_frame::plane::Plane<_>>::rows_iter |
593 | | |
594 | 0 | pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> { |
595 | 0 | RowsIterMut { |
596 | 0 | plane: self as *mut Plane<T>, |
597 | 0 | x: 0, |
598 | 0 | y: 0, |
599 | 0 | phantom: PhantomData, |
600 | 0 | } |
601 | 0 | } |
602 | | |
603 | | /// Return a line |
604 | 0 | pub fn row(&self, y: isize) -> &[T] { |
605 | 0 | let range = self.row_range(0, y); |
606 | 0 |
|
607 | 0 | &self.data[range] |
608 | 0 | } Unexecuted instantiation: <v_frame::plane::Plane<u16>>::row Unexecuted instantiation: <v_frame::plane::Plane<u8>>::row Unexecuted instantiation: <v_frame::plane::Plane<_>>::row |
609 | | } |
610 | | |
611 | | /// Iterator over plane pixels, skipping padding. |
612 | | #[derive(Debug)] |
613 | | pub struct PlaneIter<'a, T: Pixel> { |
614 | | plane: &'a Plane<T>, |
615 | | y: usize, |
616 | | x: usize, |
617 | | } |
618 | | |
619 | | impl<'a, T: Pixel> PlaneIter<'a, T> { |
620 | | /// Creates a new iterator. |
621 | 0 | pub fn new(plane: &'a Plane<T>) -> Self { |
622 | 0 | Self { plane, y: 0, x: 0 } |
623 | 0 | } |
624 | | |
625 | 0 | fn width(&self) -> usize { |
626 | 0 | self.plane.cfg.width |
627 | 0 | } |
628 | | |
629 | 0 | fn height(&self) -> usize { |
630 | 0 | self.plane.cfg.height |
631 | 0 | } |
632 | | } |
633 | | |
634 | | impl<T: Pixel> Iterator for PlaneIter<'_, T> { |
635 | | type Item = T; |
636 | | |
637 | 0 | fn next(&mut self) -> Option<<Self as Iterator>::Item> { |
638 | 0 | if self.y == self.height() { |
639 | 0 | return None; |
640 | 0 | } |
641 | 0 | let pixel = self.plane.p(self.x, self.y); |
642 | 0 | if self.x == self.width() - 1 { |
643 | 0 | self.x = 0; |
644 | 0 | self.y += 1; |
645 | 0 | } else { |
646 | 0 | self.x += 1; |
647 | 0 | } |
648 | 0 | Some(pixel) |
649 | 0 | } |
650 | | } |
651 | | |
652 | | impl<T: Pixel> FusedIterator for PlaneIter<'_, T> {} |
653 | | |
654 | | // A Plane, PlaneSlice, or PlaneRegion is assumed to include or be able to include |
655 | | // padding on the edge of the frame |
656 | | #[derive(Clone, Copy, Debug)] |
657 | | pub struct PlaneSlice<'a, T: Pixel> { |
658 | | pub plane: &'a Plane<T>, |
659 | | pub x: isize, |
660 | | pub y: isize, |
661 | | } |
662 | | |
663 | | // A RowsIter or RowsIterMut is assumed to crop the padding from the frame edges |
664 | | pub struct RowsIter<'a, T: Pixel> { |
665 | | plane: &'a Plane<T>, |
666 | | x: isize, |
667 | | y: isize, |
668 | | } |
669 | | |
670 | | impl<'a, T: Pixel> Iterator for RowsIter<'a, T> { |
671 | | type Item = &'a [T]; |
672 | | |
673 | 0 | fn next(&mut self) -> Option<Self::Item> { |
674 | 0 | if self.plane.cfg.height as isize > self.y { |
675 | | // cannot directly return self.ps.row(row) due to lifetime issue |
676 | 0 | let range = self.plane.row_range_cropped(self.x, self.y); |
677 | 0 | self.y += 1; |
678 | 0 | Some(&self.plane.data[range]) |
679 | | } else { |
680 | 0 | None |
681 | | } |
682 | 0 | } Unexecuted instantiation: <v_frame::plane::RowsIter<u16> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <v_frame::plane::RowsIter<u8> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <v_frame::plane::RowsIter<_> as core::iter::traits::iterator::Iterator>::next |
683 | | |
684 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
685 | 0 | let remaining = self.plane.cfg.height as isize - self.y; |
686 | 0 | debug_assert!(remaining >= 0); |
687 | 0 | let remaining = remaining as usize; |
688 | 0 |
|
689 | 0 | (remaining, Some(remaining)) |
690 | 0 | } |
691 | | } |
692 | | |
693 | | impl<T: Pixel> ExactSizeIterator for RowsIter<'_, T> {} |
694 | | impl<T: Pixel> FusedIterator for RowsIter<'_, T> {} |
695 | | |
696 | | impl<'a, T: Pixel> PlaneSlice<'a, T> { |
697 | | #[allow(unused)] |
698 | 0 | pub fn as_ptr(&self) -> *const T { |
699 | 0 | self[0].as_ptr() |
700 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::as_ptr Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::as_ptr Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::as_ptr |
701 | | |
702 | 0 | pub fn rows_iter(&self) -> RowsIter<'_, T> { |
703 | 0 | RowsIter { |
704 | 0 | plane: self.plane, |
705 | 0 | x: self.x, |
706 | 0 | y: self.y, |
707 | 0 | } |
708 | 0 | } |
709 | | |
710 | 0 | pub fn clamp(&self) -> PlaneSlice<'a, T> { |
711 | 0 | PlaneSlice { |
712 | 0 | plane: self.plane, |
713 | 0 | x: self.x.clamp( |
714 | 0 | -(self.plane.cfg.xorigin as isize), |
715 | 0 | self.plane.cfg.width as isize, |
716 | 0 | ), |
717 | 0 | y: self.y.clamp( |
718 | 0 | -(self.plane.cfg.yorigin as isize), |
719 | 0 | self.plane.cfg.height as isize, |
720 | 0 | ), |
721 | 0 | } |
722 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::clamp Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::clamp Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::clamp |
723 | | |
724 | 0 | pub fn subslice(&self, xo: usize, yo: usize) -> PlaneSlice<'a, T> { |
725 | 0 | PlaneSlice { |
726 | 0 | plane: self.plane, |
727 | 0 | x: self.x + xo as isize, |
728 | 0 | y: self.y + yo as isize, |
729 | 0 | } |
730 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::subslice Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::subslice Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::subslice |
731 | | |
732 | 0 | pub fn reslice(&self, xo: isize, yo: isize) -> PlaneSlice<'a, T> { |
733 | 0 | PlaneSlice { |
734 | 0 | plane: self.plane, |
735 | 0 | x: self.x + xo, |
736 | 0 | y: self.y + yo, |
737 | 0 | } |
738 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::reslice Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::reslice Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::reslice |
739 | | |
740 | | /// A slice starting i pixels above the current one. |
741 | 0 | pub fn go_up(&self, i: usize) -> PlaneSlice<'a, T> { |
742 | 0 | PlaneSlice { |
743 | 0 | plane: self.plane, |
744 | 0 | x: self.x, |
745 | 0 | y: self.y - i as isize, |
746 | 0 | } |
747 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::go_up Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::go_up Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::go_up |
748 | | |
749 | | /// A slice starting i pixels to the left of the current one. |
750 | 0 | pub fn go_left(&self, i: usize) -> PlaneSlice<'a, T> { |
751 | 0 | PlaneSlice { |
752 | 0 | plane: self.plane, |
753 | 0 | x: self.x - i as isize, |
754 | 0 | y: self.y, |
755 | 0 | } |
756 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::go_left Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::go_left Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::go_left |
757 | | |
758 | 0 | pub fn p(&self, add_x: usize, add_y: usize) -> T { |
759 | 0 | let new_y = (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize; |
760 | 0 | let new_x = (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize; |
761 | 0 | self.plane.data[new_y * self.plane.cfg.stride + new_x] |
762 | 0 | } |
763 | | |
764 | | /// Checks if `add_y` and `add_x` lies in the allocated bounds of the |
765 | | /// underlying plane. |
766 | 0 | pub fn accessible(&self, add_x: usize, add_y: usize) -> bool { |
767 | 0 | let y = (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize; |
768 | 0 | let x = (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize; |
769 | 0 | y < self.plane.cfg.alloc_height && x < self.plane.cfg.stride |
770 | 0 | } |
771 | | |
772 | | /// Checks if -`sub_x` and -`sub_y` lies in the allocated bounds of the |
773 | | /// underlying plane. |
774 | 0 | pub fn accessible_neg(&self, sub_x: usize, sub_y: usize) -> bool { |
775 | 0 | let y = self.y - sub_y as isize + self.plane.cfg.yorigin as isize; |
776 | 0 | let x = self.x - sub_x as isize + self.plane.cfg.xorigin as isize; |
777 | 0 | y >= 0 && x >= 0 |
778 | 0 | } |
779 | | |
780 | | /// This version of the function crops off the padding on the right side of the image |
781 | 0 | pub fn row_cropped(&self, y: usize) -> &[T] { |
782 | 0 | let y = (self.y + y as isize + self.plane.cfg.yorigin as isize) as usize; |
783 | 0 | let x = (self.x + self.plane.cfg.xorigin as isize) as usize; |
784 | 0 | let start = y * self.plane.cfg.stride + x; |
785 | 0 | let width = (self.plane.cfg.width as isize - self.x) as usize; |
786 | 0 | &self.plane.data[start..start + width] |
787 | 0 | } |
788 | | |
789 | | /// This version of the function includes the padding on the right side of the image |
790 | 0 | pub fn row(&self, y: usize) -> &[T] { |
791 | 0 | let y = (self.y + y as isize + self.plane.cfg.yorigin as isize) as usize; |
792 | 0 | let x = (self.x + self.plane.cfg.xorigin as isize) as usize; |
793 | 0 | let start = y * self.plane.cfg.stride + x; |
794 | 0 | let width = self.plane.cfg.stride - x; |
795 | 0 | &self.plane.data[start..start + width] |
796 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::row Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::row Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::row |
797 | | } |
798 | | |
799 | | impl<T: Pixel> Index<usize> for PlaneSlice<'_, T> { |
800 | | type Output = [T]; |
801 | 0 | fn index(&self, index: usize) -> &Self::Output { |
802 | 0 | let range = self.plane.row_range(self.x, self.y + index as isize); |
803 | 0 | &self.plane.data[range] |
804 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16> as core::ops::index::Index<usize>>::index Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8> as core::ops::index::Index<usize>>::index Unexecuted instantiation: <v_frame::plane::PlaneSlice<_> as core::ops::index::Index<usize>>::index |
805 | | } |
806 | | |
807 | | pub struct PlaneMutSlice<'a, T: Pixel> { |
808 | | pub plane: &'a mut Plane<T>, |
809 | | pub x: isize, |
810 | | pub y: isize, |
811 | | } |
812 | | |
813 | | pub struct RowsIterMut<'a, T: Pixel> { |
814 | | plane: *mut Plane<T>, |
815 | | x: isize, |
816 | | y: isize, |
817 | | phantom: PhantomData<&'a mut Plane<T>>, |
818 | | } |
819 | | |
820 | | impl<'a, T: Pixel> Iterator for RowsIterMut<'a, T> { |
821 | | type Item = &'a mut [T]; |
822 | | |
823 | 0 | fn next(&mut self) -> Option<Self::Item> { |
824 | 0 | // SAFETY: there could not be a concurrent call using a mutable reference to the plane |
825 | 0 | let plane = unsafe { &mut *self.plane }; |
826 | 0 | if plane.cfg.height as isize > self.y { |
827 | | // cannot directly return self.ps.row(row) due to lifetime issue |
828 | 0 | let range = plane.row_range_cropped(self.x, self.y); |
829 | 0 | self.y += 1; |
830 | 0 | Some(&mut plane.data[range]) |
831 | | } else { |
832 | 0 | None |
833 | | } |
834 | 0 | } Unexecuted instantiation: <v_frame::plane::RowsIterMut<u16> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <v_frame::plane::RowsIterMut<u8> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <v_frame::plane::RowsIterMut<_> as core::iter::traits::iterator::Iterator>::next |
835 | | |
836 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
837 | 0 | // SAFETY: there could not be a concurrent call using a mutable reference to the plane |
838 | 0 | let plane = unsafe { &mut *self.plane }; |
839 | 0 | let remaining = plane.cfg.height as isize - self.y; |
840 | 0 | debug_assert!(remaining >= 0); |
841 | 0 | let remaining = remaining as usize; |
842 | 0 |
|
843 | 0 | (remaining, Some(remaining)) |
844 | 0 | } |
845 | | } |
846 | | |
847 | | impl<T: Pixel> ExactSizeIterator for RowsIterMut<'_, T> {} |
848 | | impl<T: Pixel> FusedIterator for RowsIterMut<'_, T> {} |
849 | | |
850 | | impl<T: Pixel> PlaneMutSlice<'_, T> { |
851 | | #[allow(unused)] |
852 | 0 | pub fn rows_iter(&self) -> RowsIter<'_, T> { |
853 | 0 | RowsIter { |
854 | 0 | plane: self.plane, |
855 | 0 | x: self.x, |
856 | 0 | y: self.y, |
857 | 0 | } |
858 | 0 | } |
859 | | |
860 | 0 | pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> { |
861 | 0 | RowsIterMut { |
862 | 0 | plane: self.plane as *mut Plane<T>, |
863 | 0 | x: self.x, |
864 | 0 | y: self.y, |
865 | 0 | phantom: PhantomData, |
866 | 0 | } |
867 | 0 | } Unexecuted instantiation: <v_frame::plane::PlaneMutSlice<u16>>::rows_iter_mut Unexecuted instantiation: <v_frame::plane::PlaneMutSlice<u8>>::rows_iter_mut Unexecuted instantiation: <v_frame::plane::PlaneMutSlice<_>>::rows_iter_mut |
868 | | |
869 | | #[allow(unused)] |
870 | 0 | pub fn subslice(&mut self, xo: usize, yo: usize) -> PlaneMutSlice<'_, T> { |
871 | 0 | PlaneMutSlice { |
872 | 0 | plane: self.plane, |
873 | 0 | x: self.x + xo as isize, |
874 | 0 | y: self.y + yo as isize, |
875 | 0 | } |
876 | 0 | } |
877 | | } |
878 | | |
879 | | impl<T: Pixel> Index<usize> for PlaneMutSlice<'_, T> { |
880 | | type Output = [T]; |
881 | 0 | fn index(&self, index: usize) -> &Self::Output { |
882 | 0 | let range = self.plane.row_range(self.x, self.y + index as isize); |
883 | 0 | &self.plane.data[range] |
884 | 0 | } |
885 | | } |
886 | | |
887 | | impl<T: Pixel> IndexMut<usize> for PlaneMutSlice<'_, T> { |
888 | 0 | fn index_mut(&mut self, index: usize) -> &mut Self::Output { |
889 | 0 | let range = self.plane.row_range(self.x, self.y + index as isize); |
890 | 0 | &mut self.plane.data[range] |
891 | 0 | } |
892 | | } |
893 | | |
894 | | #[cfg(test)] |
895 | | pub mod test { |
896 | | use super::*; |
897 | | |
898 | | #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] |
899 | | use wasm_bindgen_test::*; |
900 | | |
901 | | #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] |
902 | | wasm_bindgen_test_configure!(run_in_browser); |
903 | | |
904 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
905 | | #[test] |
906 | | fn copy_from_raw_u8() { |
907 | | #[rustfmt::skip] |
908 | | let mut plane = Plane::from_slice(&[ |
909 | | 0, 0, 0, 0, 0, 0, 0, 0, |
910 | | 0, 0, 0, 0, 0, 0, 0, 0, |
911 | | 0, 0, 0, 0, 0, 0, 0, 0, |
912 | | 0, 0, 1, 2, 3, 4, 0, 0, |
913 | | 0, 0, 8, 7, 6, 5, 0, 0, |
914 | | 0, 0, 9, 8, 7, 6, 0, 0, |
915 | | 0, 0, 2, 3, 4, 5, 0, 0, |
916 | | 0, 0, 0, 0, 0, 0, 0, 0, |
917 | | 0, 0, 0, 0, 0, 0, 0, 0, |
918 | | ], 8); |
919 | | |
920 | | let input = vec![42u8; 64]; |
921 | | |
922 | | plane.copy_from_raw_u8(&input, 8, 1); |
923 | | |
924 | | println!("{:?}", &plane.data[..10]); |
925 | | |
926 | | assert_eq!(&input[..64], &plane.data[..64]); |
927 | | } |
928 | | |
929 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
930 | | #[test] |
931 | | fn copy_to_raw_u8() { |
932 | | #[rustfmt::skip] |
933 | | let plane = Plane::from_slice(&[ |
934 | | 0, 0, 0, 0, 0, 0, 0, 0, |
935 | | 0, 0, 0, 0, 0, 0, 0, 0, |
936 | | 0, 0, 0, 0, 0, 0, 0, 0, |
937 | | 0, 0, 1, 2, 3, 4, 0, 0, |
938 | | 0, 0, 8, 7, 6, 5, 0, 0, |
939 | | 0, 0, 9, 8, 7, 6, 0, 0, |
940 | | 0, 0, 2, 3, 4, 5, 0, 0, |
941 | | 0, 0, 0, 0, 0, 0, 0, 0, |
942 | | 0, 0, 0, 0, 0, 0, 0, 0, |
943 | | ], 8); |
944 | | |
945 | | let mut output = vec![42u8; 64]; |
946 | | |
947 | | plane.copy_to_raw_u8(&mut output, 8, 1); |
948 | | |
949 | | println!("{:?}", &plane.data[..10]); |
950 | | |
951 | | assert_eq!(&output[..64], &plane.data[..64]); |
952 | | } |
953 | | |
954 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
955 | | #[test] |
956 | | fn test_plane_downsample() { |
957 | | #[rustfmt::skip] |
958 | | let plane = Plane::<u8> { |
959 | | data: PlaneData::from_slice(&[ |
960 | | 0, 0, 0, 0, 0, 0, 0, 0, |
961 | | 0, 0, 0, 0, 0, 0, 0, 0, |
962 | | 0, 0, 0, 0, 0, 0, 0, 0, |
963 | | 0, 0, 1, 2, 3, 4, 0, 0, |
964 | | 0, 0, 8, 7, 6, 5, 0, 0, |
965 | | 0, 0, 9, 8, 7, 6, 0, 0, |
966 | | 0, 0, 2, 3, 4, 5, 0, 0, |
967 | | 0, 0, 0, 0, 0, 0, 0, 0, |
968 | | 0, 0, 0, 0, 0, 0, 0, 0, |
969 | | ]), |
970 | | cfg: PlaneConfig { |
971 | | stride: 8, |
972 | | alloc_height: 9, |
973 | | width: 4, |
974 | | height: 4, |
975 | | xdec: 0, |
976 | | ydec: 0, |
977 | | xpad: 0, |
978 | | ypad: 0, |
979 | | xorigin: 2, |
980 | | yorigin: 3, |
981 | | }, |
982 | | }; |
983 | | let downsampled = plane.downsampled(4, 4); |
984 | | |
985 | | #[rustfmt::skip] |
986 | | let expected = &[ |
987 | | 5, 5, |
988 | | 6, 6, |
989 | | ]; |
990 | | |
991 | | let v: Vec<_> = downsampled.iter().collect(); |
992 | | |
993 | | assert_eq!(&expected[..], &v[..]); |
994 | | } |
995 | | |
996 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
997 | | #[test] |
998 | | fn test_plane_downsample_odd() { |
999 | | #[rustfmt::skip] |
1000 | | let plane = Plane::<u8> { |
1001 | | data: PlaneData::from_slice(&[ |
1002 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1003 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1004 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1005 | | 0, 0, 1, 2, 3, 4, 0, 0, |
1006 | | 0, 0, 8, 7, 6, 5, 0, 0, |
1007 | | 0, 0, 9, 8, 7, 6, 0, 0, |
1008 | | 0, 0, 2, 3, 4, 5, 0, 0, |
1009 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1010 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1011 | | ]), |
1012 | | cfg: PlaneConfig { |
1013 | | stride: 8, |
1014 | | alloc_height: 9, |
1015 | | width: 3, |
1016 | | height: 3, |
1017 | | xdec: 0, |
1018 | | ydec: 0, |
1019 | | xpad: 0, |
1020 | | ypad: 0, |
1021 | | xorigin: 2, |
1022 | | yorigin: 3, |
1023 | | }, |
1024 | | }; |
1025 | | let downsampled = plane.downsampled(3, 3); |
1026 | | |
1027 | | #[rustfmt::skip] |
1028 | | let expected = &[ |
1029 | | 5, 5, |
1030 | | 6, 6, |
1031 | | ]; |
1032 | | |
1033 | | let v: Vec<_> = downsampled.iter().collect(); |
1034 | | assert_eq!(&expected[..], &v[..]); |
1035 | | } |
1036 | | |
1037 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
1038 | | #[test] |
1039 | | fn test_plane_downscale() { |
1040 | | #[rustfmt::skip] |
1041 | | let plane = Plane::<u8> { |
1042 | | data: PlaneData::from_slice(&[ |
1043 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1044 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1045 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1046 | | 0, 0, 0, 1, 4, 5, 0, 0, |
1047 | | 0, 0, 2, 3, 6, 7, 0, 0, |
1048 | | 0, 0, 8, 9, 7, 5, 0, 0, |
1049 | | 0, 0, 9, 8, 3, 1, 0, 0, |
1050 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1051 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1052 | | ]), |
1053 | | cfg: PlaneConfig { |
1054 | | stride: 8, |
1055 | | alloc_height: 9, |
1056 | | width: 4, |
1057 | | height: 4, |
1058 | | xdec: 0, |
1059 | | ydec: 0, |
1060 | | xpad: 0, |
1061 | | ypad: 0, |
1062 | | xorigin: 2, |
1063 | | yorigin: 3, |
1064 | | }, |
1065 | | }; |
1066 | | let downscaled = plane.downscale::<2>(); |
1067 | | |
1068 | | #[rustfmt::skip] |
1069 | | let expected = &[ |
1070 | | 2, 6, |
1071 | | 9, 4 |
1072 | | ]; |
1073 | | |
1074 | | let v: Vec<_> = downscaled.iter().collect(); |
1075 | | assert_eq!(&expected[..], &v[..]); |
1076 | | } |
1077 | | |
1078 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
1079 | | #[test] |
1080 | | fn test_plane_downscale_odd() { |
1081 | | #[rustfmt::skip] |
1082 | | let plane = Plane::<u8> { |
1083 | | data: PlaneData::from_slice(&[ |
1084 | | 1, 2, 3, 4, 1, 2, 3, 4, |
1085 | | 0, 0, 8, 7, 6, 5, 8, 7, |
1086 | | 6, 5, 8, 7, 6, 5, 8, 7, |
1087 | | 6, 5, 8, 7, 0, 0, 2, 3, |
1088 | | 4, 5, 0, 0, 9, 8, 7, 6, |
1089 | | 0, 0, 0, 0, 2, 3, 4, 5, |
1090 | | 0, 0, 0, 0, 2, 3, 4, 5, |
1091 | | ]), |
1092 | | cfg: PlaneConfig { |
1093 | | stride: 8, |
1094 | | alloc_height: 7, |
1095 | | width: 8, |
1096 | | height: 7, |
1097 | | xdec: 0, |
1098 | | ydec: 0, |
1099 | | xpad: 0, |
1100 | | ypad: 0, |
1101 | | xorigin: 0, |
1102 | | yorigin: 0, |
1103 | | }, |
1104 | | }; |
1105 | | |
1106 | | let downscaled = plane.downscale::<3>(); |
1107 | | |
1108 | | #[rustfmt::skip] |
1109 | | let expected = &[ |
1110 | | 4, 5, |
1111 | | 3, 3 |
1112 | | ]; |
1113 | | |
1114 | | let v: Vec<_> = downscaled.iter().collect(); |
1115 | | assert_eq!(&expected[..], &v[..]); |
1116 | | } |
1117 | | |
1118 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
1119 | | #[test] |
1120 | | fn test_plane_downscale_odd_2() { |
1121 | | #[rustfmt::skip] |
1122 | | let plane = Plane::<u8> { |
1123 | | data: PlaneData::from_slice(&[ |
1124 | | 9, 8, 3, 1, 0, 1, 4, 5, 0, 0, |
1125 | | 0, 1, 4, 5, 0, 0, 0, 0, 0, 0, |
1126 | | 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, |
1127 | | 0, 2, 3, 6, 7, 0, 0, 0, 0, 0, |
1128 | | 0, 0, 8, 9, 7, 5, 0, 0, 0, 0, |
1129 | | 9, 8, 3, 1, 0, 1, 4, 5, 0, 0, |
1130 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
1131 | | 0, 0, 0, 0, 0, 2, 3, 6, 7, 0, |
1132 | | 0, 0, 0, 0, 0, 0, 8, 9, 7, 5, |
1133 | | 0, 0, 0, 0, 9, 8, 3, 1, 0, 0 |
1134 | | ]), |
1135 | | cfg: PlaneConfig { |
1136 | | stride: 10, |
1137 | | alloc_height: 10, |
1138 | | width: 10, |
1139 | | height: 10, |
1140 | | xdec: 0, |
1141 | | ydec: 0, |
1142 | | xpad: 0, |
1143 | | ypad: 0, |
1144 | | xorigin: 0, |
1145 | | yorigin: 0, |
1146 | | }, |
1147 | | }; |
1148 | | let downscaled = plane.downscale::<3>(); |
1149 | | |
1150 | | #[rustfmt::skip] |
1151 | | let expected = &[ |
1152 | | 3, 1, 2, |
1153 | | 4, 4, 1, |
1154 | | 0, 0, 4, |
1155 | | ]; |
1156 | | |
1157 | | let v: Vec<_> = downscaled.iter().collect(); |
1158 | | assert_eq!(&expected[..], &v[..]); |
1159 | | } |
1160 | | |
1161 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
1162 | | #[test] |
1163 | | fn test_plane_pad() { |
1164 | | #[rustfmt::skip] |
1165 | | let mut plane = Plane::<u8> { |
1166 | | data: PlaneData::from_slice(&[ |
1167 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1168 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1169 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1170 | | 0, 0, 1, 2, 3, 4, 0, 0, |
1171 | | 0, 0, 8, 7, 6, 5, 0, 0, |
1172 | | 0, 0, 9, 8, 7, 6, 0, 0, |
1173 | | 0, 0, 2, 3, 4, 5, 0, 0, |
1174 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1175 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1176 | | ]), |
1177 | | cfg: PlaneConfig { |
1178 | | stride: 8, |
1179 | | alloc_height: 9, |
1180 | | width: 4, |
1181 | | height: 4, |
1182 | | xdec: 0, |
1183 | | ydec: 0, |
1184 | | xpad: 0, |
1185 | | ypad: 0, |
1186 | | xorigin: 2, |
1187 | | yorigin: 3, |
1188 | | }, |
1189 | | }; |
1190 | | plane.pad(4, 4); |
1191 | | |
1192 | | #[rustfmt::skip] |
1193 | | assert_eq!(&[ |
1194 | | 1, 1, 1, 2, 3, 4, 4, 4, |
1195 | | 1, 1, 1, 2, 3, 4, 4, 4, |
1196 | | 1, 1, 1, 2, 3, 4, 4, 4, |
1197 | | 1, 1, 1, 2, 3, 4, 4, 4, |
1198 | | 8, 8, 8, 7, 6, 5, 5, 5, |
1199 | | 9, 9, 9, 8, 7, 6, 6, 6, |
1200 | | 2, 2, 2, 3, 4, 5, 5, 5, |
1201 | | 2, 2, 2, 3, 4, 5, 5, 5, |
1202 | | 2, 2, 2, 3, 4, 5, 5, 5, |
1203 | | ], &plane.data[..]); |
1204 | | } |
1205 | | |
1206 | | #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)] |
1207 | | #[test] |
1208 | | fn test_pixel_iterator() { |
1209 | | #[rustfmt::skip] |
1210 | | let plane = Plane::<u8> { |
1211 | | data: PlaneData::from_slice(&[ |
1212 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1213 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1214 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1215 | | 0, 0, 1, 2, 3, 4, 0, 0, |
1216 | | 0, 0, 8, 7, 6, 5, 0, 0, |
1217 | | 0, 0, 9, 8, 7, 6, 0, 0, |
1218 | | 0, 0, 2, 3, 4, 5, 0, 0, |
1219 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1220 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1221 | | ]), |
1222 | | cfg: PlaneConfig { |
1223 | | stride: 8, |
1224 | | alloc_height: 9, |
1225 | | width: 4, |
1226 | | height: 4, |
1227 | | xdec: 0, |
1228 | | ydec: 0, |
1229 | | xpad: 0, |
1230 | | ypad: 0, |
1231 | | xorigin: 2, |
1232 | | yorigin: 3, |
1233 | | }, |
1234 | | }; |
1235 | | |
1236 | | let pixels: Vec<u8> = plane.iter().collect(); |
1237 | | |
1238 | | assert_eq!( |
1239 | | &[1, 2, 3, 4, 8, 7, 6, 5, 9, 8, 7, 6, 2, 3, 4, 5,][..], |
1240 | | &pixels[..] |
1241 | | ); |
1242 | | } |
1243 | | } |