Browse Source

Implement Parse Partitions

pull/1552/head
Brian Popow 6 years ago
parent
commit
9838e2e512
  1. 4
      src/ImageSharp/Formats/WebP/BitReaderBase.cs
  2. 4
      src/ImageSharp/Formats/WebP/VP8BandProbas.cs
  3. 44
      src/ImageSharp/Formats/WebP/Vp8BitReader.cs
  4. 60
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  5. 3
      src/ImageSharp/Formats/WebP/Vp8MacroBlockData.cs
  6. 16
      src/ImageSharp/Formats/WebP/Vp8Proba.cs
  7. 6
      src/ImageSharp/Formats/WebP/Vp8QuantMatrix.cs
  8. 14
      src/ImageSharp/Formats/WebP/Vp8TopSamples.cs
  9. 3
      src/ImageSharp/Formats/WebP/WebPConstants.cs
  10. 22
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
  11. 9
      src/ImageSharp/Formats/WebP/WebPImageInfo.cs
  12. 227
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

4
src/ImageSharp/Formats/WebP/BitReaderBase.cs

@ -15,9 +15,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
internal abstract class BitReaderBase
{
/// <summary>
/// Gets raw encoded image data.
/// Gets or sets the raw encoded image data.
/// </summary>
protected byte[] Data { get; private set; }
public byte[] Data { get; set; }
/// <summary>
/// Copies the raw encoded image data from the stream into a byte array.

4
src/ImageSharp/Formats/WebP/VP8BandProbas.cs

@ -11,6 +11,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8BandProbas()
{
this.Probabilities = new Vp8ProbaArray[WebPConstants.NumCtx];
for (int i = 0; i < WebPConstants.NumCtx; i++)
{
this.Probabilities[i] = new Vp8ProbaArray();
}
}
public Vp8ProbaArray[] Probabilities { get; }

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

@ -32,9 +32,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
private int bits;
/// <summary>
/// The next byte to be read.
/// Max packed-read position on buffer.
/// </summary>
private byte buf;
private uint bufferMax;
private uint bufferEnd;
/// <summary>
/// True if input is exhausted.
@ -53,10 +55,20 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <param name="imageDataSize">The raw image data size in bytes.</param>
/// <param name="memoryAllocator">Used for allocating memory during reading data from the stream.</param>
/// <param name="startPos">Start index in the data array. Defaults to 0.</param>
public Vp8BitReader(Stream inputStream, uint imageDataSize, MemoryAllocator memoryAllocator, int startPos = 0)
public Vp8BitReader(Stream inputStream, uint imageDataSize, MemoryAllocator memoryAllocator, uint partitionLength, int startPos = 0)
{
this.ImageDataSize = imageDataSize;
this.PartitionLength = partitionLength;
this.ReadImageDataFromStream(inputStream, (int)imageDataSize, memoryAllocator);
this.InitBitreader(startPos);
this.InitBitreader(partitionLength, startPos);
}
public Vp8BitReader(byte[] imageData, uint partitionLength, int startPos = 0)
{
this.Data = imageData;
this.ImageDataSize = (uint)imageData.Length;
this.PartitionLength = partitionLength;
this.InitBitreader(partitionLength, startPos);
}
public int Pos
@ -64,6 +76,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
get { return (int)this.pos; }
}
public uint ImageDataSize { get; }
public uint PartitionLength { get; }
public uint Remaining { get; set; }
public int GetBit(int prob)
{
Guard.MustBeGreaterThan(prob, 0, nameof(prob));
@ -123,26 +141,26 @@ namespace SixLabors.ImageSharp.Formats.WebP
return this.ReadValue(1) != 0 ? -value : value;
}
private void InitBitreader(int pos = 0)
private void InitBitreader(uint size, int pos = 0)
{
this.range = 255 - 1;
this.value = 0;
this.bits = -8; // to load the very first 8bits.
this.bits = -8; // to load the very first 8 bits.
this.eof = false;
this.pos = 0;
this.pos = pos;
this.bufferEnd = (uint)(pos + size);
this.bufferMax = (uint)(size > 8 ? pos + size - 8 + 1 : pos);
this.LoadNewBytes();
}
private void LoadNewBytes()
{
if (this.pos < this.Data.Length)
if (this.pos < this.bufferMax)
{
ulong bits;
ulong inBits = BinaryPrimitives.ReadUInt64LittleEndian(this.Data.AsSpan().Slice((int)this.pos, 8));
ulong inBits = BinaryPrimitives.ReadUInt64LittleEndian(this.Data.AsSpan((int)this.pos, 8));
this.pos += BitsCount >> 3;
this.buf = this.Data[this.pos];
bits = this.ByteSwap64(inBits);
ulong bits = this.ByteSwap64(inBits);
bits >>= 64 - BitsCount;
this.value = bits | (this.value << BitsCount);
this.bits += BitsCount;
@ -156,7 +174,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
private void LoadFinalBytes()
{
// Only read 8bits at a time.
if (this.pos < this.Data.Length)
if (this.pos < this.bufferEnd)
{
this.bits += 8;
this.value = this.Data[this.pos++] | (this.value << 8);

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

@ -15,10 +15,32 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.FilterHeader = filterHeader;
this.SegmentHeader = segmentHeader;
this.Probabilities = probabilities;
this.IntraL = new byte[4];
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.MacroBlockData = new Vp8MacroBlockData[this.MbWidth];
this.YuvTopSamples = new Vp8TopSamples[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.DeQuantMatrices = new Vp8QuantMatrix[WebPConstants.NumMbSegments];
this.FilterStrength = new Vp8FilterInfo[WebPConstants.NumMbSegments, 2];
this.IntraL = new byte[4];
for (int i = 0; i < WebPConstants.NumMbSegments; i++)
{
this.DeQuantMatrices[i] = new Vp8QuantMatrix();
for (int j = 0; j < 2; j++)
{
this.FilterStrength[i, j] = new Vp8FilterInfo();
}
}
this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions];
this.Init(io);
}
@ -30,14 +52,20 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8SegmentHeader SegmentHeader { get; }
// number of partitions minus one.
public uint NumPartsMinusOne { get; }
// per-partition boolean decoders.
public Vp8BitReader[] Vp8BitReaders { get; }
public bool Dither { get; set; }
/// <summary>
/// Gets or sets dequantization matrices (one set of DC/AC dequant factor per segment).
/// </summary>
public Vp8QuantMatrix[] DeQuantMatrices { get; private set; }
public Vp8QuantMatrix[] DeQuantMatrices { get; }
public bool UseSkipProba { get; set; }
public bool UseSkipProbability { get; set; }
public byte SkipProbability { get; set; }
@ -52,12 +80,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <summary>
/// Gets or sets the width in macroblock units.
/// </summary>
public int MbWidth { get; set; }
public int MbWidth { get; }
/// <summary>
/// Gets or sets the height in macroblock units.
/// </summary>
public int MbHeight { get; set; }
public int MbHeight { get; }
/// <summary>
/// Gets or sets the top-left x index of the macroblock that must be in-loop filtered.
@ -72,7 +100,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <summary>
/// Gets or sets the last bottom-right x index of the macroblock that must be decoded.
/// </summary>
public int BotomRightMbX { get; set; }
public int BottomRightMbX { get; set; }
/// <summary>
/// Gets or sets the last bottom-right y index of the macroblock that must be decoded.
@ -90,14 +118,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
public int MbY { get; set; }
/// <summary>
/// Gets or sets the parsed reconstruction data.
/// Gets the parsed reconstruction data.
/// </summary>
public Vp8MacroBlockData[] MacroBlockData { get; set; }
public Vp8MacroBlockData[] MacroBlockData { get; }
/// <summary>
/// Gets or sets contextual macroblock infos.
/// Gets contextual macroblock infos.
/// </summary>
public Vp8MacroBlock[] MacroBlockInfo { get; set; }
public Vp8MacroBlock[] MacroBlockInfo { get; }
public int MacroBlockIdx { get; set; }
@ -105,6 +133,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8FilterInfo[,] FilterStrength { get; }
public byte[] YuvBuffer { get; }
public Vp8TopSamples[] YuvTopSamples { get; }
/// <summary>
/// Gets or sets filter strength info.
/// </summary>
@ -112,8 +144,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
public void Init(Vp8Io io)
{
this.MbWidth = (int)((this.PictureHeader.Width + 15) >> 4);
this.MbHeight = (int)((this.PictureHeader.Height + 15) >> 4);
int intraPredModeSize = 4 * this.MbWidth;
this.IntraT = new byte[intraPredModeSize];
@ -157,10 +187,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
// We need some 'extra' pixels on the right/bottom.
this.BottomRightMbY = (io.CropBottom + 15 + extraPixels) >> 4;
this.BotomRightMbX = (io.CropRight + 15 + extraPixels) >> 4;
if (this.BotomRightMbX > this.MbWidth)
this.BottomRightMbX = (io.CropRight + 15 + extraPixels) >> 4;
if (this.BottomRightMbX > this.MbWidth)
{
this.BotomRightMbX = this.MbWidth;
this.BottomRightMbX = this.MbWidth;
}
if (this.BottomRightMbY > this.MbHeight)

3
src/ImageSharp/Formats/WebP/Vp8MacroBlockData.cs

@ -11,12 +11,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8MacroBlockData()
{
this.Modes = new byte[16];
this.Coeffs = new short[384];
}
/// <summary>
/// Gets or sets the coefficient. 384 coeffs = (16+4+4) * 4*4.
/// </summary>
public short Coeffs { get; set; }
public short[] Coeffs { get; set; }
/// <summary>
/// Gets or sets a value indicating whether its intra4x4.

16
src/ImageSharp/Formats/WebP/Vp8Proba.cs

@ -15,6 +15,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.Segments = new uint[MbFeatureTreeProbs];
this.Bands = new Vp8BandProbas[WebPConstants.NumTypes, WebPConstants.NumBands];
this.BandsPtr = new Vp8BandProbas[WebPConstants.NumTypes, 16 + 1];
for (int i = 0; i < WebPConstants.NumTypes; i++)
{
for (int j = 0; j < WebPConstants.NumBands; j++)
{
this.Bands[i, j] = new Vp8BandProbas();
}
}
for (int i = 0; i < WebPConstants.NumTypes; i++)
{
for (int j = 0; j < 17; j++)
{
this.BandsPtr[i, j] = new Vp8BandProbas();
}
}
}
public uint[] Segments { get; }

6
src/ImageSharp/Formats/WebP/Vp8QuantMatrix.cs

@ -5,11 +5,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
internal class Vp8QuantMatrix
{
public int[] Y1Mat { get; set; }
public int[] Y1Mat { get; } = new int[2];
public int[] Y2Mat { get; set; }
public int[] Y2Mat { get; } = new int[2];
public int[] UvMat { get; set; }
public int[] UvMat { get; } = new int[2];
/// <summary>
/// Gets or sets the U/V quantizer value.

14
src/ImageSharp/Formats/WebP/Vp8TopSamples.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.WebP
{
internal class Vp8TopSamples
{
public byte[] Y { get; } = new byte[16];
public byte[] U { get; } = new byte[8];
public byte[] V { get; } = new byte[8];
}
}

3
src/ImageSharp/Formats/WebP/WebPConstants.cs

@ -121,6 +121,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
public const int NumCtx = 3;
// this is the common stride for enc/dec
public const int Bps = 32;
// intra prediction modes (TODO: maybe use an enum for this)
public const int DcPred = 0;
public const int TmPred = 1;

22
src/ImageSharp/Formats/WebP/WebPDecoderCore.cs

@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
// remaining counts the available image data payload.
uint remaining = dataSize;
// See paragraph 9.1 https://tools.ietf.org/html/rfc6386#page-30
// Paragraph 9.1 https://tools.ietf.org/html/rfc6386#page-30
// Frame tag that contains four fields:
// - A 1-bit frame type (0 for key frames, 1 for interframes).
// - A 3-bit version number.
@ -359,31 +359,21 @@ namespace SixLabors.ImageSharp.Formats.WebP
var bitReader = new Vp8BitReader(
this.currentStream,
remaining,
this.memoryAllocator);
// Paragraph 9.2: color space and clamp type follow.
sbyte colorSpace = (sbyte)bitReader.ReadValue(1);
sbyte clampType = (sbyte)bitReader.ReadValue(1);
var vp8PictureHeader = new Vp8PictureHeader()
{
Width = (uint)width,
Height = (uint)height,
XScale = xScale,
YScale = yScale,
ColorSpace = colorSpace,
ClampType = clampType
};
this.memoryAllocator,
partitionLength);
bitReader.Remaining = remaining;
return new WebPImageInfo()
{
Width = width,
Height = height,
XScale = xScale,
YScale = yScale,
BitsPerPixel = features?.Alpha is true ? WebPBitsPerPixel.Pixel32 : WebPBitsPerPixel.Pixel24,
IsLossLess = false,
Features = features,
Vp8Profile = (sbyte)version,
Vp8FrameHeader = vp8FrameHeader,
Vp8PictureHeader = vp8PictureHeader,
Vp8BitReader = bitReader
};
}

9
src/ImageSharp/Formats/WebP/WebPImageInfo.cs

@ -15,6 +15,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public uint Height { get; set; }
public sbyte XScale { get; set; }
public sbyte YScale { get; set; }
/// <summary>
/// Gets or sets the bits per pixel.
/// </summary>
@ -40,11 +44,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public Vp8FrameHeader Vp8FrameHeader { get; set; }
/// <summary>
/// Gets or sets the VP8 picture header.
/// </summary>
public Vp8PictureHeader Vp8PictureHeader { get; set; }
/// <summary>
/// Gets or sets the VP8L bitreader. Will be null, if its not lossless image.
/// </summary>

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

@ -36,6 +36,19 @@ namespace SixLabors.ImageSharp.Formats.WebP
// TODO residue signal from DCT: 4x4 blocks of DCT transforms, 16Y, 4U, 4V
Vp8Profile vp8Profile = this.DecodeProfile(info.Vp8Profile);
// Paragraph 9.2: color space and clamp type follow.
sbyte colorSpace = (sbyte)this.bitReader.ReadValue(1);
sbyte clampType = (sbyte)this.bitReader.ReadValue(1);
var vp8PictureHeader = new Vp8PictureHeader()
{
Width = (uint)width,
Height = (uint)height,
XScale = info.XScale,
YScale = info.YScale,
ColorSpace = colorSpace,
ClampType = clampType
};
// Paragraph 9.3: Parse the segment header.
var proba = new Vp8Proba();
Vp8SegmentHeader vp8SegmentHeader = this.ParseSegmentHeader(proba);
@ -43,23 +56,21 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Paragraph 9.4: Parse the filter specs.
Vp8FilterHeader vp8FilterHeader = this.ParseFilterHeader();
// TODO: Review Paragraph 9.5: ParsePartitions.
int numPartsMinusOne = (1 << (int)this.bitReader.ReadValue(2)) - 1;
int lastPart = numPartsMinusOne;
// TODO: check if we have enough data available here, throw exception if not
int partStart = this.bitReader.Pos + (lastPart * 3);
var vp8Io = default(Vp8Io);
var decoder = new Vp8Decoder(info.Vp8FrameHeader, vp8PictureHeader, vp8FilterHeader, vp8SegmentHeader, proba, vp8Io);
// Paragraph 9.5: Parse partitions.
this.ParsePartitions(decoder);
// Paragraph 9.6: Dequantization Indices.
this.ParseDequantizationIndices(vp8SegmentHeader);
this.ParseDequantizationIndices(decoder.SegmentHeader);
// Ignore the value of update_proba
this.bitReader.ReadBool();
// Paragraph 13.4: Parse probabilities.
this.ParseProbabilities(proba);
this.ParseProbabilities(decoder, decoder.Probabilities);
var vp8Io = default(Vp8Io);
var decoder = new Vp8Decoder(info.Vp8FrameHeader, info.Vp8PictureHeader, vp8FilterHeader, vp8SegmentHeader, proba, vp8Io);
this.ParseFrame(decoder, vp8Io);
}
@ -81,21 +92,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Prepare for next scanline.
this.InitScanline(dec);
// TODO: Reconstruct, filter and emit the row.
}
}
private void InitScanline(Vp8Decoder dec)
{
Vp8MacroBlock left = dec.MacroBlockInfo[dec.MacroBlockIdx - 1];
left.NoneZeroAcDcCoeffs = 0;
left.NoneZeroDcCoeffs = 0;
for (int i = 0; i < dec.IntraL.Length; i++)
{
dec.IntraL[i] = 0;
// Reconstruct, filter and emit the row.
this.ProcessRow(dec);
}
dec.MbX = 0;
}
private void ParseIntraMode(Vp8Decoder dec, int mbX)
@ -117,7 +116,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
block.Segment = 0;
}
if (dec.UseSkipProba)
if (dec.UseSkipProbability)
{
block.Skip = (byte)this.bitReader.GetBit(dec.SkipProbability);
}
@ -165,7 +164,144 @@ namespace SixLabors.ImageSharp.Formats.WebP
block.UvMode = (byte)(this.bitReader.GetBit(142) is 0 ? 0 :
this.bitReader.GetBit(114) is 0 ? 2 :
this.bitReader.GetBit(183) > 0 ? 1 : 3);
}
private void InitScanline(Vp8Decoder dec)
{
Vp8MacroBlock left = dec.MacroBlockInfo[dec.MacroBlockIdx - 1];
left.NoneZeroAcDcCoeffs = 0;
left.NoneZeroDcCoeffs = 0;
for (int i = 0; i < dec.IntraL.Length; i++)
{
dec.IntraL[i] = 0;
}
dec.MbX = 0;
}
private void ProcessRow(Vp8Decoder dec)
{
bool filterRow = (dec.Filter != LoopFilter.None) &&
(dec.MbY >= dec.TopLeftMbY) && (dec.MbY <= dec.BottomRightMbY);
this.ReconstructRow(dec, filterRow);
}
private void ReconstructRow(Vp8Decoder dec, bool filterRow)
{
int mby = dec.MbY;
int yOff = (WebPConstants.Bps * 1) + 8;
int uOff = yOff + (WebPConstants.Bps * 16) + WebPConstants.Bps;
int vOff = uOff + 16;
Span<byte> yDst = dec.YuvBuffer.AsSpan(yOff);
Span<byte> uDst = dec.YuvBuffer.AsSpan(uOff);
Span<byte> vDst = dec.YuvBuffer.AsSpan(vOff);
// Initialize left-most block.
for (int i = 0; i < 16; ++i)
{
yDst[(i * WebPConstants.Bps) - 1] = 129;
}
for (int i = 0; i < 8; ++i)
{
uDst[(i * WebPConstants.Bps) - 1] = 129;
vDst[(i * WebPConstants.Bps) - 1] = 129;
}
// Init top-left sample on left column too.
if (mby > 0)
{
yDst[-1 - WebPConstants.Bps] = uDst[-1 - WebPConstants.Bps] = vDst[-1 - WebPConstants.Bps] = 129;
}
else
{
// We only need to do this init once at block (0,0).
// Afterward, it remains valid for the whole topmost row.
Span<byte> tmp = dec.YuvBuffer.AsSpan(yOff - WebPConstants.Bps - 1, 16 + 4 + 1);
for (int i = 0; i < tmp.Length; ++i)
{
tmp[i] = 127;
}
tmp = dec.YuvBuffer.AsSpan(uOff - WebPConstants.Bps - 1, 8 + 1);
for (int i = 0; i < tmp.Length; ++i)
{
tmp[i] = 127;
}
tmp = dec.YuvBuffer.AsSpan(vOff - WebPConstants.Bps - 1, 8 + 1);
for (int i = 0; i < tmp.Length; ++i)
{
tmp[i] = 127;
}
}
// Reconstruct one row.
for (int mbx = 0; mbx < dec.MbWidth; ++mbx)
{
Vp8MacroBlockData block = dec.MacroBlockData[mbx];
// Rotate in the left samples from previously decoded block. We move four
// pixels at a time for alignment reason, and because of in-loop filter.
if (mbx > 0)
{
for (int i = -1; i < 16; ++i)
{
// Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
}
for (int i = -1; i < 8; ++i)
{
// Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]);
// Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]);
}
// Bring top samples into the cache.
Vp8TopSamples topSamples = dec.YuvTopSamples[mbx];
short[] coeffs = block.Coeffs;
uint bits = block.NonZeroY;
if (mby > 0)
{
//memcpy(y_dst - BPS, top_yuv[0].y, 16);
//memcpy(u_dst - BPS, top_yuv[0].u, 8);
//memcpy(v_dst - BPS, top_yuv[0].v, 8);
}
// Predict and add residuals.
if (block.IsI4x4)
{
if (mby > 0)
{
if (mbx >= dec.MbWidth - 1)
{
// On rightmost border.
//memset(top_right, top_yuv[0].y[15], sizeof(*top_right));
}
else
{
// memcpy(top_right, top_yuv[1].y, sizeof(*top_right));
}
}
// Replicate the top-right pixels below.
// Predict and add residuals for all 4x4 blocks in turn.
for (int n = 0; n < 16; ++n, bits <<= 2)
{
}
}
else
{
// 16x16
}
}
}
}
private Vp8Profile DecodeProfile(int version)
@ -193,7 +329,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
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];
int skip = dec.UseSkipProba ? blockData.Skip : 0;
int skip = dec.UseSkipProbability ? blockData.Skip : 0;
if (skip is 0)
{
@ -555,6 +691,34 @@ namespace SixLabors.ImageSharp.Formats.WebP
return vp8FilterHeader;
}
private void ParsePartitions(Vp8Decoder dec)
{
uint size = this.bitReader.Remaining - this.bitReader.PartitionLength;
int startIdx = (int)this.bitReader.PartitionLength;
Span<byte> sz = this.bitReader.Data.AsSpan(startIdx);
int sizeLeft = (int)size;
int numPartsMinusOne = (1 << (int)this.bitReader.ReadValue(2)) - 1;
int lastPart = numPartsMinusOne;
int partStart = startIdx + (lastPart * 3);
sizeLeft -= lastPart * 3;
for (int p = 0; p < lastPart; ++p)
{
int pSize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
if (pSize > sizeLeft)
{
pSize = sizeLeft;
}
dec.Vp8BitReaders[p] = new Vp8BitReader(this.bitReader.Data, (uint)pSize, partStart);
partStart += pSize;
sizeLeft -= pSize;
sz = sz.Slice(3);
}
dec.Vp8BitReaders[lastPart] = new Vp8BitReader(this.bitReader.Data, (uint)sizeLeft, partStart);
}
private void ParseDequantizationIndices(Vp8SegmentHeader vp8SegmentHeader)
{
int baseQ0 = (int)this.bitReader.ReadValue(7);
@ -613,7 +777,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private void ParseProbabilities(Vp8Proba proba)
private void ParseProbabilities(Vp8Decoder dec, Vp8Proba proba)
{
for (int t = 0; t < WebPConstants.NumTypes; ++t)
{
@ -623,8 +787,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
for (int p = 0; p < WebPConstants.NumProbas; ++p)
{
var prob = WebPConstants.CoeffsUpdateProba[t, b, c, p];
int v = this.bitReader.GetBit(prob) == 0
byte prob = WebPConstants.CoeffsUpdateProba[t, b, c, p];
int v = this.bitReader.GetBit(prob) > 0
? (int)this.bitReader.ReadValue(8)
: WebPConstants.DefaultCoeffsProba[t, b, c, p];
proba.Bands[t, b].Probabilities[c].Probabilities[p] = (byte)v;
@ -638,11 +802,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
// TODO: those values needs to be stored somewhere
bool useSkipProba = this.bitReader.ReadBool();
if (useSkipProba)
dec.UseSkipProbability = this.bitReader.ReadBool();
if (dec.UseSkipProbability)
{
uint skipP = this.bitReader.ReadValue(8);
dec.SkipProbability = (byte)this.bitReader.ReadValue(8);
}
}

Loading…
Cancel
Save