Browse Source

Fix some parsing mistakes

pull/1552/head
Brian Popow 6 years ago
parent
commit
6a1b61819f
  1. 52
      src/ImageSharp/Formats/WebP/LossyUtils.cs
  2. 20
      src/ImageSharp/Formats/WebP/Vp8BitReader.cs
  3. 18
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  4. 104
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

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

@ -177,6 +177,56 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv((byte)(dc0 >> 3), dst); Put8x8uv((byte)(dc0 >> 3), dst);
} }
public static void DC4_C(Span<byte> dst)
{
}
public static void TM4_C(Span<byte> dst)
{
}
public static void VE4_C(Span<byte> dst)
{
}
public static void HE4_C(Span<byte> dst)
{
}
public static void RD4_C(Span<byte> dst)
{
}
public static void VR4_C(Span<byte> dst)
{
}
public static void LD4_C(Span<byte> dst)
{
}
public static void VL4_C(Span<byte> dst)
{
}
public static void HD4_C(Span<byte> dst)
{
}
public static void HU4_C(Span<byte> dst)
{
}
public static void Transform(Span<short> src, Span<byte> dst, bool doTwo) public static void Transform(Span<short> src, Span<byte> dst, bool doTwo)
{ {
TransformOne(src, dst); TransformOne(src, dst);
@ -311,7 +361,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
private static byte Clip8B(int v) private static byte Clip8B(int v)
{ {
return (byte)((v & ~0xff) > 0 ? v : (v < 0) ? 0 : 255); return (byte)((v & ~0xff) is 0 ? v : (v < 0) ? 0 : 255);
} }
private static void Put8x8uv(byte value, Span<byte> dst) private static void Put8x8uv(byte value, Span<byte> dst)

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

@ -115,6 +115,26 @@ namespace SixLabors.ImageSharp.Formats.WebP
return bit ? 1 : 0; return bit ? 1 : 0;
} }
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
public int GetSigned(int v)
{
if (this.bits < 0)
{
this.LoadNewBytes();
}
int pos = this.bits;
uint split = this.range >> 1;
ulong value = this.value >> pos;
ulong mask = (split - value) >> 31; // -1 or 0
this.bits -= 1;
this.range += (uint)mask;
this.range |= 1;
this.value -= ((split + 1) & mask) << pos;
return (v ^ (int)mask) - (int)mask;
}
public bool ReadBool() public bool ReadBool()
{ {
return this.ReadValue(1) is 1; return this.ReadValue(1) is 1;

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

@ -44,6 +44,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
} }
uint width = pictureHeader.Width;
uint height = pictureHeader.Height;
// TODO: use memory allocator
this.Y = new byte[width * height];
this.U = new byte[width * height];
this.V = new byte[width * height];
this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions]; this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions];
this.Init(io); this.Init(io);
} }
@ -139,6 +147,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8TopSamples[] YuvTopSamples { get; } public Vp8TopSamples[] YuvTopSamples { get; }
public byte[] Y { get; }
public byte[] U { get; }
public byte[] V { get; }
public int YStride { get; }
public int UvStride { get; }
/// <summary> /// <summary>
/// Gets or sets filter strength info. /// Gets or sets filter strength info.
/// </summary> /// </summary>

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

