Browse Source

Implement functions for luma modes

pull/1552/head
Brian Popow 6 years ago
parent
commit
c55334bad6
  1. 309
      src/ImageSharp/Formats/WebP/LossyUtils.cs
  2. 2
      src/ImageSharp/Formats/WebP/Vp8BitReader.cs
  3. 25
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  4. 57
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

309
src/ImageSharp/Formats/WebP/LossyUtils.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
namespace SixLabors.ImageSharp.Formats.WebP namespace SixLabors.ImageSharp.Formats.WebP
{ {
@ -18,11 +19,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
public static void DC16_C(Span<byte> dst, byte[] yuv, int offset) public static void DC16_C(Span<byte> dst, byte[] yuv, int offset)
{ {
int dc = 16; int dc = 16;
int j; for (int j = 0; j < 16; ++j)
for (j = 0; j < 16; ++j)
{ {
// DC += dst[-1 + j * BPS] + dst[j - BPS]; // DC += dst[-1 + j * BPS] + dst[j - BPS];
dc += yuv[-1 + (j * WebPConstants.Bps) + offset] + yuv[j - WebPConstants.Bps + offset]; dc += yuv[offset - 1 + (j * WebPConstants.Bps)] + yuv[offset + j - WebPConstants.Bps];
} }
Put16(dc >> 5, dst); Put16(dc >> 5, dst);
@ -106,9 +106,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
// TrueMotion // TrueMotion
} }
public static void VE8uv_C(Span<byte> dst, Span<byte> src) public static void VE8uv_C(Span<byte> dst, byte[] yuv, int offset)
{ {
// vertical // vertical
Span<byte> src = yuv.AsSpan(offset - WebPConstants.Bps, 8);
for (int j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
// memcpy(dst + j * BPS, dst - BPS, 8); // memcpy(dst + j * BPS, dst - BPS, 8);
@ -122,9 +124,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
// memset(dst, dst[-1], 8); // memset(dst, dst[-1], 8);
// dst += BPS;
byte v = yuv[offset - 1]; byte v = yuv[offset - 1];
Memset(dst, v, 0, 8); Memset(dst, v, 0, 8);
dst = dst.Slice(WebPConstants.Bps); dst = dst.Slice(WebPConstants.Bps);
offset += WebPConstants.Bps;
} }
} }
@ -160,9 +164,19 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv(0x80, dst); Put8x8uv(0x80, dst);
} }
public static void DC4_C(Span<byte> dst) public static void DC4_C(Span<byte> dst, byte[] yuv, int offset)
{ {
int dc = 4;
for (int i = 0; i < 4; ++i)
{
dc += yuv[offset + i - WebPConstants.Bps] + yuv[offset - 1 + (i * WebPConstants.Bps)];
}
dc >>= 3;
for (int i = 0; i < 4; ++i)
{
Memset(dst, (byte)dc, i * WebPConstants.Bps, 4);
}
} }
public static void TM4_C(Span<byte> dst) public static void TM4_C(Span<byte> dst)
@ -170,44 +184,249 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
public static void VE4_C(Span<byte> dst) public static void VE4_C(Span<byte> dst, byte[] yuv, int offset)
{
}
public static void HE4_C(Span<byte> dst)
{
}
public static void RD4_C(Span<byte> dst)
{
}
public static void VR4_C(Span<byte> dst)
{ {
// vertical
int topOffset = offset - WebPConstants.Bps;
byte[] vals =
{
Avg3(yuv[topOffset - 1], yuv[topOffset], yuv[topOffset + 1]),
Avg3(yuv[topOffset], yuv[topOffset + 1], yuv[topOffset + 2]),
Avg3(yuv[topOffset + 1], yuv[topOffset + 2], yuv[topOffset + 3]),
Avg3(yuv[topOffset + 2], yuv[topOffset + 3], yuv[topOffset + 4])
};
for (int i = 0; i < 4; ++i)
{
vals.CopyTo(dst.Slice(i * WebPConstants.Bps));
}
} }
public static void LD4_C(Span<byte> dst) public static void HE4_C(Span<byte> dst, byte[] yuv, int offset)
{
}
public static void VL4_C(Span<byte> dst)
{
}
public static void HD4_C(Span<byte> dst)
{
}
public static void HU4_C(Span<byte> dst)
{ {
// horizontal
byte A = yuv[offset - 1 - WebPConstants.Bps];
byte B = yuv[offset - 1];
byte C = yuv[offset - 1 + WebPConstants.Bps];
byte D = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte E = yuv[offset - 1 + (3 * WebPConstants.Bps)];
uint val = 0x01010101U * Avg3(A, B, C);
BinaryPrimitives.WriteUInt32BigEndian(dst, val);
val = 0x01010101U * Avg3(B, C, D);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(WebPConstants.Bps), val);
val = 0x01010101U * Avg3(C, D, E);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(2 * WebPConstants.Bps), val);
val = 0x01010101U * Avg3(D, E, E);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(3 * WebPConstants.Bps), val);
}
public static void RD4_C(Span<byte> dst, byte[] yuv, int offset)
{
// Down-right
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte L = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte X = yuv[offset - 1 - WebPConstants.Bps];
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
Dst(dst, 0, 3, Avg3(J, K, L));
byte ijk = Avg3(I, J, K);
Dst(dst, 1, 3, ijk);
Dst(dst, 0, 2, ijk);
byte xij = Avg3(X, I, J);
Dst(dst, 2, 3, xij);
Dst(dst, 1, 2, xij);
Dst(dst, 0, 1, xij);
byte axi = Avg3(A, X, I);
Dst(dst, 3, 3, axi);
Dst(dst, 2, 2, axi);
Dst(dst, 1, 1, axi);
Dst(dst, 0, 0, axi);
byte bax = Avg3(B, A, X);
Dst(dst, 3, 2, bax);
Dst(dst, 2, 1, bax);
Dst(dst, 1, 0, bax);
byte cba = Avg3(C, B, A);
Dst(dst, 3, 1, cba);
Dst(dst, 2, 0, cba);
Dst(dst, 3, 0, Avg3(D, C, B));
}
public static void VR4_C(Span<byte> dst, byte[] yuv, int offset)
{
// Vertical-Right
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte X = yuv[offset - 1 - WebPConstants.Bps];
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
byte xa = Avg2(X, A);
Dst(dst, 0, 0, xa);
Dst(dst, 1, 2, xa);
byte ab = Avg2(A, B);
Dst(dst, 1, 0, ab);
Dst(dst, 2, 2, ab);
byte bc = Avg2(B, C);
Dst(dst, 2, 0, bc);
Dst(dst, 3, 2, bc);
Dst(dst, 3, 0, Avg2(C, D));
Dst(dst, 0, 3, Avg3(K, I, J));
Dst(dst, 0, 2, Avg3(J, I, X));
byte ixa = Avg3(I, X, A);
Dst(dst, 0, 1, ixa);
Dst(dst, 1, 3, ixa);
byte xab = Avg3(X, A, B);
Dst(dst, 1, 1, xab);
Dst(dst, 2, 3, xab);
byte abc = Avg3(A, B, C);
Dst(dst, 2, 1, abc);
Dst(dst, 3, 3, abc);
Dst(dst, 3, 1, Avg3(B, C, D));
}
public static void LD4_C(Span<byte> dst, byte[] yuv, int offset)
{
// Down-Left
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
byte E = yuv[offset + 4 - WebPConstants.Bps];
byte F = yuv[offset + 5 - WebPConstants.Bps];
byte G = yuv[offset + 6 - WebPConstants.Bps];
byte H = yuv[offset + 7 - WebPConstants.Bps];
Dst(dst, 0, 0, Avg3(A, B, C));
byte bcd = Avg3(B, C, D);
Dst(dst, 1, 0, bcd);
Dst(dst, 0, 1, bcd);
byte cde = Avg3(C, D, E);
Dst(dst, 2, 0, cde);
Dst(dst, 1, 1, cde);
Dst(dst, 0, 2, cde);
byte def = Avg3(D, E, F);
Dst(dst, 3, 0, def);
Dst(dst, 2, 1, def);
Dst(dst, 1, 2, def);
Dst(dst, 0, 3, def);
byte efg = Avg3(E, F, G);
Dst(dst, 3, 1, efg);
Dst(dst, 2, 2, efg);
Dst(dst, 1, 3, efg);
byte fgh = Avg3(F, G, H);
Dst(dst, 3, 2, fgh);
Dst(dst, 2, 3, fgh);
Dst(dst, 3, 3, Avg3(G, H, H));
}
public static void VL4_C(Span<byte> dst, byte[] yuv, int offset)
{
// Vertical-Left
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
byte E = yuv[offset + 4 - WebPConstants.Bps];
byte F = yuv[offset + 5 - WebPConstants.Bps];
byte G = yuv[offset + 6 - WebPConstants.Bps];
byte H = yuv[offset + 7 - WebPConstants.Bps];
Dst(dst, 0, 0, Avg2(A, B));
byte bc = Avg2(B, C);
Dst(dst, 1, 0, bc);
Dst(dst, 0, 2, bc);
byte cd = Avg2(C, D);
Dst(dst, 2, 0, cd);
Dst(dst, 1, 2, cd);
byte de = Avg2(D, E);
Dst(dst, 3, 0, de);
Dst(dst, 2, 2, de);
Dst(dst, 0, 1, Avg3(A, B, C));
byte bcd = Avg3(B, C, D);
Dst(dst, 1, 1, bcd);
Dst(dst, 0, 3, bcd);
byte cde = Avg3(C, D, E);
Dst(dst, 2, 1, cde);
Dst(dst, 1, 3, cde);
byte def = Avg3(D, E, F);
Dst(dst, 3, 1, def);
Dst(dst, 2, 3, def);
Dst(dst, 3, 2, Avg3(E, F, G));
Dst(dst, 3, 3, Avg3(F, G, H));
}
public static void HD4_C(Span<byte> dst, byte[] yuv, int offset)
{
// Horizontal-Down
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte L = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte X = yuv[offset - 1 - WebPConstants.Bps];
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte ix = Avg2(I, X);
Dst(dst, 0, 0, ix);
Dst(dst, 2, 1, ix);
byte ji = Avg2(J, I);
Dst(dst, 0, 1, ji);
Dst(dst, 2, 2, ji);
byte kj = Avg2(K, J);
Dst(dst, 0, 2, kj);
Dst(dst, 2, 3, kj);
Dst(dst, 0, 3, Avg2(L, K));
Dst(dst, 3, 0, Avg3(A, B, C));
Dst(dst, 2, 0, Avg3(X, A, B));
byte ixa = Avg3(I, X, A);
Dst(dst, 1, 0, ixa);
Dst(dst, 3, 1, ixa);
byte jix = Avg3(J, I, X);
Dst(dst, 1, 1, jix);
Dst(dst, 3, 2, jix);
byte kji = Avg3(K, J, I);
Dst(dst, 1, 2, kji);
Dst(dst, 3, 3, kji);
Dst(dst, 1, 3, Avg3(L, K, J));
}
public static void HU4_C(Span<byte> dst, byte[] yuv, int offset)
{
// Horizontal-Up
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte L = yuv[offset - 1 + (3 * WebPConstants.Bps)];
Dst(dst, 0, 0, Avg2(I, J));
byte jk = Avg2(J, K);
Dst(dst, 2, 0, jk);
Dst(dst, 0, 1, jk);
byte kl = Avg2(K, L);
Dst(dst, 2, 1, kl);
Dst(dst, 0, 2, kl);
Dst(dst, 1, 0, Avg3(I, J, K));
byte jkl = Avg3(J, K, L);
Dst(dst, 3, 0, jkl);
Dst(dst, 1, 1, jkl);
byte kll = Avg3(K, L, L);
Dst(dst, 3, 1, kll);
Dst(dst, 1, 2, kll);
Dst(dst, 3, 2, L);
Dst(dst, 2, 2, L);
Dst(dst, 0, 3, L);
Dst(dst, 1, 3, L);
Dst(dst, 2, 3, L);
Dst(dst, 3, 3, L);
} }
public static void Transform(Span<short> src, Span<byte> dst, bool doTwo) public static void Transform(Span<short> src, Span<byte> dst, bool doTwo)
@ -215,7 +434,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
TransformOne(src, dst); TransformOne(src, dst);
if (doTwo) if (doTwo)
{ {
TransformOne(src, dst); TransformOne(src.Slice(16), dst.Slice(4));
} }
} }
@ -229,8 +448,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
// vertical pass // vertical pass
int a = src[srcOffset] + src[srcOffset + 8]; // [-4096, 4094] int a = src[srcOffset] + src[srcOffset + 8]; // [-4096, 4094]
int b = src[srcOffset] - src[srcOffset + 8]; // [-4095, 4095] int b = src[srcOffset] - src[srcOffset + 8]; // [-4095, 4095]
int c = Mul2(src[4]) - Mul1(src[12]); // [-3783, 3783] int c = Mul2(src[srcOffset + 4]) - Mul1(src[srcOffset + 12]); // [-3783, 3783]
int d = Mul1(src[4]) + Mul2(src[12]); // [-3785, 3781] int d = Mul1(src[srcOffset + 4]) + Mul2(src[srcOffset + 12]); // [-3785, 3781]
tmp[tmpOffset] = a + d; // [-7881, 7875] tmp[tmpOffset] = a + d; // [-7881, 7875]
tmp[tmpOffset + 1] = b + c; // [-7878, 7878] tmp[tmpOffset + 1] = b + c; // [-7878, 7878]
tmp[tmpOffset + 2] = b - c; // [-7878, 7878] tmp[tmpOffset + 2] = b - c; // [-7878, 7878]
@ -276,7 +495,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
} }
// Simplified transform when only in[0], in[1] and in[4] are non-zero // Simplified transform when only src[0], src[1] and src[4] are non-zero
public static void TransformAc3(Span<short> src, Span<byte> dst) public static void TransformAc3(Span<short> src, Span<byte> dst)
{ {
int a = src[0] + 4; int a = src[0] + 4;
@ -330,6 +549,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
bgr[0] = (byte)YuvToB(y, u); bgr[0] = (byte)YuvToB(y, u);
bgr[1] = (byte)YuvToG(y, u, v); bgr[1] = (byte)YuvToG(y, u, v);
bgr[2] = (byte)YuvToR(y, v); bgr[2] = (byte)YuvToR(y, v);
int tmp = 0;
} }
public static int YuvToR(int y, int v) public static int YuvToR(int y, int v)
@ -412,5 +632,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
{ {
return (byte)((a + (2 * b) + c + 2) >> 2); return (byte)((a + (2 * b) + c + 2) >> 2);
} }
private static void Dst(Span<byte> dst, int x, int y, byte v)
{
dst[x + (y * WebPConstants.Bps)] = v;
}
} }
} }

