From 0424e74a0e1e22e30173267dd2f9401d71c0eff2 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Thu, 26 Jun 2014 13:29:30 +1000 Subject: [PATCH] go.image/vp8: implement the normal filter. The testdata was generated via: cwebp foo.png -o foo.lossy.webp dwebp -pgm foo.lossy.webp -o tmp.pgm convert tmp.pgm foo.lossy.webp.ycbcr.png rm tmp.pgm TBR=r R=r CC=golang-codereviews https://golang.org/cl/107330043 --- testdata/blue-purple-pink.lossy.webp | Bin 0 -> 2450 bytes .../blue-purple-pink.lossy.webp.ycbcr.png | Bin 0 -> 11482 bytes .../{video-001.webp => video-001.lossy.webp} | Bin ...bcr.png => video-001.lossy.webp.ycbcr.png} | Bin testdata/yellow_rose.lossy.webp.ycbcr.png | Bin 0 -> 60923 bytes vp8/decode.go | 2 +- vp8/filter.go | 420 +++++++++++++++--- webp/decode_test.go | 148 +++--- 8 files changed, 432 insertions(+), 138 deletions(-) create mode 100644 testdata/blue-purple-pink.lossy.webp create mode 100644 testdata/blue-purple-pink.lossy.webp.ycbcr.png rename testdata/{video-001.webp => video-001.lossy.webp} (100%) rename testdata/{video-001.webp.ycbcr.png => video-001.lossy.webp.ycbcr.png} (100%) create mode 100644 testdata/yellow_rose.lossy.webp.ycbcr.png diff --git a/testdata/blue-purple-pink.lossy.webp b/testdata/blue-purple-pink.lossy.webp new file mode 100644 index 0000000000000000000000000000000000000000..d5143c0afd987bf88f4afe7550216c09dc99fe47 GIT binary patch literal 2450 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 s=MB_=0YC88hjKV+?qb^rhX literal 0 HcmV?d00001 diff --git a/testdata/video-001.webp b/testdata/video-001.lossy.webp similarity index 100% rename from testdata/video-001.webp rename to testdata/video-001.lossy.webp diff --git a/testdata/video-001.webp.ycbcr.png b/testdata/video-001.lossy.webp.ycbcr.png similarity index 100% rename from testdata/video-001.webp.ycbcr.png rename to testdata/video-001.lossy.webp.ycbcr.png diff --git a/testdata/yellow_rose.lossy.webp.ycbcr.png b/testdata/yellow_rose.lossy.webp.ycbcr.png new file mode 100644 index 0000000000000000000000000000000000000000..5e3bcd8972c57c70443ae6cd4b54da3ca000a30a GIT binary patch literal 60923 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 literal 0 HcmV?d00001 diff --git a/vp8/decode.go b/vp8/decode.go index ab1115c..41daee6 100644 --- a/vp8/decode.go +++ b/vp8/decode.go @@ -368,7 +368,7 @@ func (d *Decoder) DecodeFrame() (*image.YCbCr, error) { if d.filterHeader.simple { d.simpleFilter() } else { - // TODO(nigeltao): normal filtering. + d.normalFilter() } } return d.img, nil diff --git a/vp8/filter.go b/vp8/filter.go index aa7e119..9a52451 100644 --- a/vp8/filter.go +++ b/vp8/filter.go @@ -4,14 +4,14 @@ package vp8 -// filter2 modifies a 2-pixel-wide or 2-pixel-high band along an edge. -func filter2(pix []byte, thresh int, index int, iStep int, jStep int) { - for i := 0; i < 16; i, index = i+1, index+iStep { +// 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 int(lutAbs[lutAbsBase+p0-q0])<<1+int(lutAbs[lutAbsBase+p1-q1])>>1 > thresh { + if int(lutAbs[lutAbsBase+p0-q0])<<1+int(lutAbs[lutAbsBase+p1-q1])>>1 > level { continue } a := 3*(q0-p0) + int(lutClamp127[lutClamp127Base+p1-q1]) @@ -22,32 +22,126 @@ func filter2(pix []byte, thresh int, index int, iStep int, jStep int) { } } -// TODO(nigeltao): filter4 and filter6 functions, for normal filtering. +// 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 int(lutAbs[lutAbsBase+p0-q0])<<1+int(lutAbs[lutAbsBase+p1-q1])>>1 > level { + continue + } + if int(lutAbs[lutAbsBase+p3-p2]) > ilevel || + int(lutAbs[lutAbsBase+p2-p1]) > ilevel || + int(lutAbs[lutAbsBase+p1-p0]) > ilevel || + int(lutAbs[lutAbsBase+q1-q0]) > ilevel || + int(lutAbs[lutAbsBase+q2-q1]) > ilevel || + int(lutAbs[lutAbsBase+q3-q2]) > ilevel { + continue + } + if int(lutAbs[lutAbsBase+p1-p0]) > hlevel || int(lutAbs[lutAbsBase+q1-q0]) > hlevel { + // Filter 2 pixels. + a := 3*(q0-p0) + int(lutClamp127[lutClamp127Base+p1-q1]) + a1 := int(lutClamp15[lutClamp15Base+((a+4)>>3)]) + a2 := int(lutClamp15[lutClamp15Base+((a+3)>>3)]) + pix[index-1*jStep] = lutClamp255[lutClamp255Base+p0+a2] + pix[index+0*jStep] = lutClamp255[lutClamp255Base+q0-a1] + } else if fourNotSix { + // Filter 4 pixels. + a := 3 * (q0 - p0) + a1 := int(lutClamp15[lutClamp15Base+((a+4)>>3)]) + a2 := int(lutClamp15[lutClamp15Base+((a+3)>>3)]) + a3 := (a1 + 1) >> 1 + pix[index-2*jStep] = lutClamp255[lutClamp255Base+p1+a3] + pix[index-1*jStep] = lutClamp255[lutClamp255Base+p0+a2] + pix[index+0*jStep] = lutClamp255[lutClamp255Base+q0-a1] + pix[index+1*jStep] = lutClamp255[lutClamp255Base+q1-a3] + } else { + // Filter 6 pixels. + a := 3*(q0-p0) + int(lutClamp127[lutClamp127Base+p1-q1]) + a = int(lutClamp127[lutClamp127Base+a]) + a1 := (27*a + 63) >> 7 + a2 := (18*a + 63) >> 7 + a3 := (9*a + 63) >> 7 + pix[index-3*jStep] = lutClamp255[lutClamp255Base+p2+a3] + pix[index-2*jStep] = lutClamp255[lutClamp255Base+p1+a2] + pix[index-1*jStep] = lutClamp255[lutClamp255Base+p0+a1] + pix[index+0*jStep] = lutClamp255[lutClamp255Base+q0-a1] + pix[index+1*jStep] = lutClamp255[lutClamp255Base+q1-a2] + pix[index+2*jStep] = lutClamp255[lutClamp255Base+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.limit == 0 { + if f.level == 0 { continue } - index := (mby*d.img.YStride + mbx) * 16 + l := int(f.level) + yIndex := (mby*d.img.YStride + mbx) * 16 if mbx > 0 { - filter2(d.img.Y, int(f.limit)+4, index, d.img.YStride, 1) + filter2(d.img.Y, l+4, yIndex, d.img.YStride, 1) } if f.inner { - filter2(d.img.Y, int(f.limit), index+4, d.img.YStride, 1) - filter2(d.img.Y, int(f.limit), index+8, d.img.YStride, 1) - filter2(d.img.Y, int(f.limit), index+12, d.img.YStride, 1) + 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, int(f.limit)+4, index, 1, d.img.YStride) + filter2(d.img.Y, l+4, yIndex, 1, d.img.YStride) } if f.inner { - filter2(d.img.Y, int(f.limit), index+d.img.YStride*4, 1, d.img.YStride) - filter2(d.img.Y, int(f.limit), index+d.img.YStride*8, 1, d.img.YStride) - filter2(d.img.Y, int(f.limit), index+d.img.YStride*12, 1, d.img.YStride) + 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) } } } @@ -55,10 +149,14 @@ func (d *Decoder) simpleFilter() { // filterParam holds the loop filter parameters for a macroblock. type filterParam struct { - limit uint8 - inner bool - innerLevel uint8 - hevThresh uint8 + // 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 @@ -85,7 +183,7 @@ func (d *Decoder) computeFilterParams() { } } if level <= 0 { - p.limit = 0 + p.level = 0 continue } if level > 63 { @@ -105,25 +203,25 @@ func (d *Decoder) computeFilterParams() { if ilevel < 1 { ilevel = 1 } - p.innerLevel = uint8(ilevel) - p.limit = uint8(2*level + ilevel) + p.ilevel = uint8(ilevel) + p.level = uint8(2*level + ilevel) if d.frameHeader.KeyFrame { if level < 15 { - p.hevThresh = 0 + p.hlevel = 0 } else if level < 40 { - p.hevThresh = 1 + p.hlevel = 1 } else { - p.hevThresh = 2 + p.hlevel = 2 } } else { if level < 15 { - p.hevThresh = 0 + p.hlevel = 0 } else if level < 20 { - p.hevThresh = 1 + p.hlevel = 1 } else if level < 40 { - p.hevThresh = 2 + p.hlevel = 2 } else { - p.hevThresh = 3 + p.hlevel = 3 } } } @@ -243,10 +341,10 @@ var lutClamp15 = [255 + 1 + 255]int8{ +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, } -const lutClamp127Base = 255 +const lutClamp127Base = 1020 -// lutClamp127[lutClamp127Base+x] is equal to clamp(x, -128, +127), for x in [-255, 255]. -var lutClamp127 = [255 + 1 + 255]int8{ +// lutClamp127[lutClamp127Base+x] is equal to clamp(x, -128, +127), for x in [-1020, 1020]. +var lutClamp127 = [1020 + 1 + 1020]int8{ -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, @@ -263,38 +361,134 @@ var lutClamp127 = [255 + 1 + 255]int8{ -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, - -0x7f, -0x7e, -0x7d, -0x7c, -0x7b, -0x7a, -0x79, -0x78, - -0x77, -0x76, -0x75, -0x74, -0x73, -0x72, -0x71, -0x70, - -0x6f, -0x6e, -0x6d, -0x6c, -0x6b, -0x6a, -0x69, -0x68, - -0x67, -0x66, -0x65, -0x64, -0x63, -0x62, -0x61, -0x60, - -0x5f, -0x5e, -0x5d, -0x5c, -0x5b, -0x5a, -0x59, -0x58, - -0x57, -0x56, -0x55, -0x54, -0x53, -0x52, -0x51, -0x50, - -0x4f, -0x4e, -0x4d, -0x4c, -0x4b, -0x4a, -0x49, -0x48, - -0x47, -0x46, -0x45, -0x44, -0x43, -0x42, -0x41, -0x40, - -0x3f, -0x3e, -0x3d, -0x3c, -0x3b, -0x3a, -0x39, -0x38, - -0x37, -0x36, -0x35, -0x34, -0x33, -0x32, -0x31, -0x30, - -0x2f, -0x2e, -0x2d, -0x2c, -0x2b, -0x2a, -0x29, -0x28, - -0x27, -0x26, -0x25, -0x24, -0x23, -0x22, -0x21, -0x20, - -0x1f, -0x1e, -0x1d, -0x1c, -0x1b, -0x1a, -0x19, -0x18, - -0x17, -0x16, -0x15, -0x14, -0x13, -0x12, -0x11, -0x10, - -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08, - -0x07, -0x06, -0x05, -0x04, -0x03, -0x02, -0x01, +0x00, - +0x01, +0x02, +0x03, +0x04, +0x05, +0x06, +0x07, +0x08, - +0x09, +0x0a, +0x0b, +0x0c, +0x0d, +0x0e, +0x0f, +0x10, - +0x11, +0x12, +0x13, +0x14, +0x15, +0x16, +0x17, +0x18, - +0x19, +0x1a, +0x1b, +0x1c, +0x1d, +0x1e, +0x1f, +0x20, - +0x21, +0x22, +0x23, +0x24, +0x25, +0x26, +0x27, +0x28, - +0x29, +0x2a, +0x2b, +0x2c, +0x2d, +0x2e, +0x2f, +0x30, - +0x31, +0x32, +0x33, +0x34, +0x35, +0x36, +0x37, +0x38, - +0x39, +0x3a, +0x3b, +0x3c, +0x3d, +0x3e, +0x3f, +0x40, - +0x41, +0x42, +0x43, +0x44, +0x45, +0x46, +0x47, +0x48, - +0x49, +0x4a, +0x4b, +0x4c, +0x4d, +0x4e, +0x4f, +0x50, - +0x51, +0x52, +0x53, +0x54, +0x55, +0x56, +0x57, +0x58, - +0x59, +0x5a, +0x5b, +0x5c, +0x5d, +0x5e, +0x5f, +0x60, - +0x61, +0x62, +0x63, +0x64, +0x65, +0x66, +0x67, +0x68, - +0x69, +0x6a, +0x6b, +0x6c, +0x6d, +0x6e, +0x6f, +0x70, - +0x71, +0x72, +0x73, +0x74, +0x75, +0x76, +0x77, +0x78, - +0x79, +0x7a, +0x7b, +0x7c, +0x7d, +0x7e, +0x7f, +0x7f, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, + -0x80, -0x80, -0x80, -0x80, -0x80, -0x7f, -0x7e, -0x7d, + -0x7c, -0x7b, -0x7a, -0x79, -0x78, -0x77, -0x76, -0x75, + -0x74, -0x73, -0x72, -0x71, -0x70, -0x6f, -0x6e, -0x6d, + -0x6c, -0x6b, -0x6a, -0x69, -0x68, -0x67, -0x66, -0x65, + -0x64, -0x63, -0x62, -0x61, -0x60, -0x5f, -0x5e, -0x5d, + -0x5c, -0x5b, -0x5a, -0x59, -0x58, -0x57, -0x56, -0x55, + -0x54, -0x53, -0x52, -0x51, -0x50, -0x4f, -0x4e, -0x4d, + -0x4c, -0x4b, -0x4a, -0x49, -0x48, -0x47, -0x46, -0x45, + -0x44, -0x43, -0x42, -0x41, -0x40, -0x3f, -0x3e, -0x3d, + -0x3c, -0x3b, -0x3a, -0x39, -0x38, -0x37, -0x36, -0x35, + -0x34, -0x33, -0x32, -0x31, -0x30, -0x2f, -0x2e, -0x2d, + -0x2c, -0x2b, -0x2a, -0x29, -0x28, -0x27, -0x26, -0x25, + -0x24, -0x23, -0x22, -0x21, -0x20, -0x1f, -0x1e, -0x1d, + -0x1c, -0x1b, -0x1a, -0x19, -0x18, -0x17, -0x16, -0x15, + -0x14, -0x13, -0x12, -0x11, -0x10, -0x0f, -0x0e, -0x0d, + -0x0c, -0x0b, -0x0a, -0x09, -0x08, -0x07, -0x06, -0x05, + -0x04, -0x03, -0x02, -0x01, +0x00, +0x01, +0x02, +0x03, + +0x04, +0x05, +0x06, +0x07, +0x08, +0x09, +0x0a, +0x0b, + +0x0c, +0x0d, +0x0e, +0x0f, +0x10, +0x11, +0x12, +0x13, + +0x14, +0x15, +0x16, +0x17, +0x18, +0x19, +0x1a, +0x1b, + +0x1c, +0x1d, +0x1e, +0x1f, +0x20, +0x21, +0x22, +0x23, + +0x24, +0x25, +0x26, +0x27, +0x28, +0x29, +0x2a, +0x2b, + +0x2c, +0x2d, +0x2e, +0x2f, +0x30, +0x31, +0x32, +0x33, + +0x34, +0x35, +0x36, +0x37, +0x38, +0x39, +0x3a, +0x3b, + +0x3c, +0x3d, +0x3e, +0x3f, +0x40, +0x41, +0x42, +0x43, + +0x44, +0x45, +0x46, +0x47, +0x48, +0x49, +0x4a, +0x4b, + +0x4c, +0x4d, +0x4e, +0x4f, +0x50, +0x51, +0x52, +0x53, + +0x54, +0x55, +0x56, +0x57, +0x58, +0x59, +0x5a, +0x5b, + +0x5c, +0x5d, +0x5e, +0x5f, +0x60, +0x61, +0x62, +0x63, + +0x64, +0x65, +0x66, +0x67, +0x68, +0x69, +0x6a, +0x6b, + +0x6c, +0x6d, +0x6e, +0x6f, +0x70, +0x71, +0x72, +0x73, + +0x74, +0x75, +0x76, +0x77, +0x78, +0x79, +0x7a, +0x7b, + +0x7c, +0x7d, +0x7e, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, @@ -310,7 +504,103 @@ var lutClamp127 = [255 + 1 + 255]int8{ +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, - +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, +0x7f, + +0x7f, } const lutClamp255Base = 255 diff --git a/webp/decode_test.go b/webp/decode_test.go index 37d6913..635c5d0 100644 --- a/webp/decode_test.go +++ b/webp/decode_test.go @@ -31,82 +31,85 @@ func hex(x []byte) string { } func TestDecodeVP8(t *testing.T) { - // The original video-001.png image is 150x103. - const w, h = 150, 103 - // w2 and h2 are the half-width and half-height, rounded up. - const w2, h2 = int((w + 1) / 2), int((h + 1) / 2) - - f0, err := os.Open("../testdata/video-001.webp.ycbcr.png") - if err != nil { - t.Fatal(err) - } - defer f0.Close() - img0, err := png.Decode(f0) - if err != nil { - t.Fatal(err) + testCases := []string{ + "blue-purple-pink", + "video-001", + "yellow_rose", } - // The split-into-YCbCr-planes golden image is a 2*w2 wide and h+h2 high - // gray image arranged in IMC4 format: - // YYYY - // YYYY - // BBRR - // See http://www.fourcc.org/yuv.php#IMC4 - if got, want := img0.Bounds(), image.Rect(0, 0, 2*w2, h+h2); got != want { - t.Fatalf("bounds0: got %v, want %v", got, want) - } - m0, ok := img0.(*image.Gray) - if !ok { - t.Fatal("decoded PNG image is not a Gray") - } + for _, tc := range testCases { + f0, err := os.Open("../testdata/" + tc + ".lossy.webp") + if err != nil { + t.Fatal(err) + } + defer f0.Close() + img0, err := Decode(f0) + if err != nil { + t.Fatal(err) + } - f1, err := os.Open("../testdata/video-001.webp") - if err != nil { - t.Fatal(err) - } - defer f1.Close() - img1, err := Decode(f1) - if err != nil { - t.Fatal(err) - } + m0, ok := img0.(*image.YCbCr) + if !ok || m0.SubsampleRatio != image.YCbCrSubsampleRatio420 { + t.Fatal("decoded WEBP image is not a 4:2:0 YCbCr") + } + // w2 and h2 are the half-width and half-height, rounded up. + w, h := m0.Bounds().Dx(), m0.Bounds().Dy() + w2, h2 := int((w+1)/2), int((h+1)/2) - if got, want := img1.Bounds(), image.Rect(0, 0, w, h); got != want { - t.Fatalf("bounds1: got %v, want %v", got, want) - } - m1, ok := img1.(*image.YCbCr) - if !ok || m1.SubsampleRatio != image.YCbCrSubsampleRatio420 { - t.Fatal("decoded WEBP image is not a 4:2:0 YCbCr") - } + f1, err := os.Open("../testdata/" + tc + ".lossy.webp.ycbcr.png") + if err != nil { + t.Fatal(err) + } + defer f1.Close() + img1, err := png.Decode(f1) + if err != nil { + t.Fatal(err) + } - planes := []struct { - name string - m1Pix []uint8 - m1Stride int - m0Rect image.Rectangle - }{ - {"Y", m1.Y, m1.YStride, image.Rect(0, 0, w, h)}, - {"Cb", m1.Cb, m1.CStride, image.Rect(0*w2, h, 1*w2, h+h2)}, - {"Cr", m1.Cr, m1.CStride, image.Rect(1*w2, h, 2*w2, h+h2)}, - } - for _, plane := range planes { - dx := plane.m0Rect.Dx() - nDiff, diff := 0, make([]byte, dx) - for j, y := 0, plane.m0Rect.Min.Y; y < plane.m0Rect.Max.Y; j, y = j+1, y+1 { - got := plane.m1Pix[j*plane.m1Stride:][:dx] - want := m0.Pix[y*m0.Stride+plane.m0Rect.Min.X:][:dx] - if bytes.Equal(got, want) { - continue + // The split-into-YCbCr-planes golden image is a 2*w2 wide and h+h2 high + // gray image arranged in IMC4 format: + // YYYY + // YYYY + // BBRR + // See http://www.fourcc.org/yuv.php#IMC4 + if got, want := img1.Bounds(), image.Rect(0, 0, 2*w2, h+h2); got != want { + t.Fatalf("bounds0: got %v, want %v", got, want) + } + m1, ok := img1.(*image.Gray) + if !ok { + t.Fatal("decoded PNG image is not a Gray") + } + + planes := []struct { + name string + m0Pix []uint8 + m0Stride int + m1Rect image.Rectangle + }{ + {"Y", m0.Y, m0.YStride, image.Rect(0, 0, w, h)}, + {"Cb", m0.Cb, m0.CStride, image.Rect(0*w2, h, 1*w2, h+h2)}, + {"Cr", m0.Cr, m0.CStride, image.Rect(1*w2, h, 2*w2, h+h2)}, + } + for _, plane := range planes { + dx := plane.m1Rect.Dx() + nDiff, diff := 0, make([]byte, dx) + for j, y := 0, plane.m1Rect.Min.Y; y < plane.m1Rect.Max.Y; j, y = j+1, y+1 { + got := plane.m0Pix[j*plane.m0Stride:][:dx] + want := m1.Pix[y*m1.Stride+plane.m1Rect.Min.X:][:dx] + if bytes.Equal(got, want) { + continue + } + nDiff++ + if nDiff > 10 { + t.Errorf("%s plane: more rows differ", plane.name) + break + } + for i := range got { + diff[i] = got[i] - want[i] + } + t.Errorf("%s plane: m0 row %d, m1 row %d\ngot %s\nwant%s\ndiff%s", + plane.name, j, y, hex(got), hex(want), hex(diff)) } - nDiff++ - if nDiff > 10 { - t.Errorf("%s plane: more rows differ", plane.name) - break - } - for i := range got { - diff[i] = got[i] - want[i] - } - t.Errorf("%s plane: m0 row %d, m1 row %d\ngot %s\nwant%s\ndiff%s", - plane.name, y, j, hex(got), hex(want), hex(diff)) } } } @@ -210,5 +213,6 @@ func benchmarkDecode(b *testing.B, filename string) { } } -func BenchmarkDecodeVP8(b *testing.B) { benchmarkDecode(b, "yellow_rose.lossy") } -func BenchmarkDecodeVP8L(b *testing.B) { benchmarkDecode(b, "yellow_rose.lossless") } +func BenchmarkDecodeVP8SimpleFilter(b *testing.B) { benchmarkDecode(b, "blue-purple-pink.lossy") } +func BenchmarkDecodeVP8NormalFilter(b *testing.B) { benchmarkDecode(b, "yellow_rose.lossy") } +func BenchmarkDecodeVP8L(b *testing.B) { benchmarkDecode(b, "yellow_rose.lossless") }