Skip to main content

av_scenechange/data/
block.rs

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