2
src/ImageSharp/Formats/WebP/Vp8BitReader.cs

@ -84,8 +84,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
public int GetBit(int prob) public int GetBit(int prob)
{ {
Guard.MustBeGreaterThan(prob, 0, nameof(prob));
uint range = this.range; uint range = this.range;
if (this.bits < 0) if (this.bits < 0)
{ {

25
src/ImageSharp/Formats/WebP/Vp8Decoder.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.SegmentHeader = segmentHeader; this.SegmentHeader = segmentHeader;
this.Probabilities = probabilities; this.Probabilities = probabilities;
this.IntraL = new byte[4]; this.IntraL = new byte[4];
this.YuvBuffer = new byte[(WebPConstants.Bps * 17) + (WebPConstants.Bps * 9)]; this.YuvBuffer = new byte[2000]; // new byte[(WebPConstants.Bps * 17) + (WebPConstants.Bps * 9)];
this.MbWidth = (int)((this.PictureHeader.Width + 15) >> 4); this.MbWidth = (int)((this.PictureHeader.Width + 15) >> 4);
this.MbHeight = (int)((this.PictureHeader.Height + 15) >> 4); this.MbHeight = (int)((this.PictureHeader.Height + 15) >> 4);
this.CacheYStride = 16 * this.MbWidth; this.CacheYStride = 16 * this.MbWidth;
@ -58,6 +58,18 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.TmpVBuffer = new byte[width * height]; // TODO: figure out min buffer length this.TmpVBuffer = new byte[width * height]; // TODO: figure out min buffer length
this.Bgr = new byte[width * height * 4]; this.Bgr = new byte[width * height * 4];
for (int i = 0; i < this.YuvBuffer.Length; i++)
{
this.YuvBuffer[i] = 205;
}
for (int i = 0; i < this.CacheY.Length; i++)
{
this.CacheY[i] = 205;
this.CacheU[i] = 205;
this.CacheV[i] = 205;
}
this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions]; this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions];
this.Init(io); this.Init(io);
} }
@ -176,11 +188,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary> /// </summary>
public Vp8FilterInfo[] FilterInfo { get; set; } public Vp8FilterInfo[] FilterInfo { get; set; }
private Vp8MacroBlock leftMacroBlock;
public Vp8MacroBlock CurrentMacroBlock public Vp8MacroBlock CurrentMacroBlock
{ {
get get
{ {
return this.MacroBlockInfo[this.MbX + 1]; return this.MacroBlockInfo[this.MbX];
} }
} }
@ -188,7 +202,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
{ {
get get
{ {
return this.MacroBlockInfo[this.MbX]; if (this.leftMacroBlock is null)
{
this.leftMacroBlock = new Vp8MacroBlock();
}
return this.leftMacroBlock;
} }
} }

