Skip to content

Commit

Permalink
Use iterators in intra_predict_chroma, intra_predict_luma, tmpred (#17)
Browse files Browse the repository at this point in the history
Split access pattern in `predict_luma` so that top_border can copy from ws
instead of shuffling bytes in the combined loop with left_border

In `predict_tmpred`, use `split_at_mut` to split the `above` row which allows
us to keep a reference to it while mutating the pixels after.
  • Loading branch information
okaneco authored Dec 17, 2023
1 parent 6a7c385 commit 123e967
Showing 1 changed file with 52 additions and 14 deletions.
66 changes: 52 additions & 14 deletions src/vp8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1496,18 +1496,27 @@ impl<R: Read> Vp8Decoder<R> {

self.left_border[0] = ws[16];

for i in 0usize..16 {
self.top_border[mbx * 16 + i] = ws[16 * stride + 1 + i];
self.left_border[i + 1] = ws[(i + 1) * stride + 16];
for (i, left) in self.left_border[1..][..16].iter_mut().enumerate() {
*left = ws[(i + 1) * stride + 16];
}

for (top, &w) in self.top_border[mbx * 16..][..16]
.iter_mut()
.zip(&ws[16 * stride + 1..][..16])
{
*top = w;
}

// Length is the remainder to the border, but maximally the current chunk.
let ylength = cmp::min(self.frame.height as usize - mby * 16, 16);
let xlength = cmp::min(self.frame.width as usize - mbx * 16, 16);

for y in 0usize..ylength {
for x in 0usize..xlength {
self.frame.ybuf[(mby * 16 + y) * w + mbx * 16 + x] = ws[(1 + y) * stride + 1 + x];
for (ybuf, &ws) in self.frame.ybuf[(mby * 16 + y) * w + mbx * 16..][..xlength]
.iter_mut()
.zip(ws[(1 + y) * stride + 1..][..xlength].iter())
{
*ybuf = ws;
}
}
}
Expand Down Expand Up @@ -1601,9 +1610,17 @@ impl<R: Read> Vp8Decoder<R> {
}

for y in 0usize..ylength {
for x in 0usize..xlength {
self.frame.ubuf[(mby * 8 + y) * w + mbx * 8 + x] = uws[(1 + y) * stride + 1 + x];
self.frame.vbuf[(mby * 8 + y) * w + mbx * 8 + x] = vws[(1 + y) * stride + 1 + x];
let uv_buf_index = (mby * 8 + y) * w + mbx * 8;
let ws_index = (1 + y) * stride + 1;

for (((ub, vb), &uw), &vw) in self.frame.ubuf[uv_buf_index..][..xlength]
.iter_mut()
.zip(self.frame.vbuf[uv_buf_index..][..xlength].iter_mut())
.zip(uws[ws_index..][..xlength].iter())
.zip(vws[ws_index..][..xlength].iter())
{
*ub = uw;
*vb = vw;
}
}
}
Expand Down Expand Up @@ -2357,14 +2374,35 @@ fn predict_dcpred(a: &mut [u8], size: usize, stride: usize, above: bool, left: b
}

fn predict_tmpred(a: &mut [u8], size: usize, x0: usize, y0: usize, stride: usize) {
// The formula for tmpred is:
// X_ij = L_i + A_j - P (i, j=0, 1, 2, 3)
//
// |-----|-----|-----|-----|-----|
// | P | A0 | A1 | A2 | A3 |
// |-----|-----|-----|-----|-----|
// | L0 | X00 | X01 | X02 | X03 |
// |-----|-----|-----|-----|-----|
// | L1 | X10 | X11 | X12 | X13 |
// |-----|-----|-----|-----|-----|
// | L2 | X20 | X21 | X22 | X23 |
// |-----|-----|-----|-----|-----|
// | L3 | X30 | X31 | X32 | X33 |
// |-----|-----|-----|-----|-----|
// Diagram from p. 52 of RFC 6386

// Split at L0
let (above, x_block) = a.split_at_mut(y0 * stride + (x0 - 1));
let p = i32::from(above[(y0 - 1) * stride + x0 - 1]);
let above_slice = &above[(y0 - 1) * stride + x0..];

for y in 0usize..size {
for x in 0usize..size {
let pred = i32::from(a[(y0 + y) * stride + x0 - 1])
+ i32::from(a[(y0 - 1) * stride + x0 + x])
- i32::from(a[(y0 - 1) * stride + x0 - 1]);
let left_minus_p = i32::from(x_block[y * stride]) - p;

a[(x + x0) + stride * (y + y0)] = clamp(pred, 0, 255) as u8;
}
// Add 1 to skip over L0 byte
x_block[y * stride + 1..][..size]
.iter_mut()
.zip(above_slice)
.for_each(|(cur, &abv)| *cur = (left_minus_p + i32::from(abv)).max(0).min(255) as u8);
}
}

Expand Down

0 comments on commit 123e967

Please sign in to comment.