@ -63,14 +63,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.ParsePartitions(decoder); this.ParsePartitions(decoder);
// Paragraph 9.6: Dequantization Indices. // Paragraph 9.6: Dequantization Indices.
this.ParseDequantizationIndices(decoder.SegmentHeader); this.ParseDequantizationIndices(decoder);
// Ignore the value of update_proba // Ignore the value of update_proba
this.bitReader.ReadBool(); this.bitReader.ReadBool();
// Paragraph 13.4: Parse probabilities. // Paragraph 13.4: Parse probabilities.
this.ParseProbabilities(decoder, decoder.Probabilities); this.ParseProbabilities(decoder);
// Decode image data.
this.ParseFrame(decoder, vp8Io); this.ParseFrame(decoder, vp8Io);
} }
@ -219,8 +220,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Init top-left sample on left column too. // Init top-left sample on left column too.
if (mby > 0) if (mby > 0)
{ {
// TODO: yuv[yOff - 1 - WebPConstants.Bps] = yuv[uOff - 1 - WebPConstants.Bps] = yuv[vOff - 1 - WebPConstants.Bps] = 129;
// yDst[-1 - WebPConstants.Bps] = uDst[-1 - WebPConstants.Bps] = vDst[-1 - WebPConstants.Bps] = 129;
} }
else else
{ {
@ -286,12 +286,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Predict and add residuals. // Predict and add residuals.
if (block.IsI4x4) if (block.IsI4x4)
{ {
// uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
if (mby > 0) if (mby > 0)
{ {
if (mbx >= dec.MbWidth - 1) if (mbx >= dec.MbWidth - 1)
{ {
// On rightmost border. // On rightmost border.
//memset(top_right, top_yuv[0].y[15], sizeof(*top_right)); // memset(top_right, top_yuv[0].y[15], sizeof(*top_right));
} }
else else
{ {
@ -300,38 +301,49 @@ 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];
// 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]; // uint8_t * const dst = y_dst + kScan[n];
Span<byte> dst = yDst.Slice(WebPConstants.KScan[n]);
byte lumaMode = block.Modes[n]; byte lumaMode = block.Modes[n];
switch (lumaMode) switch (lumaMode)
{ {
case 0: case 0:
LossyUtils.DC4_C(dst);
break; break;
case 1: case 1:
LossyUtils.TM4_C(dst);
break; break;
case 2: case 2:
LossyUtils.VE4_C(dst);
break; break;
case 3: case 3:
LossyUtils.HE4_C(dst);
break; break;
case 4: case 4:
LossyUtils.RD4_C(dst);
break; break;
case 5: case 5:
LossyUtils.VR4_C(dst);
break; break;
case 6: case 6:
LossyUtils.LD4_C(dst);
break; break;
case 7: case 7:
LossyUtils.VL4_C(dst);
break; break;
case 8: case 8:
LossyUtils.HD4_C(dst);
break; break;
case 9: case 9:
LossyUtils.HU4_C(dst);
break; break;
} }
//DoTransform(bits, coeffs + n * 16, dst); this.DoTransform(bits, coeffs.AsSpan(n * 16), dst);
} }
} }
else else
@ -409,6 +421,32 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.DoUVTransform(bitsUv >> 0, coeffs.AsSpan(16 * 16), uDst); this.DoUVTransform(bitsUv >> 0, coeffs.AsSpan(16 * 16), uDst);
this.DoUVTransform(bitsUv >> 8, coeffs.AsSpan(20 * 16), vDst); this.DoUVTransform(bitsUv >> 8, coeffs.AsSpan(20 * 16), vDst);
// Stash away top samples for next block.
if (mby < dec.MbHeight - 1)
{
yDst.Slice(15 * WebPConstants.Bps, 16).CopyTo(topYuv.Y);
uDst.Slice(7 * WebPConstants.Bps, 8).CopyTo(topYuv.U);
vDst.Slice(7 * WebPConstants.Bps, 8).CopyTo(topYuv.V);
}
// Transfer reconstructed samples from yuv_b_ cache to final destination.
int cacheId = 0; // TODO: what should be cacheId?
int yOffset = cacheId * 16 * dec.YStride;
int uvOffset = cacheId * 8 * dec.UvStride;
Span<byte> yOut = dec.Y.AsSpan((mbx * 16) + yOffset);
Span<byte> uOut = dec.U.AsSpan((mbx * 8) + uvOffset);
Span<byte> vOut = dec.V.AsSpan((mbx * 8) + uvOffset);
for (int j = 0; j < 16; ++j)
{
yDst.Slice(j * WebPConstants.Bps, 16).CopyTo(yOut.Slice(j * dec.YStride));
}
for (int j = 0; j < 8; ++j)
{
uDst.Slice(j * WebPConstants.Bps, 8).CopyTo(uOut);
vDst.Slice(j * WebPConstants.Bps, 8).CopyTo(vOut);
}
} }
} }
@ -504,13 +542,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint nonZeroY = 0; uint nonZeroY = 0;
uint nonZeroUv = 0; uint nonZeroUv = 0;
int first; int first;
var dst = new short[384];
int dstOffset = 0; int dstOffset = 0;
Vp8MacroBlockData block = dec.MacroBlockData[dec.MbX]; Vp8MacroBlockData block = dec.MacroBlockData[dec.MbX];
Vp8QuantMatrix q = dec.DeQuantMatrices[block.Segment]; Vp8QuantMatrix q = dec.DeQuantMatrices[block.Segment];
Vp8BandProbas[,] bands = dec.Probabilities.BandsPtr; Vp8BandProbas[,] bands = dec.Probabilities.BandsPtr;
Vp8BandProbas[] acProba; Vp8BandProbas[] acProba;
Vp8MacroBlock leftMb = dec.MacroBlockInfo[0]; Vp8MacroBlock leftMb = dec.MacroBlockInfo[0];
short[] dst = block.Coeffs;
if (!block.IsI4x4) if (!block.IsI4x4)
{ {
@ -519,7 +557,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int ctx = (int)(mb.NoneZeroDcCoeffs + leftMb.NoneZeroDcCoeffs); int ctx = (int)(mb.NoneZeroDcCoeffs + leftMb.NoneZeroDcCoeffs);
int nz = this.GetCoeffs(br, 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); mb.NoneZeroDcCoeffs = leftMb.NoneZeroDcCoeffs = (uint)(nz > 0 ? 1 : 0);
if (nz > 0) if (nz > 1)
{ {
// More than just the DC -> perform the full transform. // More than just the DC -> perform the full transform.
this.TransformWht(dc, dst); this.TransformWht(dc, dst);
@ -534,7 +572,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
first = 1; first = 1;
acProba = GetBandsRow(bands, 1); acProba = GetBandsRow(bands, 0);
} }
else else
{ {
@ -615,14 +653,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
Vp8ProbaArray p = prob[n].Probabilities[ctx]; Vp8ProbaArray p = prob[n].Probabilities[ctx];
for (; n < 16; ++n) for (; n < 16; ++n)
{ {
if (this.bitReader.GetBit((int)p.Probabilities[0]) is 0) if (br.GetBit(p.Probabilities[0]) is 0)
{ {
// Previous coeff was last non - zero coeff. // Previous coeff was last non - zero coeff.
return n; return n;
} }
// Sequence of zero coeffs. // Sequence of zero coeffs.
while (br.GetBit((int)p.Probabilities[1]) is 0) while (br.GetBit(p.Probabilities[1]) is 0)
{ {
p = prob[++n].Probabilities[0]; p = prob[++n].Probabilities[0];
if (n is 16) if (n is 16)
@ -633,57 +671,57 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Non zero coeffs. // Non zero coeffs.
int v; int v;
if (br.GetBit((int)p.Probabilities[2]) is 0) if (br.GetBit(p.Probabilities[2]) is 0)
{ {
v = 1; v = 1;
p = prob[n + 1].Probabilities[1]; p = prob[n + 1].Probabilities[1];
} }
else else
{ {
v = this.GetLargeValue(p.Probabilities); v = this.GetLargeValue(br, p.Probabilities);
p = prob[n + 1].Probabilities[2]; p = prob[n + 1].Probabilities[2];
} }
int idx = n > 0 ? 1 : 0; int idx = n > 0 ? 1 : 0;
coeffs[WebPConstants.Zigzag[n]] = (short)(br.ReadSignedValue(v) * dq[idx]); coeffs[WebPConstants.Zigzag[n]] = (short)(br.GetSigned(v) * dq[idx]);
} }
return 16; return 16;
} }
private int GetLargeValue(byte[] p) private int GetLargeValue(Vp8BitReader br, byte[] p)
{ {
// See section 13 - 2: http://tools.ietf.org/html/rfc6386#section-13.2 // See section 13 - 2: http://tools.ietf.org/html/rfc6386#section-13.2
int v; int v;
if (this.bitReader.GetBit(p[3]) is 0) if (br.GetBit(p[3]) is 0)
{ {
if (this.bitReader.GetBit(p[4]) is 0) if (br.GetBit(p[4]) is 0)
{ {
v = 2; v = 2;
} }
else else
{ {
v = 3 + this.bitReader.GetBit(p[5]); v = 3 + br.GetBit(p[5]);
} }
} }
else else
{ {
if (this.bitReader.GetBit(p[6]) is 0) if (br.GetBit(p[6]) is 0)
{ {
if (this.bitReader.GetBit(p[7]) is 0) if (br.GetBit(p[7]) is 0)
{ {
v = 5 + this.bitReader.GetBit(159); v = 5 + br.GetBit(159);
} }
else else
{ {
v = 7 + (2 * this.bitReader.GetBit(165)); v = 7 + (2 * br.GetBit(165));
v += this.bitReader.GetBit(145); v += br.GetBit(145);
} }
} }
else else
{ {
int bit1 = this.bitReader.GetBit(p[8]); int bit1 = br.GetBit(p[8]);
int bit0 = this.bitReader.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;
@ -708,7 +746,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int i = 0; i < tab.Length; i++) for (int i = 0; i < tab.Length; i++)
{ {
v += v + this.bitReader.GetBit(tab[i]); v += v + br.GetBit(tab[i]);
} }
v += 3 + (8 << cat); v += 3 + (8 << cat);
@ -866,8 +904,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
dec.Vp8BitReaders[lastPart] = new Vp8BitReader(this.bitReader.Data, (uint)sizeLeft, partStart); dec.Vp8BitReaders[lastPart] = new Vp8BitReader(this.bitReader.Data, (uint)sizeLeft, partStart);
} }
private void ParseDequantizationIndices(Vp8SegmentHeader vp8SegmentHeader) private void ParseDequantizationIndices(Vp8Decoder decoder)
{ {
Vp8SegmentHeader vp8SegmentHeader = decoder.SegmentHeader;
int baseQ0 = (int)this.bitReader.ReadValue(7); int baseQ0 = (int)this.bitReader.ReadValue(7);
bool hasValue = this.bitReader.ReadBool(); bool hasValue = this.bitReader.ReadBool();
int dqy1Dc = hasValue ? this.bitReader.ReadSignedValue(4) : 0; int dqy1Dc = hasValue ? this.bitReader.ReadSignedValue(4) : 0;
@ -894,7 +934,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{ {
if (i > 0) if (i > 0)
{ {
// dec->dqm_[i] = dec->dqm_[0]; decoder.DeQuantMatrices[i] = decoder.DeQuantMatrices[0];
continue; continue;
} }
else else
@ -903,7 +943,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
} }
var m = new Vp8QuantMatrix(); Vp8QuantMatrix m = decoder.DeQuantMatrices[i];
m.Y1Mat[0] = WebPConstants.DcTable[Clip(q + dqy1Dc, 127)]; m.Y1Mat[0] = WebPConstants.DcTable[Clip(q + dqy1Dc, 127)];
m.Y1Mat[1] = WebPConstants.AcTable[Clip(q + 0, 127)]; m.Y1Mat[1] = WebPConstants.AcTable[Clip(q + 0, 127)];
m.Y2Mat[0] = WebPConstants.DcTable[Clip(q + dqy2Dc, 127)] * 2; m.Y2Mat[0] = WebPConstants.DcTable[Clip(q + dqy2Dc, 127)] * 2;
@ -924,8 +964,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
} }
private void ParseProbabilities(Vp8Decoder dec, Vp8Proba proba) private void ParseProbabilities(Vp8Decoder dec)
{ {
Vp8Proba proba = dec.Probabilities;
for (int t = 0; t < WebPConstants.NumTypes; ++t) for (int t = 0; t < WebPConstants.NumTypes; ++t)
{ {
for (int b = 0; b < WebPConstants.NumBands; ++b) for (int b = 0; b < WebPConstants.NumBands; ++b)

Loading…
Cancel
Save