57
src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -129,15 +130,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
private void ParseIntraMode(Vp8Decoder dec, int mbX) private void ParseIntraMode(Vp8Decoder dec, int mbX)
{ {
Vp8MacroBlockData block = dec.MacroBlockData[mbX]; Vp8MacroBlockData block = dec.MacroBlockData[mbX];
Span<byte> top = dec.IntraT.AsSpan(4 * mbX, 4);
byte[] left = dec.IntraL; byte[] left = dec.IntraL;
byte[] top = dec.IntraT;
if (dec.SegmentHeader.UpdateMap) if (dec.SegmentHeader.UpdateMap)
{ {
// Hardcoded tree parsing. // Hardcoded tree parsing.
block.Segment = this.bitReader.GetBit((int)dec.Probabilities.Segments[0]) != 0 block.Segment = this.bitReader.GetBit((int)dec.Probabilities.Segments[0]) is 0
? (byte)this.bitReader.GetBit((int)dec.Probabilities.Segments[1]) ? (byte)this.bitReader.GetBit((int)dec.Probabilities.Segments[1])
: (byte)this.bitReader.GetBit((int)dec.Probabilities.Segments[2]); : (byte)(this.bitReader.GetBit((int)dec.Probabilities.Segments[2]) + 2);
} }
else else
{ {
@ -154,9 +155,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (!block.IsI4x4) if (!block.IsI4x4)
{ {
// Hardcoded 16x16 intra-mode decision tree. // Hardcoded 16x16 intra-mode decision tree.
int yMode = this.bitReader.GetBit(156) > 0 ? int yMode = this.bitReader.GetBit(156) != 0 ?
this.bitReader.GetBit(128) > 0 ? WebPConstants.TmPred : WebPConstants.HPred : this.bitReader.GetBit(128) != 0 ? WebPConstants.TmPred : WebPConstants.HPred :
this.bitReader.GetBit(163) > 0 ? WebPConstants.VPred : WebPConstants.DcPred; this.bitReader.GetBit(163) != 0 ? WebPConstants.VPred : WebPConstants.DcPred;
block.Modes[0] = (byte)yMode; block.Modes[0] = (byte)yMode;
for (int i = 0; i < left.Length; i++) for (int i = 0; i < left.Length; i++)
{ {
@ -192,12 +193,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Hardcoded UVMode decision tree. // Hardcoded UVMode decision tree.
block.UvMode = (byte)(this.bitReader.GetBit(142) is 0 ? 0 : block.UvMode = (byte)(this.bitReader.GetBit(142) is 0 ? 0 :
this.bitReader.GetBit(114) is 0 ? 2 : this.bitReader.GetBit(114) is 0 ? 2 :
this.bitReader.GetBit(183) > 0 ? 1 : 3); this.bitReader.GetBit(183) != 0 ? 1 : 3);
} }
private void InitScanline(Vp8Decoder dec) private void InitScanline(Vp8Decoder dec)
{ {
Vp8MacroBlock left = dec.MacroBlockInfo[0]; Vp8MacroBlock left = dec.LeftMacroBlock;
left.NoneZeroAcDcCoeffs = 0; left.NoneZeroAcDcCoeffs = 0;
left.NoneZeroDcCoeffs = 0; left.NoneZeroDcCoeffs = 0;
for (int i = 0; i < dec.IntraL.Length; i++) for (int i = 0; i < dec.IntraL.Length; i++)
@ -312,6 +313,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (block.IsI4x4) if (block.IsI4x4)
{ {
// uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16); // uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
Span<uint> topRight = MemoryMarshal.Cast<byte, uint>(yuv.AsSpan(yOff - WebPConstants.Bps + 16));
if (mby > 0) if (mby > 0)
{ {
if (mbx >= dec.MbWidth - 1) if (mbx >= dec.MbWidth - 1)
@ -326,45 +328,45 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
// Replicate the top-right pixels below. // Replicate the top-right pixels below.
// top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0]; //topRight[WebPConstants.Bps] = topRight[2 * WebPConstants.Bps] = topRight[3 * WebPConstants.Bps] = topRight[0];
// Predict and add residuals for all 4x4 blocks in turn. // Predict and add residuals for all 4x4 blocks in turn.
for (int n = 0; n < 16; ++n, bits <<= 2) for (int n = 0; n < 16; ++n, bits <<= 2)
{ {
// uint8_t * const dst = y_dst + kScan[n]; int offset = yOff + WebPConstants.Scan[n];
Span<byte> dst = yDst.Slice(WebPConstants.Scan[n]); Span<byte> dst = yuv.AsSpan(offset);
byte lumaMode = block.Modes[n]; byte lumaMode = block.Modes[n];
switch (lumaMode) switch (lumaMode)
{ {
case 0: case 0:
LossyUtils.DC4_C(dst); LossyUtils.DC4_C(dst, yuv, offset);
break; break;
case 1: case 1:
LossyUtils.TM4_C(dst); LossyUtils.TM4_C(dst);
break; break;
case 2: case 2:
LossyUtils.VE4_C(dst); LossyUtils.VE4_C(dst, yuv, offset);
break; break;
case 3: case 3:
LossyUtils.HE4_C(dst); LossyUtils.HE4_C(dst, yuv, offset);
break; break;
case 4: case 4:
LossyUtils.RD4_C(dst); LossyUtils.RD4_C(dst, yuv, offset);
break; break;
case 5: case 5:
LossyUtils.VR4_C(dst); LossyUtils.VR4_C(dst, yuv, offset);
break; break;
case 6: case 6:
LossyUtils.LD4_C(dst); LossyUtils.LD4_C(dst, yuv, offset);
break; break;
case 7: case 7:
LossyUtils.VL4_C(dst); LossyUtils.VL4_C(dst, yuv, offset);
break; break;
case 8: case 8:
LossyUtils.HD4_C(dst); LossyUtils.HD4_C(dst, yuv, offset);
break; break;
case 9: case 9:
LossyUtils.HU4_C(dst); LossyUtils.HU4_C(dst, yuv, offset);
break; break;
} }
@ -423,8 +425,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
LossyUtils.TM8uv_C(vDst); LossyUtils.TM8uv_C(vDst);
break; break;
case 2: case 2:
LossyUtils.VE8uv_C(uDst, yuv.AsSpan(uOff - WebPConstants.Bps, 8)); LossyUtils.VE8uv_C(uDst, yuv, uOff);
LossyUtils.VE8uv_C(vDst, yuv.AsSpan(vOff - WebPConstants.Bps, 8)); LossyUtils.VE8uv_C(vDst, yuv, vOff);
break; break;
case 3: case 3:
LossyUtils.HE8uv_C(uDst, yuv, uOff); LossyUtils.HE8uv_C(uDst, yuv, uOff);
@ -647,7 +649,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
luv = uv; luv = uv;
} }
/*if ((len & 1) is 0) if ((len & 1) is 0)
{ {
uv0 = ((3 * tluv) + luv + 0x00020002u) >> 2; uv0 = ((3 * tluv) + luv + 0x00020002u) >> 2;
LossyUtils.YuvToBgr(topY[len - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), topDst.Slice((len - 1) * xStep)); LossyUtils.YuvToBgr(topY[len - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), topDst.Slice((len - 1) * xStep));
@ -656,7 +658,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
uv0 = ((3 * luv) + tluv + 0x00020002u) >> 2; uv0 = ((3 * luv) + tluv + 0x00020002u) >> 2;
LossyUtils.YuvToBgr(bottomY[len - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), bottomDst.Slice((len - 1) * xStep)); LossyUtils.YuvToBgr(bottomY[len - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), bottomDst.Slice((len - 1) * xStep));
} }
}*/ }
} }
private void DoTransform(uint bits, Span<short> src, Span<byte> dst) private void DoTransform(uint bits, Span<short> src, Span<byte> dst)
@ -773,6 +775,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
else else
{ {
// Only DC is non-zero -> inlined simplified transform.
int dc0 = (dc[0] + 3) >> 3; int dc0 = (dc[0] + 3) >> 3;
for (int i = 0; i < 16 * 16; i += 16) for (int i = 0; i < 16 * 16; i += 16)
{ {
@ -930,7 +933,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
else else
{ {
int bit1 = br.GetBit(p[8]); int bit1 = br.GetBit(p[8]);
int bit0 = br.GetBit(p[9] + bit1); int bit0 = br.GetBit(p[9 + bit1]);
int cat = (2 * bit1) + bit0; int cat = (2 * bit1) + bit0;
v = 0; v = 0;
byte[] tab = null; byte[] tab = null;
@ -1016,14 +1019,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int i = 0; i < vp8SegmentHeader.Quantizer.Length; i++) for (int i = 0; i < vp8SegmentHeader.Quantizer.Length; i++)
{ {
hasValue = this.bitReader.ReadBool(); hasValue = this.bitReader.ReadBool();
uint quantizeValue = hasValue ? this.bitReader.ReadValue(7) : 0; int quantizeValue = hasValue ? this.bitReader.ReadSignedValue(7) : 0;
vp8SegmentHeader.Quantizer[i] = (byte)quantizeValue; vp8SegmentHeader.Quantizer[i] = (byte)quantizeValue;
} }
for (int i = 0; i < vp8SegmentHeader.FilterStrength.Length; i++) for (int i = 0; i < vp8SegmentHeader.FilterStrength.Length; i++)
{ {
hasValue = this.bitReader.ReadBool(); hasValue = this.bitReader.ReadBool();
uint filterStrengthValue = hasValue ? this.bitReader.ReadValue(6) : 0; int filterStrengthValue = hasValue ? this.bitReader.ReadSignedValue(6) : 0;
vp8SegmentHeader.FilterStrength[i] = (byte)filterStrengthValue; vp8SegmentHeader.FilterStrength[i] = (byte)filterStrengthValue;
} }

Loading…
Cancel
Save