// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package vp8 // filter2 modifies a 2-pixel wide or 2-pixel high band along an edge. func filter2(pix []byte, level, index, iStep, jStep int) { for n := 16; n > 0; n, index = n-1, index+iStep { p1 := int(pix[index-2*jStep]) p0 := int(pix[index-1*jStep]) q0 := int(pix[index+0*jStep]) q1 := int(pix[index+1*jStep]) if abs(p0-q0)<<1+abs(p1-q1)>>1 > level { continue } a := 3*(q0-p0) + clamp127(p1-q1) a1 := clamp15((a + 4) >> 3) a2 := clamp15((a + 3) >> 3) pix[index-1*jStep] = clamp255(p0 + a2) pix[index+0*jStep] = clamp255(q0 - a1) } } // filter246 modifies a 2-, 4- or 6-pixel wide or high band along an edge. func filter246(pix []byte, n, level, ilevel, hlevel, index, iStep, jStep int, fourNotSix bool) { for ; n > 0; n, index = n-1, index+iStep { p3 := int(pix[index-4*jStep]) p2 := int(pix[index-3*jStep]) p1 := int(pix[index-2*jStep]) p0 := int(pix[index-1*jStep]) q0 := int(pix[index+0*jStep]) q1 := int(pix[index+1*jStep]) q2 := int(pix[index+2*jStep]) q3 := int(pix[index+3*jStep]) if abs(p0-q0)<<1+abs(p1-q1)>>1 > level { continue } if abs(p3-p2) > ilevel || abs(p2-p1) > ilevel || abs(p1-p0) > ilevel || abs(q1-q0) > ilevel || abs(q2-q1) > ilevel || abs(q3-q2) > ilevel { continue } if abs(p1-p0) > hlevel || abs(q1-q0) > hlevel { // Filter 2 pixels. a := 3*(q0-p0) + clamp127(p1-q1) a1 := clamp15((a + 4) >> 3) a2 := clamp15((a + 3) >> 3) pix[index-1*jStep] = clamp255(p0 + a2) pix[index+0*jStep] = clamp255(q0 - a1) } else if fourNotSix { // Filter 4 pixels. a := 3 * (q0 - p0) a1 := clamp15((a + 4) >> 3) a2 := clamp15((a + 3) >> 3) a3 := (a1 + 1) >> 1 pix[index-2*jStep] = clamp255(p1 + a3) pix[index-1*jStep] = clamp255(p0 + a2) pix[index+0*jStep] = clamp255(q0 - a1) pix[index+1*jStep] = clamp255(q1 - a3) } else { // Filter 6 pixels. a := clamp127(3*(q0-p0) + clamp127(p1-q1)) a1 := (27*a + 63) >> 7 a2 := (18*a + 63) >> 7 a3 := (9*a + 63) >> 7 pix[index-3*jStep] = clamp255(p2 + a3) pix[index-2*jStep] = clamp255(p1 + a2) pix[index-1*jStep] = clamp255(p0 + a1) pix[index+0*jStep] = clamp255(q0 - a1) pix[index+1*jStep] = clamp255(q1 - a2) pix[index+2*jStep] = clamp255(q2 - a3) } } } // simpleFilter implements the simple filter, as specified in section 15.2. func (d *Decoder) simpleFilter() { for mby := 0; mby < d.mbh; mby++ { for mbx := 0; mbx < d.mbw; mbx++ { f := d.perMBFilterParams[d.mbw*mby+mbx] if f.level == 0 { continue } l := int(f.level) yIndex := (mby*d.img.YStride + mbx) * 16 if mbx > 0 { filter2(d.img.Y, l+4, yIndex, d.img.YStride, 1) } if f.inner { filter2(d.img.Y, l, yIndex+0x4, d.img.YStride, 1) filter2(d.img.Y, l, yIndex+0x8, d.img.YStride, 1) filter2(d.img.Y, l, yIndex+0xc, d.img.YStride, 1) } if mby > 0 { filter2(d.img.Y, l+4, yIndex, 1, d.img.YStride) } if f.inner { filter2(d.img.Y, l, yIndex+d.img.YStride*0x4, 1, d.img.YStride) filter2(d.img.Y, l, yIndex+d.img.YStride*0x8, 1, d.img.YStride) filter2(d.img.Y, l, yIndex+d.img.YStride*0xc, 1, d.img.YStride) } } } } // normalFilter implements the normal filter, as specified in section 15.3. func (d *Decoder) normalFilter() { for mby := 0; mby < d.mbh; mby++ { for mbx := 0; mbx < d.mbw; mbx++ { f := d.perMBFilterParams[d.mbw*mby+mbx] if f.level == 0 { continue } l, il, hl := int(f.level), int(f.ilevel), int(f.hlevel) yIndex := (mby*d.img.YStride + mbx) * 16 cIndex := (mby*d.img.CStride + mbx) * 8 if mbx > 0 { filter246(d.img.Y, 16, l+4, il, hl, yIndex, d.img.YStride, 1, false) filter246(d.img.Cb, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false) filter246(d.img.Cr, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false) } if f.inner { filter246(d.img.Y, 16, l, il, hl, yIndex+0x4, d.img.YStride, 1, true) filter246(d.img.Y, 16, l, il, hl, yIndex+0x8, d.img.YStride, 1, true) filter246(d.img.Y, 16, l, il, hl, yIndex+0xc, d.img.YStride, 1, true) filter246(d.img.Cb, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true) filter246(d.img.Cr, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true) } if mby > 0 { filter246(d.img.Y, 16, l+4, il, hl, yIndex, 1, d.img.YStride, false) filter246(d.img.Cb, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false) filter246(d.img.Cr, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false) } if f.inner { filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x4, 1, d.img.YStride, true) filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x8, 1, d.img.YStride, true) filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0xc, 1, d.img.YStride, true) filter246(d.img.Cb, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true) filter246(d.img.Cr, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true) } } } } // filterParam holds the loop filter parameters for a macroblock. type filterParam struct { // The first three fields are thresholds used by the loop filter to smooth // over the edges and interior of a macroblock. level is used by both the // simple and normal filters. The inner level and high edge variance level // are only used by the normal filter. level, ilevel, hlevel uint8 // inner is whether the inner loop filter cannot be optimized out as a // no-op for this particular macroblock. inner bool } // computeFilterParams computes the loop filter parameters, as specified in // section 15.4. func (d *Decoder) computeFilterParams() { for i := range d.filterParams { baseLevel := d.filterHeader.level if d.segmentHeader.useSegment { baseLevel = d.segmentHeader.filterStrength[i] if d.segmentHeader.relativeDelta { baseLevel += d.filterHeader.level } } for j := range d.filterParams[i] { p := &d.filterParams[i][j] p.inner = j != 0 level := baseLevel if d.filterHeader.useLFDelta { // The libwebp C code has a "TODO: only CURRENT is handled for now." level += d.filterHeader.refLFDelta[0] if j != 0 { level += d.filterHeader.modeLFDelta[0] } } if level <= 0 { p.level = 0 continue } if level > 63 { level = 63 } ilevel := level if d.filterHeader.sharpness > 0 { if d.filterHeader.sharpness > 4 { ilevel >>= 2 } else { ilevel >>= 1 } if x := int8(9 - d.filterHeader.sharpness); ilevel > x { ilevel = x } } if ilevel < 1 { ilevel = 1 } p.ilevel = uint8(ilevel) p.level = uint8(2*level + ilevel) if d.frameHeader.KeyFrame { if level < 15 { p.hlevel = 0 } else if level < 40 { p.hlevel = 1 } else { p.hlevel = 2 } } else { if level < 15 { p.hlevel = 0 } else if level < 20 { p.hlevel = 1 } else if level < 40 { p.hlevel = 2 } else { p.hlevel = 3 } } } } } // intSize is either 32 or 64. const intSize = 32 << (^uint(0) >> 63) func abs(x int) int { // m := -1 if x < 0. m := 0 otherwise. m := x >> (intSize - 1) // In two's complement representation, the negative number // of any number (except the smallest one) can be computed // by flipping all the bits and add 1. This is faster than // code with a branch. // See Hacker's Delight, section 2-4. return (x ^ m) - m } func clamp15(x int) int { if x < -16 { return -16 } if x > 15 { return 15 } return x } func clamp127(x int) int { if x < -128 { return -128 } if x > 127 { return 127 } return x } func clamp255(x int) uint8 { if x < 0 { return 0 } if x > 255 { return 255 } return uint8(x) }