/rust/registry/src/index.crates.io-1949cf8c6b5b557f/av-scenechange-0.14.1/src/data/block.rs
Line | Count | Source |
1 | | use std::{ |
2 | | fmt, |
3 | | fmt::Display, |
4 | | ops::{Index, IndexMut}, |
5 | | }; |
6 | | |
7 | | use thiserror::Error; |
8 | | use v_frame::plane::PlaneOffset; |
9 | | |
10 | | use crate::data::{ |
11 | | plane::PlaneBlockOffset, |
12 | | superblock::{MI_SIZE_LOG2, SB_SIZE_LOG2}, |
13 | | }; |
14 | | |
15 | | pub const MAX_TX_SIZE: usize = 64; |
16 | | pub const BLOCK_TO_PLANE_SHIFT: usize = MI_SIZE_LOG2; |
17 | | pub const MIB_SIZE_LOG2: usize = SB_SIZE_LOG2 - MI_SIZE_LOG2; |
18 | | |
19 | | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
20 | | #[cfg_attr(test, derive(Default))] |
21 | | #[allow(non_camel_case_types)] |
22 | | pub enum BlockSize { |
23 | | BLOCK_4X4, |
24 | | BLOCK_4X8, |
25 | | BLOCK_8X4, |
26 | | BLOCK_8X8, |
27 | | BLOCK_8X16, |
28 | | BLOCK_16X8, |
29 | | BLOCK_16X16, |
30 | | BLOCK_16X32, |
31 | | BLOCK_32X16, |
32 | | BLOCK_32X32, |
33 | | BLOCK_32X64, |
34 | | BLOCK_64X32, |
35 | | #[cfg_attr(test, default)] |
36 | | BLOCK_64X64, |
37 | | BLOCK_64X128, |
38 | | BLOCK_128X64, |
39 | | BLOCK_128X128, |
40 | | BLOCK_4X16, |
41 | | BLOCK_16X4, |
42 | | BLOCK_8X32, |
43 | | BLOCK_32X8, |
44 | | BLOCK_16X64, |
45 | | BLOCK_64X16, |
46 | | } |
47 | | |
48 | | impl BlockSize { |
49 | | /// # Errors |
50 | | /// |
51 | | /// - Returns `InvalidBlockSize` if the given `w` and `h` do not produce a |
52 | | /// valid block size. |
53 | 0 | pub fn from_width_and_height_opt(w: usize, h: usize) -> Result<BlockSize, InvalidBlockSize> { |
54 | | use crate::data::block::BlockSize::*; |
55 | | |
56 | 0 | match (w, h) { |
57 | 0 | (4, 4) => Ok(BLOCK_4X4), |
58 | 0 | (4, 8) => Ok(BLOCK_4X8), |
59 | 0 | (4, 16) => Ok(BLOCK_4X16), |
60 | 0 | (8, 4) => Ok(BLOCK_8X4), |
61 | 0 | (8, 8) => Ok(BLOCK_8X8), |
62 | 0 | (8, 16) => Ok(BLOCK_8X16), |
63 | 0 | (8, 32) => Ok(BLOCK_8X32), |
64 | 0 | (16, 4) => Ok(BLOCK_16X4), |
65 | 0 | (16, 8) => Ok(BLOCK_16X8), |
66 | 0 | (16, 16) => Ok(BLOCK_16X16), |
67 | 0 | (16, 32) => Ok(BLOCK_16X32), |
68 | 0 | (16, 64) => Ok(BLOCK_16X64), |
69 | 0 | (32, 8) => Ok(BLOCK_32X8), |
70 | 0 | (32, 16) => Ok(BLOCK_32X16), |
71 | 0 | (32, 32) => Ok(BLOCK_32X32), |
72 | 0 | (32, 64) => Ok(BLOCK_32X64), |
73 | 0 | (64, 16) => Ok(BLOCK_64X16), |
74 | 0 | (64, 32) => Ok(BLOCK_64X32), |
75 | 0 | (64, 64) => Ok(BLOCK_64X64), |
76 | 0 | (64, 128) => Ok(BLOCK_64X128), |
77 | 0 | (128, 64) => Ok(BLOCK_128X64), |
78 | 0 | (128, 128) => Ok(BLOCK_128X128), |
79 | 0 | _ => Err(InvalidBlockSize), |
80 | | } |
81 | 0 | } |
82 | | |
83 | | /// # Panics |
84 | | /// |
85 | | /// - If the given `w` and `h` do not produce a valid block size. |
86 | 0 | pub fn from_width_and_height(w: usize, h: usize) -> BlockSize { |
87 | 0 | Self::from_width_and_height_opt(w, h).unwrap() |
88 | 0 | } |
89 | | |
90 | 0 | pub const fn width(self) -> usize { |
91 | 0 | 1 << self.width_log2() |
92 | 0 | } |
93 | | |
94 | 0 | pub const fn width_log2(self) -> usize { |
95 | | use crate::data::block::BlockSize::*; |
96 | | |
97 | 0 | match self { |
98 | 0 | BLOCK_4X4 | BLOCK_4X8 | BLOCK_4X16 => 2, |
99 | 0 | BLOCK_8X4 | BLOCK_8X8 | BLOCK_8X16 | BLOCK_8X32 => 3, |
100 | 0 | BLOCK_16X4 | BLOCK_16X8 | BLOCK_16X16 | BLOCK_16X32 | BLOCK_16X64 => 4, |
101 | 0 | BLOCK_32X8 | BLOCK_32X16 | BLOCK_32X32 | BLOCK_32X64 => 5, |
102 | 0 | BLOCK_64X16 | BLOCK_64X32 | BLOCK_64X64 | BLOCK_64X128 => 6, |
103 | 0 | BLOCK_128X64 | BLOCK_128X128 => 7, |
104 | | } |
105 | 0 | } |
106 | | |
107 | 0 | pub const fn height(self) -> usize { |
108 | 0 | 1 << self.height_log2() |
109 | 0 | } |
110 | | |
111 | 0 | pub const fn height_log2(self) -> usize { |
112 | | use crate::data::block::BlockSize::*; |
113 | | |
114 | 0 | match self { |
115 | 0 | BLOCK_4X4 | BLOCK_8X4 | BLOCK_16X4 => 2, |
116 | 0 | BLOCK_4X8 | BLOCK_8X8 | BLOCK_16X8 | BLOCK_32X8 => 3, |
117 | 0 | BLOCK_4X16 | BLOCK_8X16 | BLOCK_16X16 | BLOCK_32X16 | BLOCK_64X16 => 4, |
118 | 0 | BLOCK_8X32 | BLOCK_16X32 | BLOCK_32X32 | BLOCK_64X32 => 5, |
119 | 0 | BLOCK_16X64 | BLOCK_32X64 | BLOCK_64X64 | BLOCK_128X64 => 6, |
120 | 0 | BLOCK_64X128 | BLOCK_128X128 => 7, |
121 | | } |
122 | 0 | } |
123 | | |
124 | 0 | pub const fn tx_size(self) -> TxSize { |
125 | | use crate::data::block::{BlockSize::*, TxSize::*}; |
126 | | |
127 | 0 | match self { |
128 | 0 | BLOCK_4X4 => TX_4X4, |
129 | 0 | BLOCK_4X8 => TX_4X8, |
130 | 0 | BLOCK_8X4 => TX_8X4, |
131 | 0 | BLOCK_8X8 => TX_8X8, |
132 | 0 | BLOCK_8X16 => TX_8X16, |
133 | 0 | BLOCK_16X8 => TX_16X8, |
134 | 0 | BLOCK_16X16 => TX_16X16, |
135 | 0 | BLOCK_16X32 => TX_16X32, |
136 | 0 | BLOCK_32X16 => TX_32X16, |
137 | 0 | BLOCK_32X32 => TX_32X32, |
138 | 0 | BLOCK_32X64 => TX_32X64, |
139 | 0 | BLOCK_64X32 => TX_64X32, |
140 | 0 | BLOCK_4X16 => TX_4X16, |
141 | 0 | BLOCK_16X4 => TX_16X4, |
142 | 0 | BLOCK_8X32 => TX_8X32, |
143 | 0 | BLOCK_32X8 => TX_32X8, |
144 | 0 | BLOCK_16X64 => TX_16X64, |
145 | 0 | BLOCK_64X16 => TX_64X16, |
146 | 0 | _ => TX_64X64, |
147 | | } |
148 | 0 | } |
149 | | } |
150 | | |
151 | | #[derive(Debug, Copy, Clone, Error, Eq, PartialEq)] |
152 | | pub struct InvalidBlockSize; |
153 | | |
154 | | impl Display for InvalidBlockSize { |
155 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
156 | 0 | f.write_str("invalid block size") |
157 | 0 | } |
158 | | } |
159 | | |
160 | | /// Transform Size |
161 | | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] |
162 | | #[allow(non_camel_case_types)] |
163 | | pub enum TxSize { |
164 | | TX_4X4, |
165 | | TX_8X8, |
166 | | TX_16X16, |
167 | | TX_32X32, |
168 | | TX_64X64, |
169 | | |
170 | | TX_4X8, |
171 | | TX_8X4, |
172 | | TX_8X16, |
173 | | TX_16X8, |
174 | | TX_16X32, |
175 | | TX_32X16, |
176 | | TX_32X64, |
177 | | TX_64X32, |
178 | | |
179 | | TX_4X16, |
180 | | TX_16X4, |
181 | | TX_8X32, |
182 | | TX_32X8, |
183 | | TX_16X64, |
184 | | TX_64X16, |
185 | | } |
186 | | |
187 | | impl TxSize { |
188 | 0 | pub const fn width(self) -> usize { |
189 | 0 | 1 << self.width_log2() |
190 | 0 | } |
191 | | |
192 | 0 | pub const fn width_log2(self) -> usize { |
193 | | use crate::data::block::TxSize::*; |
194 | 0 | match self { |
195 | 0 | TX_4X4 | TX_4X8 | TX_4X16 => 2, |
196 | 0 | TX_8X8 | TX_8X4 | TX_8X16 | TX_8X32 => 3, |
197 | 0 | TX_16X16 | TX_16X8 | TX_16X32 | TX_16X4 | TX_16X64 => 4, |
198 | 0 | TX_32X32 | TX_32X16 | TX_32X64 | TX_32X8 => 5, |
199 | 0 | TX_64X64 | TX_64X32 | TX_64X16 => 6, |
200 | | } |
201 | 0 | } |
202 | | |
203 | 0 | pub const fn height(self) -> usize { |
204 | 0 | 1 << self.height_log2() |
205 | 0 | } |
206 | | |
207 | 0 | pub const fn height_log2(self) -> usize { |
208 | | use crate::data::block::TxSize::*; |
209 | 0 | match self { |
210 | 0 | TX_4X4 | TX_8X4 | TX_16X4 => 2, |
211 | 0 | TX_8X8 | TX_4X8 | TX_16X8 | TX_32X8 => 3, |
212 | 0 | TX_16X16 | TX_8X16 | TX_32X16 | TX_4X16 | TX_64X16 => 4, |
213 | 0 | TX_32X32 | TX_16X32 | TX_64X32 | TX_8X32 => 5, |
214 | 0 | TX_64X64 | TX_32X64 | TX_16X64 => 6, |
215 | | } |
216 | 0 | } |
217 | | } |
218 | | |
219 | | /// Absolute offset in blocks, where a block is defined |
220 | | /// to be an `N*N` square where `N == (1 << BLOCK_TO_PLANE_SHIFT)`. |
221 | | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] |
222 | | pub struct BlockOffset { |
223 | | pub x: usize, |
224 | | pub y: usize, |
225 | | } |
226 | | |
227 | | impl BlockOffset { |
228 | | /// Convert to plane offset without decimation. |
229 | 0 | pub const fn to_luma_plane_offset(self) -> PlaneOffset { |
230 | 0 | PlaneOffset { |
231 | 0 | x: (self.x as isize) << BLOCK_TO_PLANE_SHIFT, |
232 | 0 | y: (self.y as isize) << BLOCK_TO_PLANE_SHIFT, |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | 0 | pub fn with_offset(self, col_offset: isize, row_offset: isize) -> BlockOffset { |
237 | 0 | let x = self.x as isize + col_offset; |
238 | 0 | let y = self.y as isize + row_offset; |
239 | 0 | debug_assert!(x >= 0); |
240 | 0 | debug_assert!(y >= 0); |
241 | | |
242 | 0 | BlockOffset { |
243 | 0 | x: x as usize, |
244 | 0 | y: y as usize, |
245 | 0 | } |
246 | 0 | } |
247 | | } |
248 | | |
249 | | #[derive(Clone)] |
250 | | pub struct FrameBlocks { |
251 | | blocks: Box<[Block]>, |
252 | | pub cols: usize, |
253 | | } |
254 | | |
255 | | impl Index<usize> for FrameBlocks { |
256 | | type Output = [Block]; |
257 | | |
258 | 0 | fn index(&self, index: usize) -> &Self::Output { |
259 | 0 | &self.blocks[index * self.cols..(index + 1) * self.cols] |
260 | 0 | } |
261 | | } |
262 | | |
263 | | impl IndexMut<usize> for FrameBlocks { |
264 | 0 | fn index_mut(&mut self, index: usize) -> &mut Self::Output { |
265 | 0 | &mut self.blocks[index * self.cols..(index + 1) * self.cols] |
266 | 0 | } |
267 | | } |
268 | | |
269 | | // for convenience, also index by BlockOffset |
270 | | |
271 | | impl Index<PlaneBlockOffset> for FrameBlocks { |
272 | | type Output = Block; |
273 | | |
274 | 0 | fn index(&self, bo: PlaneBlockOffset) -> &Self::Output { |
275 | 0 | &self[bo.0.y][bo.0.x] |
276 | 0 | } |
277 | | } |
278 | | |
279 | | impl IndexMut<PlaneBlockOffset> for FrameBlocks { |
280 | 0 | fn index_mut(&mut self, bo: PlaneBlockOffset) -> &mut Self::Output { |
281 | 0 | &mut self[bo.0.y][bo.0.x] |
282 | 0 | } |
283 | | } |
284 | | |
285 | | #[derive(Copy, Clone, Default)] |
286 | | pub struct Block {} |