Oregami
Repositories/oxedyne/fe2o3

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
32use 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)]
40pub 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
50impl 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
85fn 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.
90fn 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)]
99pub 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
111impl 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.
148fn 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`].
164pub 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.
287fn 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.
300pub 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.
340pub 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)]
468pub 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
475impl 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).
491pub 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)]
544pub enum ModeC {
545 Dc, // the mean, taken separately over each four-by-four quarter
546 Horizontal,
547 Vertical,
548 Plane,
549}
550
551impl 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).
567pub 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)]
649mod 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}