diff --git a/src/ImageSharp/Formats/WebP/Vp8Decoder.cs b/src/ImageSharp/Formats/WebP/Vp8Decoder.cs
index 24d329e5b..872ddf36e 100644
--- a/src/ImageSharp/Formats/WebP/Vp8Decoder.cs
+++ b/src/ImageSharp/Formats/WebP/Vp8Decoder.cs
@@ -19,16 +19,20 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.YuvBuffer = new byte[(WebPConstants.Bps * 17) + (WebPConstants.Bps * 9)];
this.MbWidth = (int)((this.PictureHeader.Width + 15) >> 4);
this.MbHeight = (int)((this.PictureHeader.Height + 15) >> 4);
- this.MacroBlockInfo = new Vp8MacroBlock[this.MbWidth];
+ this.MacroBlockInfo = new Vp8MacroBlock[this.MbWidth + 1];
this.MacroBlockData = new Vp8MacroBlockData[this.MbWidth];
this.YuvTopSamples = new Vp8TopSamples[this.MbWidth];
+ this.FilterInfo = new Vp8FilterInfo[this.MbWidth];
for (int i = 0; i < this.MbWidth; i++)
{
this.MacroBlockInfo[i] = new Vp8MacroBlock();
this.MacroBlockData[i] = new Vp8MacroBlockData();
this.YuvTopSamples[i] = new Vp8TopSamples();
+ this.FilterInfo[i] = new Vp8FilterInfo();
}
+ this.MacroBlockInfo[this.MbWidth] = new Vp8MacroBlock();
+
this.DeQuantMatrices = new Vp8QuantMatrix[WebPConstants.NumMbSegments];
this.FilterStrength = new Vp8FilterInfo[WebPConstants.NumMbSegments, 2];
for (int i = 0; i < WebPConstants.NumMbSegments; i++)
@@ -123,12 +127,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8MacroBlockData[] MacroBlockData { get; }
///
- /// Gets contextual macroblock infos.
+ /// Gets contextual contextual macroblock info (mbw + 1).
///
public Vp8MacroBlock[] MacroBlockInfo { get; }
- public int MacroBlockIdx { get; set; }
-
public LoopFilter Filter { get; set; }
public Vp8FilterInfo[,] FilterStrength { get; }
@@ -140,7 +142,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
/// Gets or sets filter strength info.
///
- public Vp8FilterInfo FilterInfo { get; set; }
+ public Vp8FilterInfo[] FilterInfo { get; set; }
public void Init(Vp8Io io)
{
diff --git a/src/ImageSharp/Formats/WebP/Vp8FilterInfo.cs b/src/ImageSharp/Formats/WebP/Vp8FilterInfo.cs
index 4204386bc..bb6c6da17 100644
--- a/src/ImageSharp/Formats/WebP/Vp8FilterInfo.cs
+++ b/src/ImageSharp/Formats/WebP/Vp8FilterInfo.cs
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
/// Gets or sets a value indicating whether to do inner filtering.
///
- public bool InnerFiltering { get; set; }
+ public byte InnerFiltering { get; set; }
///
/// Gets or sets the high edge variance threshold in [0..2].
diff --git a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
index ed5a7a0b9..8c8915e00 100644
--- a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
+++ b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
@@ -78,6 +78,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
for (dec.MbY = 0; dec.MbY < dec.BottomRightMbY; ++dec.MbY)
{
+ // Parse bitstream for this row.
+ long bitreaderIdx = dec.MbY & dec.NumPartsMinusOne;
+ Vp8BitReader bitreader = dec.Vp8BitReaders[bitreaderIdx];
+
// Parse intra mode mode row.
for (int mbX = 0; mbX < dec.MbWidth; ++mbX)
{
@@ -86,7 +90,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (; dec.MbX < dec.MbWidth; ++dec.MbX)
{
- this.DecodeMacroBlock(dec);
+ this.DecodeMacroBlock(dec, bitreader);
}
// Prepare for next scanline.
@@ -168,7 +172,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
private void InitScanline(Vp8Decoder dec)
{
- Vp8MacroBlock left = dec.MacroBlockInfo[dec.MacroBlockIdx - 1];
+ Vp8MacroBlock left = dec.MacroBlockInfo[0];
left.NoneZeroAcDcCoeffs = 0;
left.NoneZeroDcCoeffs = 0;
for (int i = 0; i < dec.IntraL.Length; i++)
@@ -324,16 +328,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
- private void DecodeMacroBlock(Vp8Decoder dec)
+ private void DecodeMacroBlock(Vp8Decoder dec, Vp8BitReader bitreader)
{
- Vp8MacroBlock left = dec.MacroBlockInfo[dec.MacroBlockIdx - 1]; // TODO: not sure if this - 1 is correct here
- Vp8MacroBlock macroBlock = dec.MacroBlockInfo[dec.MacroBlockIdx + dec.MbX];
- Vp8MacroBlockData blockData = dec.MacroBlockData[dec.MacroBlockIdx + dec.MbX];
+ Vp8MacroBlock left = dec.MacroBlockInfo[0];
+ Vp8MacroBlock macroBlock = dec.MacroBlockInfo[1 + dec.MbX];
+ Vp8MacroBlockData blockData = dec.MacroBlockData[dec.MbX];
int skip = dec.UseSkipProbability ? blockData.Skip : 0;
if (skip is 0)
{
- this.ParseResiduals(dec, macroBlock);
+ this.ParseResiduals(dec, bitreader, macroBlock);
}
else
{
@@ -348,29 +352,33 @@ namespace SixLabors.ImageSharp.Formats.WebP
blockData.Dither = 0;
}
- // TODO: store filter info
+ // Store filter info.
+ if (dec.Filter != LoopFilter.None)
+ {
+ dec.FilterInfo[dec.MbX] = dec.FilterStrength[blockData.Segment, blockData.IsI4x4 ? 1 : 0];
+ dec.FilterInfo[dec.MbX].InnerFiltering |= (byte)(skip is 0 ? 1 : 0);
+ }
}
- private bool ParseResiduals(Vp8Decoder decoder, Vp8MacroBlock mb)
+ private bool ParseResiduals(Vp8Decoder dec, Vp8BitReader br, Vp8MacroBlock mb)
{
- byte tnz, lnz;
uint nonZeroY = 0;
uint nonZeroUv = 0;
int first;
var dst = new short[384];
- var dstOffset = 0;
- Vp8MacroBlockData block = decoder.MacroBlockData[decoder.MbX];
- Vp8QuantMatrix q = decoder.DeQuantMatrices[block.Segment];
- Vp8BandProbas[,] bands = decoder.Probabilities.BandsPtr;
+ int dstOffset = 0;
+ Vp8MacroBlockData block = dec.MacroBlockData[dec.MbX];
+ Vp8QuantMatrix q = dec.DeQuantMatrices[block.Segment];
+ Vp8BandProbas[,] bands = dec.Probabilities.BandsPtr;
Vp8BandProbas[] acProba;
- Vp8MacroBlock leftMb = null; // TODO: this value needs to be set
+ Vp8MacroBlock leftMb = dec.MacroBlockInfo[0];
if (!block.IsI4x4)
{
// Parse DC
var dc = new short[16];
int ctx = (int)(mb.NoneZeroDcCoeffs + leftMb.NoneZeroDcCoeffs);
- int nz = this.GetCoeffs(GetBandsRow(bands, 1), ctx, q.Y2Mat, 0, dc);
+ int nz = this.GetCoeffs(br, GetBandsRow(bands, 1), ctx, q.Y2Mat, 0, dc);
mb.NoneZeroDcCoeffs = leftMb.NoneZeroDcCoeffs = (uint)(nz > 0 ? 1 : 0);
if (nz > 0)
{
@@ -395,8 +403,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
acProba = GetBandsRow(bands, 3);
}
- tnz = (byte)(mb.NoneZeroAcDcCoeffs & 0x0f);
- lnz = (byte)(leftMb.NoneZeroAcDcCoeffs & 0x0f);
+ byte tnz = (byte)(mb.NoneZeroAcDcCoeffs & 0x0f);
+ byte lnz = (byte)(leftMb.NoneZeroAcDcCoeffs & 0x0f);
for (int y = 0; y < 4; ++y)
{
@@ -405,7 +413,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int x = 0; x < 4; ++x)
{
int ctx = l + (tnz & 1);
- int nz = this.GetCoeffs(acProba, ctx, q.Y1Mat, first, dst.AsSpan(dstOffset));
+ int nz = this.GetCoeffs(br, acProba, ctx, q.Y1Mat, first, dst.AsSpan(dstOffset));
l = (nz > first) ? 1 : 0;
tnz = (byte)((tnz >> 1) | (l << 7));
nzCoeffs = NzCodeBits(nzCoeffs, nz, dst[0] != 0 ? 1 : 0);
@@ -431,7 +439,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int x = 0; x < 2; ++x)
{
int ctx = l + (tnz & 1);
- int nz = this.GetCoeffs(GetBandsRow(bands, 2), ctx, q.UvMat, 0, dst.AsSpan(dstOffset));
+ int nz = this.GetCoeffs(br, GetBandsRow(bands, 2), ctx, q.UvMat, 0, dst.AsSpan(dstOffset));
l = (nz > 0) ? 1 : 0;
tnz = (byte)((tnz >> 1) | (l << 3));
nzCoeffs = NzCodeBits(nzCoeffs, nz, dst[0] != 0 ? 1 : 0);
@@ -462,7 +470,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return (nonZeroY | nonZeroUv) is 0;
}
- private int GetCoeffs(Vp8BandProbas[] prob, int ctx, int[] dq, int n, Span coeffs)
+ private int GetCoeffs(Vp8BitReader br, Vp8BandProbas[] prob, int ctx, int[] dq, int n, Span coeffs)
{
// Returns the position of the last non - zero coeff plus one.
Vp8ProbaArray p = prob[n].Probabilities[ctx];
@@ -475,7 +483,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
// Sequence of zero coeffs.
- while (this.bitReader.GetBit((int)p.Probabilities[1]) is 0)
+ while (br.GetBit((int)p.Probabilities[1]) is 0)
{
p = prob[++n].Probabilities[0];
if (n is 16)
@@ -486,7 +494,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Non zero coeffs.
int v;
- if (this.bitReader.GetBit((int)p.Probabilities[2]) is 0)
+ if (br.GetBit((int)p.Probabilities[2]) is 0)
{
v = 1;
p = prob[n + 1].Probabilities[1];
@@ -498,7 +506,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
int idx = n > 0 ? 1 : 0;
- coeffs[WebPConstants.Zigzag[n]] = (short)(this.bitReader.ReadSignedValue(v) * dq[idx]);
+ coeffs[WebPConstants.Zigzag[n]] = (short)(br.ReadSignedValue(v) * dq[idx]);
}
return 16;