oxedyne/fe2o3/fe2o3_graphics/src/h264/intra.rs
25.9 KiB, 45 runs
created by r1870400018:21087, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! Predicting a block from the samples around it. |
| 2 | //! |
| 3 | //! An intra picture carries no samples directly. Every block is *predicted* from the row above it |
| 4 | //! and the column to its left -- both already reconstructed -- and what the bitstream carries is |
| 5 | //! only the difference. So the prediction is not an optimisation: it is most of the picture, and a |
| 6 | //! mode implemented slightly wrongly produces a picture that is recognisable and wrong rather than |
| 7 | //! an error. |
| 8 | //! |
| 9 | //! There are four families, and a real film uses all of them: |
| 10 | //! |
| 11 | //! - **Intra_4x4** (§8.3.1.2), nine modes over a four-by-four block. |
| 12 | //! - **Intra_8x8** (§8.3.2.2), the same nine modes over an eight-by-eight block, with the |
| 13 | //! reference samples **filtered first**. High profile adds it and 861 films in the corpus turn it |
| 14 | //! on. |
| 15 | //! - **Intra_16x16** (§8.3.3), four modes over the whole macroblock, for regions with little detail. |
| 16 | //! - **Chroma** (§8.3.4), four modes over an eight-by-eight chroma block, both components together. |
| 17 | //! |
| 18 | //! # Availability, which is the part that cannot be seen |
| 19 | //! |
| 20 | //! A neighbour may be predicted from only where it has already been decoded *and* belongs to the |
| 21 | //! same slice. A block at the left edge of a picture has no left neighbour; a block in the second |
| 22 | //! slice of a picture has no neighbour in the first, however close it sits. Each mode is defined |
| 23 | //! only for a particular set of available neighbours, and where they are missing the direct-current |
| 24 | //! mode falls back through three cases to the mid-grey of `1 << (bitDepth − 1)`. A decoder careless |
| 25 | //! about it predicts from samples that are still nought and produces a picture with a plausible |
| 26 | //! grid of dark blocks -- which is why availability is carried here as explicit flags on |
| 27 | //! [`Edges`] rather than inferred from whether a sample happens to be zero. |
| 28 | //! |
| 29 | //! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\ |
| 30 | //! Anthropic Claude |
| 31 | |
| 32 | use oxedyne_fe2o3_core::prelude::*; |
| 33 | |
| 34 | /// The samples around a block, and which of them may be predicted from. |
| 35 | /// |
| 36 | /// One shape serves all four families. `top` runs from the block's left edge rightwards and holds |
| 37 | /// up to sixteen samples: the eight or sixteen above the block, and then the ones above and to the |
| 38 | /// right where the mode reaches for them. `left` runs downwards from the block's top edge. |
| 39 | #[derive(Clone, Debug)] |
| 40 | pub struct Edges { |
| 41 | pub top: [i32; 16], // p[x, −1] for x from nought |
| 42 | pub top_ok: bool, // may the samples directly above the block be predicted from? |
| 43 | pub right_ok: bool, // may those above and to the right of it be? |
| 44 | pub left: [i32; 16], // p[−1, y] for y from nought |
| 45 | pub left_ok: bool, // may the column to the left be predicted from? |
| 46 | pub corner: i32, // p[−1, −1], the sample diagonally above and left |
| 47 | pub corner_ok: bool, // may that one be? |
| 48 | } |
| 49 | |
| 50 | impl Edges { |
| 51 | |
| 52 | /// Edges with nothing available, which is what a macroblock at the top-left corner of a slice |
| 53 | /// has. |
| 54 | pub fn none() -> Self { |
| 55 | Self { |
| 56 | top: [0; 16], |
| 57 | top_ok: false, |
| 58 | right_ok: false, |
| 59 | left: [0; 16], |
| 60 | left_ok: false, |
| 61 | corner: 0, |
| 62 | corner_ok: false, |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | /// Extends the row above rightwards where the mode reaches past what is available (§8.3.1.2). |
| 67 | /// |
| 68 | /// "When samples `p[x, −1]`, with `x` = 4..7, are marked as not available and the sample |
| 69 | /// `p[3, −1]` is available, the sample value of `p[3, −1]` is substituted." A block at the right |
| 70 | /// edge of a picture, or one whose upper-right neighbour has not been decoded yet, still uses |
| 71 | /// the diagonal modes; it uses them against a repeated sample. Leaving the substitution out |
| 72 | /// makes every such block predict from nought, which is a black wedge in the corner of it. |
| 73 | pub fn pad_right(&mut self, from: usize, to: usize) { |
| 74 | if self.right_ok || !self.top_ok || from == 0 { |
| 75 | return; |
| 76 | } |
| 77 | let v = self.top[from - 1]; |
| 78 | for x in from..to.min(16) { |
| 79 | self.top[x] = v; |
| 80 | } |
| 81 | self.right_ok = true; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | fn clip(v: i32, bit_depth: u32) -> i32 { |
| 86 | v.clamp(0, (1i32 << bit_depth) - 1) |
| 87 | } |
| 88 | |
| 89 | /// The value a block takes where nothing around it is available: mid-grey. |
| 90 | fn mid(bit_depth: u32) -> i32 { |
| 91 | 1 << (bit_depth - 1) |
| 92 | } |
| 93 | |
| 94 | /// One of the nine directions a four-by-four or eight-by-eight block may be predicted in. |
| 95 | /// |
| 96 | /// The numbering is the specification's, and the order matters: the most probable mode machinery |
| 97 | /// in §8.3.1.1 compares these numbers directly. |
| 98 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 99 | pub enum Mode { |
| 100 | Vertical, // straight down from the row above |
| 101 | Horizontal, // straight across from the column to the left |
| 102 | Dc, // the mean of whichever neighbours there are |
| 103 | DiagonalDownLeft, // at forty-five degrees |
| 104 | DiagonalDownRight, |
| 105 | VerticalRight, // steeply down and right |
| 106 | HorizontalDown, // shallowly down and right |
| 107 | VerticalLeft, // steeply down and left |
| 108 | HorizontalUp, // shallowly up and right |
| 109 | } |
| 110 | |
| 111 | impl Mode { |
| 112 | |
| 113 | pub fn of(n: u32) -> Outcome<Self> { |
| 114 | Ok(match n { |
| 115 | 0 => Self::Vertical, |
| 116 | 1 => Self::Horizontal, |
| 117 | 2 => Self::Dc, |
| 118 | 3 => Self::DiagonalDownLeft, |
| 119 | 4 => Self::DiagonalDownRight, |
| 120 | 5 => Self::VerticalRight, |
| 121 | 6 => Self::HorizontalDown, |
| 122 | 7 => Self::VerticalLeft, |
| 123 | 8 => Self::HorizontalUp, |
| 124 | _ => return Err(err!( |
| 125 | "An intra prediction mode of {} was coded, and 0 to 8 are the only ones defined.", |
| 126 | n; Invalid, Input, Decode)), |
| 127 | }) |
| 128 | } |
| 129 | |
| 130 | pub fn number(self) -> u32 { |
| 131 | match self { |
| 132 | Self::Vertical => 0, |
| 133 | Self::Horizontal => 1, |
| 134 | Self::Dc => 2, |
| 135 | Self::DiagonalDownLeft => 3, |
| 136 | Self::DiagonalDownRight => 4, |
| 137 | Self::VerticalRight => 5, |
| 138 | Self::HorizontalDown => 6, |
| 139 | Self::VerticalLeft => 7, |
| 140 | Self::HorizontalUp => 8, |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | /// The direct-current prediction, which is the one mode a block may always use (§8.3.1.2.3). |
| 146 | /// |
| 147 | /// Its whole substance is the four cases: both edges, the left alone, the top alone, and neither. |
| 148 | fn dc(e: &Edges, n: usize, bit_depth: u32) -> i32 { |
| 149 | let top: i32 = e.top[..n].iter().sum(); |
| 150 | let left: i32 = e.left[..n].iter().sum(); |
| 151 | let shift = n.trailing_zeros(); |
| 152 | match (e.top_ok, e.left_ok) { |
| 153 | (true, true) => (top + left + n as i32) >> (shift + 1), |
| 154 | (false, true) => (left + (n as i32 >> 1)) >> shift, |
| 155 | (true, false) => (top + (n as i32 >> 1)) >> shift, |
| 156 | (false, false) => mid(bit_depth), |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | /// Predicts a four-by-four luma block (§8.3.1.2). |
| 161 | /// |
| 162 | /// The caller has already padded the row above where the mode reaches past it; see |
| 163 | /// [`Edges::pad_right`]. |
| 164 | pub fn pred_4x4(mode: Mode, e: &Edges, bit_depth: u32) -> [i32; 16] { |
| 165 | let mut p = [0i32; 16]; |
| 166 | let t = &e.top; |
| 167 | let l = &e.left; |
| 168 | let c = e.corner; |
| 169 | match mode { |
| 170 | Mode::Vertical => { |
| 171 | for y in 0..4 { |
| 172 | for x in 0..4 { |
| 173 | p[y * 4 + x] = t[x]; |
| 174 | } |
| 175 | } |
| 176 | }, |
| 177 | Mode::Horizontal => { |
| 178 | for y in 0..4 { |
| 179 | for x in 0..4 { |
| 180 | p[y * 4 + x] = l[y]; |
| 181 | } |
| 182 | } |
| 183 | }, |
| 184 | Mode::Dc => { |
| 185 | let v = dc(e, 4, bit_depth); |
| 186 | p = [v; 16]; |
| 187 | }, |
| 188 | Mode::DiagonalDownLeft => { |
| 189 | for y in 0..4 { |
| 190 | for x in 0..4 { |
| 191 | p[y * 4 + x] = if x == 3 && y == 3 { |
| 192 | (t[6] + 3 * t[7] + 2) >> 2 |
| 193 | } else { |
| 194 | (t[x + y] + 2 * t[x + y + 1] + t[x + y + 2] + 2) >> 2 |
| 195 | }; |
| 196 | } |
| 197 | } |
| 198 | }, |
| 199 | Mode::DiagonalDownRight => { |
| 200 | for y in 0..4i32 { |
| 201 | for x in 0..4i32 { |
| 202 | let (xu, yu) = (x as usize, y as usize); |
| 203 | p[yu * 4 + xu] = if x > y { |
| 204 | let d = (x - y) as usize; |
| 205 | (at(t, c, d as i32 - 2) + 2 * at(t, c, d as i32 - 1) + t[d] + 2) >> 2 |
| 206 | } else if x < y { |
| 207 | let d = (y - x) as usize; |
| 208 | (at(l, c, d as i32 - 2) + 2 * at(l, c, d as i32 - 1) + l[d] + 2) >> 2 |
| 209 | } else { |
| 210 | (t[0] + 2 * c + l[0] + 2) >> 2 |
| 211 | }; |
| 212 | } |
| 213 | } |
| 214 | }, |
| 215 | Mode::VerticalRight => { |
| 216 | for y in 0..4i32 { |
| 217 | for x in 0..4i32 { |
| 218 | let z = 2 * x - y; |
| 219 | let (xu, yu) = (x as usize, y as usize); |
| 220 | let h = x - (y >> 1); |
| 221 | p[yu * 4 + xu] = match z { |
| 222 | 0 | 2 | 4 | 6 => (at(t, c, h - 1) + at(t, c, h) + 1) >> 1, |
| 223 | 1 | 3 | 5 => (at(t, c, h - 2) + 2 * at(t, c, h - 1) |
| 224 | + at(t, c, h) + 2) >> 2, |
| 225 | -1 => (l[0] + 2 * c + t[0] + 2) >> 2, |
| 226 | _ => (at(l, c, y - 1) + 2 * at(l, c, y - 2) |
| 227 | + at(l, c, y - 3) + 2) >> 2, |
| 228 | }; |
| 229 | } |
| 230 | } |
| 231 | }, |
| 232 | Mode::HorizontalDown => { |
| 233 | for y in 0..4i32 { |
| 234 | for x in 0..4i32 { |
| 235 | let z = 2 * y - x; |
| 236 | let (xu, yu) = (x as usize, y as usize); |
| 237 | let v = y - (x >> 1); |
| 238 | p[yu * 4 + xu] = match z { |
| 239 | 0 | 2 | 4 | 6 => (at(l, c, v - 1) + at(l, c, v) + 1) >> 1, |
| 240 | 1 | 3 | 5 => (at(l, c, v - 2) + 2 * at(l, c, v - 1) |
| 241 | + at(l, c, v) + 2) >> 2, |
| 242 | -1 => (l[0] + 2 * c + t[0] + 2) >> 2, |
| 243 | _ => (at(t, c, x - 1) + 2 * at(t, c, x - 2) |
| 244 | + at(t, c, x - 3) + 2) >> 2, |
| 245 | }; |
| 246 | } |
| 247 | } |
| 248 | }, |
| 249 | Mode::VerticalLeft => { |
| 250 | for y in 0..4 { |
| 251 | for x in 0..4 { |
| 252 | let h = x + (y >> 1); |
| 253 | p[y * 4 + x] = if y % 2 == 0 { |
| 254 | (t[h] + t[h + 1] + 1) >> 1 |
| 255 | } else { |
| 256 | (t[h] + 2 * t[h + 1] + t[h + 2] + 2) >> 2 |
| 257 | }; |
| 258 | } |
| 259 | } |
| 260 | }, |
| 261 | Mode::HorizontalUp => { |
| 262 | for y in 0..4 { |
| 263 | for x in 0..4 { |
| 264 | let z = x + 2 * y; |
| 265 | let v = y + (x >> 1); |
| 266 | p[y * 4 + x] = match z { |
| 267 | 0 | 2 | 4 => (l[v] + l[v + 1] + 1) >> 1, |
| 268 | 1 | 3 => (l[v] + 2 * l[v + 1] + l[v + 2] + 2) >> 2, |
| 269 | 5 => (l[2] + 3 * l[3] + 2) >> 2, |
| 270 | _ => l[3], |
| 271 | }; |
| 272 | } |
| 273 | } |
| 274 | }, |
| 275 | } |
| 276 | for v in p.iter_mut() { |
| 277 | *v = clip(*v, bit_depth); |
| 278 | } |
| 279 | p |
| 280 | } |
| 281 | |
| 282 | /// One sample of an edge, where an index of −1 means the corner. |
| 283 | /// |
| 284 | /// The diagonal modes index an edge from −1, which in the specification's notation is `p[−1, −1]` |
| 285 | /// for both edges at once. Writing that as a signed index into one array keeps each mode's |
| 286 | /// arithmetic the shape the clause gives it. |
| 287 | fn at(edge: &[i32; 16], corner: i32, i: i32) -> i32 { |
| 288 | if i < 0 { |
| 289 | corner |
| 290 | } else { |
| 291 | edge[(i as usize).min(15)] |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | /// Filters the reference samples an eight-by-eight block predicts from (§8.3.2.2.1). |
| 296 | /// |
| 297 | /// Every Intra_8x8 mode reads the *filtered* samples, not the reconstructed ones. This is the one |
| 298 | /// step Intra_4x4 has no equivalent of, and leaving it out gives a picture that is right in its |
| 299 | /// large shapes and wrong in every eight-by-eight block's texture. |
| 300 | pub fn filter_8x8(e: &Edges) -> Edges { |
| 301 | let mut out = e.clone(); |
| 302 | if e.top_ok && e.right_ok { |
| 303 | out.top[0] = if e.corner_ok { |
| 304 | (e.corner + 2 * e.top[0] + e.top[1] + 2) >> 2 |
| 305 | } else { |
| 306 | (3 * e.top[0] + e.top[1] + 2) >> 2 |
| 307 | }; |
| 308 | for x in 1..15 { |
| 309 | out.top[x] = (e.top[x - 1] + 2 * e.top[x] + e.top[x + 1] + 2) >> 2; |
| 310 | } |
| 311 | out.top[15] = (e.top[14] + 3 * e.top[15] + 2) >> 2; |
| 312 | } |
| 313 | if e.corner_ok { |
| 314 | out.corner = match (e.top_ok, e.left_ok) { |
| 315 | (true, true) => (e.top[0] + 2 * e.corner + e.left[0] + 2) >> 2, |
| 316 | (true, false) => (3 * e.corner + e.top[0] + 2) >> 2, |
| 317 | (false, true) => (3 * e.corner + e.left[0] + 2) >> 2, |
| 318 | // Not used by any mode in this case, but defined so that nothing reads a stale value. |
| 319 | (false, false) => e.corner, |
| 320 | }; |
| 321 | } |
| 322 | if e.left_ok { |
| 323 | out.left[0] = if e.corner_ok { |
| 324 | (e.corner + 2 * e.left[0] + e.left[1] + 2) >> 2 |
| 325 | } else { |
| 326 | (3 * e.left[0] + e.left[1] + 2) >> 2 |
| 327 | }; |
| 328 | for y in 1..7 { |
| 329 | out.left[y] = (e.left[y - 1] + 2 * e.left[y] + e.left[y + 1] + 2) >> 2; |
| 330 | } |
| 331 | out.left[7] = (e.left[6] + 3 * e.left[7] + 2) >> 2; |
| 332 | } |
| 333 | out |
| 334 | } |
| 335 | |
| 336 | /// Predicts an eight-by-eight luma block (§8.3.2.2). |
| 337 | /// |
| 338 | /// `e` holds the **unfiltered** samples; the filtering of §8.3.2.2.1 is done here, because every |
| 339 | /// mode wants it and a caller that had to remember would eventually forget. |
| 340 | pub fn pred_8x8(mode: Mode, e: &Edges, bit_depth: u32) -> [i32; 64] { |
| 341 | let f = filter_8x8(e); |
| 342 | let t = &f.top; |
| 343 | let l = &f.left; |
| 344 | let c = f.corner; |
| 345 | let mut p = [0i32; 64]; |
| 346 | match mode { |
| 347 | Mode::Vertical => { |
| 348 | for y in 0..8 { |
| 349 | for x in 0..8 { |
| 350 | p[y * 8 + x] = t[x]; |
| 351 | } |
| 352 | } |
| 353 | }, |
| 354 | Mode::Horizontal => { |
| 355 | for y in 0..8 { |
| 356 | for x in 0..8 { |
| 357 | p[y * 8 + x] = l[y]; |
| 358 | } |
| 359 | } |
| 360 | }, |
| 361 | Mode::Dc => { |
| 362 | let v = dc(&f, 8, bit_depth); |
| 363 | p = [v; 64]; |
| 364 | }, |
| 365 | Mode::DiagonalDownLeft => { |
| 366 | for y in 0..8 { |
| 367 | for x in 0..8 { |
| 368 | p[y * 8 + x] = if x == 7 && y == 7 { |
| 369 | (t[14] + 3 * t[15] + 2) >> 2 |
| 370 | } else { |
| 371 | (t[x + y] + 2 * t[x + y + 1] + t[x + y + 2] + 2) >> 2 |
| 372 | }; |
| 373 | } |
| 374 | } |
| 375 | }, |
| 376 | Mode::DiagonalDownRight => { |
| 377 | for y in 0..8i32 { |
| 378 | for x in 0..8i32 { |
| 379 | let (xu, yu) = (x as usize, y as usize); |
| 380 | p[yu * 8 + xu] = if x > y { |
| 381 | let d = (x - y) as usize; |
| 382 | (at(t, c, d as i32 - 2) + 2 * at(t, c, d as i32 - 1) + t[d] + 2) >> 2 |
| 383 | } else if x < y { |
| 384 | let d = (y - x) as usize; |
| 385 | (at(l, c, d as i32 - 2) + 2 * at(l, c, d as i32 - 1) + l[d] + 2) >> 2 |
| 386 | } else { |
| 387 | (t[0] + 2 * c + l[0] + 2) >> 2 |
| 388 | }; |
| 389 | } |
| 390 | } |
| 391 | }, |
| 392 | Mode::VerticalRight => { |
| 393 | for y in 0..8i32 { |
| 394 | for x in 0..8i32 { |
| 395 | let z = 2 * x - y; |
| 396 | let (xu, yu) = (x as usize, y as usize); |
| 397 | let h = x - (y >> 1); |
| 398 | p[yu * 8 + xu] = if z >= 0 && z % 2 == 0 { |
| 399 | (at(t, c, h - 1) + at(t, c, h) + 1) >> 1 |
| 400 | } else if z >= 0 { |
| 401 | (at(t, c, h - 2) + 2 * at(t, c, h - 1) + at(t, c, h) + 2) >> 2 |
| 402 | } else if z == -1 { |
| 403 | (l[0] + 2 * c + t[0] + 2) >> 2 |
| 404 | } else { |
| 405 | let k = y - 2 * x; |
| 406 | (at(l, c, k - 1) + 2 * at(l, c, k - 2) + at(l, c, k - 3) + 2) >> 2 |
| 407 | }; |
| 408 | } |
| 409 | } |
| 410 | }, |
| 411 | Mode::HorizontalDown => { |
| 412 | for y in 0..8i32 { |
| 413 | for x in 0..8i32 { |
| 414 | let z = 2 * y - x; |
| 415 | let (xu, yu) = (x as usize, y as usize); |
| 416 | let v = y - (x >> 1); |
| 417 | p[yu * 8 + xu] = if z >= 0 && z % 2 == 0 { |
| 418 | (at(l, c, v - 1) + at(l, c, v) + 1) >> 1 |
| 419 | } else if z >= 0 { |
| 420 | (at(l, c, v - 2) + 2 * at(l, c, v - 1) + at(l, c, v) + 2) >> 2 |
| 421 | } else if z == -1 { |
| 422 | (l[0] + 2 * c + t[0] + 2) >> 2 |
| 423 | } else { |
| 424 | let k = x - 2 * y; |
| 425 | (at(t, c, k - 1) + 2 * at(t, c, k - 2) + at(t, c, k - 3) + 2) >> 2 |
| 426 | }; |
| 427 | } |
| 428 | } |
| 429 | }, |
| 430 | Mode::VerticalLeft => { |
| 431 | for y in 0..8 { |
| 432 | for x in 0..8 { |
| 433 | let h = x + (y >> 1); |
| 434 | p[y * 8 + x] = if y % 2 == 0 { |
| 435 | (t[h] + t[h + 1] + 1) >> 1 |
| 436 | } else { |
| 437 | (t[h] + 2 * t[h + 1] + t[h + 2] + 2) >> 2 |
| 438 | }; |
| 439 | } |
| 440 | } |
| 441 | }, |
| 442 | Mode::HorizontalUp => { |
| 443 | for y in 0..8 { |
| 444 | for x in 0..8 { |
| 445 | let z = x + 2 * y; |
| 446 | let v = y + (x >> 1); |
| 447 | p[y * 8 + x] = if z <= 12 && z % 2 == 0 { |
| 448 | (l[v] + l[v.min(6) + 1] + 1) >> 1 |
| 449 | } else if z <= 11 { |
| 450 | (l[v] + 2 * l[(v + 1).min(7)] + l[(v + 2).min(7)] + 2) >> 2 |
| 451 | } else if z == 13 { |
| 452 | (l[6] + 3 * l[7] + 2) >> 2 |
| 453 | } else { |
| 454 | l[7] |
| 455 | }; |
| 456 | } |
| 457 | } |
| 458 | }, |
| 459 | } |
| 460 | for v in p.iter_mut() { |
| 461 | *v = clip(*v, bit_depth); |
| 462 | } |
| 463 | p |
| 464 | } |
| 465 | |
| 466 | /// One of the four ways a whole macroblock's luma may be predicted (§8.3.3). |
| 467 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 468 | pub enum Mode16 { |
| 469 | Vertical, |
| 470 | Horizontal, |
| 471 | Dc, // the mean |
| 472 | Plane, // a tilted plane fitted to the row above and the column to the left |
| 473 | } |
| 474 | |
| 475 | impl Mode16 { |
| 476 | |
| 477 | pub fn of(n: u32) -> Outcome<Self> { |
| 478 | Ok(match n { |
| 479 | 0 => Self::Vertical, |
| 480 | 1 => Self::Horizontal, |
| 481 | 2 => Self::Dc, |
| 482 | 3 => Self::Plane, |
| 483 | _ => return Err(err!( |
| 484 | "An Intra_16x16 prediction mode of {} was coded, and 0 to 3 are the only ones \ |
| 485 | defined.", n; Invalid, Input, Decode)), |
| 486 | }) |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | /// Predicts a whole macroblock's luma (§8.3.3). |
| 491 | pub fn pred_16x16(mode: Mode16, e: &Edges, bit_depth: u32) -> [i32; 256] { |
| 492 | let mut p = [0i32; 256]; |
| 493 | match mode { |
| 494 | Mode16::Vertical => { |
| 495 | for y in 0..16 { |
| 496 | for x in 0..16 { |
| 497 | p[y * 16 + x] = e.top[x]; |
| 498 | } |
| 499 | } |
| 500 | }, |
| 501 | Mode16::Horizontal => { |
| 502 | for y in 0..16 { |
| 503 | for x in 0..16 { |
| 504 | p[y * 16 + x] = e.left[y]; |
| 505 | } |
| 506 | } |
| 507 | }, |
| 508 | Mode16::Dc => { |
| 509 | let v = dc(e, 16, bit_depth); |
| 510 | p = [v; 256]; |
| 511 | }, |
| 512 | Mode16::Plane => { |
| 513 | // A plane through the corner samples: `a` is twice the mean of the two far corners, |
| 514 | // and `b` and `c` are the slopes, each a weighted difference across the edge. |
| 515 | let mut h = 0i32; |
| 516 | let mut v = 0i32; |
| 517 | for i in 0..8i32 { |
| 518 | let iu = i as usize; |
| 519 | h += (i + 1) * (e.top[8 + iu] - at(&e.top, e.corner, 6 - i)); |
| 520 | v += (i + 1) * (e.left[8 + iu] - at(&e.left, e.corner, 6 - i)); |
| 521 | } |
| 522 | let a = 16 * (e.left[15] + e.top[15]); |
| 523 | let b = (5 * h + 32) >> 6; |
| 524 | let c = (5 * v + 32) >> 6; |
| 525 | for y in 0..16i32 { |
| 526 | for x in 0..16i32 { |
| 527 | p[(y * 16 + x) as usize] = (a + b * (x - 7) + c * (y - 7) + 16) >> 5; |
| 528 | } |
| 529 | } |
| 530 | }, |
| 531 | } |
| 532 | for s in p.iter_mut() { |
| 533 | *s = clip(*s, bit_depth); |
| 534 | } |
| 535 | p |
| 536 | } |
| 537 | |
| 538 | /// One of the four ways a macroblock's chroma may be predicted (§8.3.4). |
| 539 | /// |
| 540 | /// The numbering is not the luma one: chroma codes the direct current first and the two straight |
| 541 | /// directions the other way about. Reading a chroma mode as though it were a luma one swaps every |
| 542 | /// picture's horizontal and vertical gradients, which is the kind of fault that looks almost right. |
| 543 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 544 | pub enum ModeC { |
| 545 | Dc, // the mean, taken separately over each four-by-four quarter |
| 546 | Horizontal, |
| 547 | Vertical, |
| 548 | Plane, |
| 549 | } |
| 550 | |
| 551 | impl ModeC { |
| 552 | |
| 553 | pub fn of(n: u32) -> Outcome<Self> { |
| 554 | Ok(match n { |
| 555 | 0 => Self::Dc, |
| 556 | 1 => Self::Horizontal, |
| 557 | 2 => Self::Vertical, |
| 558 | 3 => Self::Plane, |
| 559 | _ => return Err(err!( |
| 560 | "An intra_chroma_pred_mode of {} was coded, and 0 to 3 are the only ones defined.", |
| 561 | n; Invalid, Input, Decode)), |
| 562 | }) |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | /// Predicts one eight-by-eight chroma block of a 4:2:0 macroblock (§8.3.4). |
| 567 | pub fn pred_chroma(mode: ModeC, e: &Edges, bit_depth: u32) -> [i32; 64] { |
| 568 | let mut p = [0i32; 64]; |
| 569 | match mode { |
| 570 | ModeC::Horizontal => { |
| 571 | for y in 0..8 { |
| 572 | for x in 0..8 { |
| 573 | p[y * 8 + x] = e.left[y]; |
| 574 | } |
| 575 | } |
| 576 | }, |
| 577 | ModeC::Vertical => { |
| 578 | for y in 0..8 { |
| 579 | for x in 0..8 { |
| 580 | p[y * 8 + x] = e.top[x]; |
| 581 | } |
| 582 | } |
| 583 | }, |
| 584 | ModeC::Dc => { |
| 585 | // Each four-by-four quarter takes its own mean, and *which* edges it prefers depends |
| 586 | // on where in the block it sits: the two quarters off the diagonal look first along |
| 587 | // the edge they touch, and only then at the other one. A decoder that averaged the |
| 588 | // whole block would give a chroma plane that is smooth where the picture is not. |
| 589 | for by in 0..2usize { |
| 590 | for bx in 0..2usize { |
| 591 | let (xo, yo) = (bx * 4, by * 4); |
| 592 | let top: i32 = e.top[xo..xo + 4].iter().sum(); |
| 593 | let left: i32 = e.left[yo..yo + 4].iter().sum(); |
| 594 | let v = if (bx == 0 && by == 0) || (bx > 0 && by > 0) { |
| 595 | match (e.top_ok, e.left_ok) { |
| 596 | (true, true) => (top + left + 4) >> 3, |
| 597 | (false, true) => (left + 2) >> 2, |
| 598 | (true, false) => (top + 2) >> 2, |
| 599 | (false, false) => mid(bit_depth), |
| 600 | } |
| 601 | } else if bx > 0 { |
| 602 | // Upper right: along the top first. |
| 603 | match (e.top_ok, e.left_ok) { |
| 604 | (true, _) => (top + 2) >> 2, |
| 605 | (false, true) => (left + 2) >> 2, |
| 606 | (false, false) => mid(bit_depth), |
| 607 | } |
| 608 | } else { |
| 609 | // Lower left: down the side first. |
| 610 | match (e.left_ok, e.top_ok) { |
| 611 | (true, _) => (left + 2) >> 2, |
| 612 | (false, true) => (top + 2) >> 2, |
| 613 | (false, false) => mid(bit_depth), |
| 614 | } |
| 615 | }; |
| 616 | for y in 0..4 { |
| 617 | for x in 0..4 { |
| 618 | p[(yo + y) * 8 + xo + x] = v; |
| 619 | } |
| 620 | } |
| 621 | } |
| 622 | } |
| 623 | }, |
| 624 | ModeC::Plane => { |
| 625 | let mut h = 0i32; |
| 626 | let mut v = 0i32; |
| 627 | for i in 0..4i32 { |
| 628 | let iu = i as usize; |
| 629 | h += (i + 1) * (e.top[4 + iu] - at(&e.top, e.corner, 2 - i)); |
| 630 | v += (i + 1) * (e.left[4 + iu] - at(&e.left, e.corner, 2 - i)); |
| 631 | } |
| 632 | let a = 16 * (e.left[7] + e.top[7]); |
| 633 | let b = (34 * h + 32) >> 6; |
| 634 | let c = (34 * v + 32) >> 6; |
| 635 | for y in 0..8i32 { |
| 636 | for x in 0..8i32 { |
| 637 | p[(y * 8 + x) as usize] = (a + b * (x - 3) + c * (y - 3) + 16) >> 5; |
| 638 | } |
| 639 | } |
| 640 | }, |
| 641 | } |
| 642 | for s in p.iter_mut() { |
| 643 | *s = clip(*s, bit_depth); |
| 644 | } |
| 645 | p |
| 646 | } |
| 647 | |
| 648 | #[cfg(test)] |
| 649 | mod tests { |
| 650 | use super::*; |
| 651 | |
| 652 | /// Edges with a known ramp along each, and everything available. |
| 653 | fn ramp() -> Edges { |
| 654 | let mut e = Edges::none(); |
| 655 | for i in 0..16 { |
| 656 | e.top[i] = 10 + i as i32; |
| 657 | e.left[i] = 100 + i as i32; |
| 658 | } |
| 659 | e.top_ok = true; |
| 660 | e.right_ok = true; |
| 661 | e.left_ok = true; |
| 662 | e.corner = 50; |
| 663 | e.corner_ok = true; |
| 664 | e |
| 665 | } |
| 666 | |
| 667 | #[test] |
| 668 | fn test_the_straight_modes_copy_the_edge_they_name_01() -> Outcome<()> { |
| 669 | // Vertical copies the row above down every column, horizontal copies the column across |
| 670 | // every row. The two are one transposition apart, and swapping them is the single easiest |
| 671 | // mistake to make here -- so both are checked against an edge whose samples are all |
| 672 | // different from each other's. |
| 673 | let e = ramp(); |
| 674 | let v = pred_4x4(Mode::Vertical, &e, 8); |
| 675 | for y in 0..4 { |
| 676 | for x in 0..4 { |
| 677 | req!(v[y * 4 + x], e.top[x], "vertical at ({}, {})", x, y); |
| 678 | } |
| 679 | } |
| 680 | let h = pred_4x4(Mode::Horizontal, &e, 8); |
| 681 | for y in 0..4 { |
| 682 | for x in 0..4 { |
| 683 | req!(h[y * 4 + x], e.left[y], "horizontal at ({}, {})", x, y); |
| 684 | } |
| 685 | } |
| 686 | // And chroma numbers them the other way about, which is the fault this guards against. |
| 687 | let cv = pred_chroma(ModeC::Vertical, &e, 8); |
| 688 | let ch = pred_chroma(ModeC::Horizontal, &e, 8); |
| 689 | req!(cv[1], e.top[1], "chroma vertical did not take the row above"); |
| 690 | req!(ch[8], e.left[1], "chroma horizontal did not take the column beside"); |
| 691 | let same = cv == ch; |
| 692 | req!(same, false, "the two chroma directions are the same prediction"); |
| 693 | Ok(()) |
| 694 | } |
| 695 | |
| 696 | #[test] |
| 697 | fn test_the_mean_falls_back_through_its_four_cases_02() -> Outcome<()> { |
| 698 | // The direct current mode is the only one a block may always use, and it is the only one |
| 699 | // whose answer depends on what is *missing*. Each of the four cases is a different |
| 700 | // divisor, and taking the wrong one is a block that is uniformly too bright or too dark. |
| 701 | let mut e = ramp(); |
| 702 | // Both edges: the mean of eight samples. |
| 703 | let both = pred_4x4(Mode::Dc, &e, 8)[0]; |
| 704 | let want = (10 + 11 + 12 + 13 + 100 + 101 + 102 + 103 + 4) >> 3; |
| 705 | req!(both, want); |
| 706 | // The left alone. |
| 707 | e.top_ok = false; |
| 708 | req!(pred_4x4(Mode::Dc, &e, 8)[0], (100 + 101 + 102 + 103 + 2) >> 2); |
| 709 | // The top alone. |
| 710 | e.top_ok = true; |
| 711 | e.left_ok = false; |
| 712 | req!(pred_4x4(Mode::Dc, &e, 8)[0], (10 + 11 + 12 + 13 + 2) >> 2); |
| 713 | // Neither: mid-grey, and *not* nought, which is what a decoder that read the unavailable |
| 714 | // samples anyway would produce. |
| 715 | e.top_ok = false; |
| 716 | req!(pred_4x4(Mode::Dc, &e, 8)[0], 128, "a block with no neighbours came out black"); |
| 717 | req!(pred_4x4(Mode::Dc, &e, 10)[0], 512, "mid-grey is not scaled to the bit depth"); |
| 718 | Ok(()) |
| 719 | } |
| 720 | |
| 721 | #[test] |
| 722 | fn test_an_eight_by_eight_block_predicts_from_filtered_samples_03() -> Outcome<()> { |
| 723 | // The step Intra_4x4 has no equivalent of. A vertical prediction of an eight-by-eight block |
| 724 | // does not copy the row above; it copies the row above smoothed by a three-tap filter. The |
| 725 | // difference is invisible on a flat edge and obvious on a step, so the fixture is a step. |
| 726 | let mut e = Edges::none(); |
| 727 | for i in 0..16 { |
| 728 | e.top[i] = if i < 8 { 0 } else { 200 }; |
| 729 | e.left[i] = 60; |
| 730 | } |
| 731 | e.top_ok = true; |
| 732 | e.right_ok = true; |
| 733 | e.left_ok = true; |
| 734 | e.corner = 60; |
| 735 | e.corner_ok = true; |
| 736 | let p = pred_8x8(Mode::Vertical, &e, 8); |
| 737 | // The filter spreads the step over the two samples either side of it. |
| 738 | let unfiltered = p[7] == e.top[7]; |
| 739 | req!(unfiltered, false, "an eight-by-eight block predicted from unfiltered samples"); |
| 740 | req!(p[7], (0 + 2 * 0 + 200 + 2) >> 2, "the filter is not the published three-tap one"); |
| 741 | // Away from the step it changes nothing, which is why the fault survives a flat test. |
| 742 | req!(p[2], 0); |
| 743 | req!(p[6], 0); |
| 744 | // The leftmost column takes the corner into the filter, so it is not the sample above it. |
| 745 | req!(p[0], (60 + 2 * 0 + 0 + 2) >> 2, "the corner was left out of the filter"); |
| 746 | // And a vertical prediction repeats down every row. |
| 747 | req!(p[8], p[0]); |
| 748 | Ok(()) |
| 749 | } |
| 750 | |
| 751 | #[test] |
| 752 | fn test_an_unavailable_upper_right_is_repeated_not_read_04() -> Outcome<()> { |
| 753 | // A block at the right edge of a picture has no samples above and to the right, and the |
| 754 | // diagonal modes reach for them anyway. The substitution rule repeats `p[3, −1]`; without |
| 755 | // it the modes read whatever is in the array, which for a fresh one is nought -- a black |
| 756 | // wedge in the corner of every block along the right edge. |
| 757 | let mut e = ramp(); |
| 758 | e.right_ok = false; |
| 759 | for x in 4..16 { |
| 760 | e.top[x] = 0; |
| 761 | } |
| 762 | e.pad_right(4, 8); |
| 763 | let padded = e.right_ok; |
| 764 | req!(padded, true, "the substitution did not mark the samples available"); |
| 765 | for x in 4..8 { |
| 766 | req!(e.top[x], 13, "the sample at {} was not the repeat of p[3, -1]", x); |
| 767 | } |
| 768 | let p = pred_4x4(Mode::DiagonalDownLeft, &e, 8); |
| 769 | // Bottom right corner, which reads only the repeated samples. |
| 770 | req!(p[15], (13 + 3 * 13 + 2) >> 2); |
| 771 | let black = p[15] == 0; |
| 772 | req!(black, false, "a block at the right edge predicted from nothing"); |
| 773 | Ok(()) |
| 774 | } |
| 775 | |
| 776 | #[test] |
| 777 | fn test_the_plane_modes_fit_a_ramp_exactly_05() -> Outcome<()> { |
| 778 | // A plane fitted to edges that lie on a plane must reproduce it. The fixture is a linear |
| 779 | // ramp across and down, so every predicted sample is determined, and a sign error in |
| 780 | // either slope shows up as a picture that leans the wrong way. |
| 781 | let mut e = Edges::none(); |
| 782 | for i in 0..16i32 { |
| 783 | e.top[i as usize] = 100 + 2 * i; |
| 784 | e.left[i as usize] = 100 + 2 * i; |
| 785 | } |
| 786 | e.top_ok = true; |
| 787 | e.right_ok = true; |
| 788 | e.left_ok = true; |
| 789 | e.corner = 98; |
| 790 | e.corner_ok = true; |
| 791 | let p = pred_16x16(Mode16::Plane, &e, 8); |
| 792 | // Along the top row the prediction should climb at the same rate the edge does. |
| 793 | let step = p[1] - p[0]; |
| 794 | req!(step, 2, "the plane climbs across at {} where the edge climbs at 2", step); |
| 795 | let down = p[16] - p[0]; |
| 796 | req!(down, 2, "the plane climbs down at {} where the edge climbs at 2", down); |
| 797 | // And it must climb *up* to the right, not down: a sign error passes the step check. |
| 798 | let rising = p[15] > p[0]; |
| 799 | req!(rising, true, "the plane leans the wrong way across"); |
| 800 | let falling_down = p[240] > p[0]; |
| 801 | req!(falling_down, true, "the plane leans the wrong way down"); |
| 802 | Ok(()) |
| 803 | } |
| 804 | |
| 805 | #[test] |
| 806 | fn test_the_chroma_mean_takes_each_quarter_on_its_own_06() -> Outcome<()> { |
| 807 | // Chroma's direct current mode is four means and not one, and the two quarters off the |
| 808 | // diagonal prefer the edge they touch. A decoder that took one mean over the whole block |
| 809 | // gives a chroma plane that is smooth where the picture is not, which shows as colour |
| 810 | // bleeding across a hard edge. |
| 811 | let mut e = Edges::none(); |
| 812 | for i in 0..8 { |
| 813 | e.top[i] = if i < 4 { 20 } else { 200 }; |
| 814 | e.left[i] = if i < 4 { 30 } else { 210 }; |
| 815 | } |
| 816 | e.top_ok = true; |
| 817 | e.left_ok = true; |
| 818 | let p = pred_chroma(ModeC::Dc, &e, 8); |
| 819 | // Upper left: both edges. |
| 820 | req!(p[0], (4 * 20 + 4 * 30 + 4) >> 3); |
| 821 | // Upper right: the top alone, even though the left is available. |
| 822 | req!(p[4], (4 * 200 + 2) >> 2); |
| 823 | // Lower left: the left alone. |
| 824 | req!(p[32], (4 * 210 + 2) >> 2); |
| 825 | // Lower right: both again. |
| 826 | req!(p[36], (4 * 200 + 4 * 210 + 4) >> 3); |
| 827 | let uniform = p.iter().all(|v| *v == p[0]); |
| 828 | req!(uniform, false, "the whole chroma block took one mean"); |
| 829 | Ok(()) |
| 830 | } |
| 831 | } |