Browse Source

Implement VP8 decoder init

pull/1552/head
Brian Popow 6 years ago
parent
commit
834deae68c
  1. 6
      src/ImageSharp/Formats/WebP/LoopFilter.cs
  2. 153
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  3. 6
      src/ImageSharp/Formats/WebP/Vp8FilterInfo.cs
  4. 10
      src/ImageSharp/Formats/WebP/Vp8Io.cs
  5. 7
      src/ImageSharp/Formats/WebP/WebPConstants.cs
  6. 27
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

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

@ -5,8 +5,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
internal enum LoopFilter
{
Complex,
Simple,
None
None = 0,
Simple = 1,
Complex = 2,
}
}

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

@ -11,6 +11,129 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8Decoder()
{
this.DeQuantMatrices = new Vp8QuantMatrix[WebPConstants.NumMbSegments];
this.FilterStrength = new Vp8FilterInfo[WebPConstants.NumMbSegments, 2];
}
public void Init(Vp8Io io)
{
int extraPixels = WebPConstants.FilterExtraRows[(int)this.Filter];
if (this.Filter is LoopFilter.Complex)
{
// For complex filter, we need to preserve the dependency chain.
this.TopLeftMbX = 0;
this.TopLeftMbY = 0;
}
else
{
// For simple filter, we can filter only the cropped region. We include 'extraPixels' on
// the other side of the boundary, since vertical or horizontal filtering of the previous
// macroblock can modify some abutting pixels.
this.TopLeftMbX = (io.CropLeft - extraPixels) >> 4;
this.TopLeftMbY = (io.CropTop - extraPixels) >> 4;
if (this.TopLeftMbX < 0)
{
this.TopLeftMbX = 0;
}
if (this.TopLeftMbY < 0)
{
this.TopLeftMbY = 0;
}
}
// 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.BotomRightMbX = this.MbWidth;
}
if (this.BottomRightMbY > this.MbHeight)
{
this.BottomRightMbY = this.MbHeight;
}
this.PrecomputeFilterStrengths();
}
private void PrecomputeFilterStrengths()
{
if (this.Filter is LoopFilter.None)
{
return;
}
Vp8FilterHeader hdr = this.FilterHeader;
for (int s = 0; s < WebPConstants.NumMbSegments; ++s)
{
int baseLevel;
// First, compute the initial level
if (this.SegmentHeader.UseSegment)
{
baseLevel = this.SegmentHeader.FilterStrength[s];
if (!this.SegmentHeader.Delta)
{
baseLevel += hdr.Level;
}
}
else
{
baseLevel = hdr.Level;
}
for (int i4x4 = 0; i4x4 <= 1; ++i4x4)
{
Vp8FilterInfo info = this.FilterStrength[s, i4x4];
int level = baseLevel;
if (hdr.UseLfDelta)
{
level += hdr.RefLfDelta[0];
if (i4x4 > 0)
{
level += hdr.ModeLfDelta[0];
}
}
level = (level < 0) ? 0 : (level > 63) ? 63 : level;
if (level > 0)
{
int iLevel = level;
if (hdr.Sharpness > 0)
{
if (hdr.Sharpness > 4)
{
iLevel >>= 2;
}
else
{
iLevel >>= 1;
}
if (iLevel > 9 - hdr.Sharpness)
{
iLevel = 9 - hdr.Sharpness;
}
}
if (iLevel < 1)
{
iLevel = 1;
}
info.InnerLevel = (byte)iLevel;
info.Limit = (byte)((2 * level) + iLevel);
info.HighEdgeVarianceThreshold = (byte)((level >= 40) ? 2 : (level >= 15) ? 1 : 0);
}
else
{
info.Limit = 0; // no filtering
}
info.InnerLevel = (byte)i4x4;
}
}
}
public Vp8FrameHeader FrameHeader { get; set; }
@ -28,6 +151,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public Vp8QuantMatrix[] DeQuantMatrices { get; private set; }
public bool UseSkipProba { get; set; }
public byte SkipProbability { get; set; }
public Vp8Proba Probabilities { get; set; }
/// <summary>
@ -40,6 +167,26 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public int MbHeight { get; set; }
/// <summary>
/// Gets or sets the top-left x index of the macroblock that must be in-loop filtered.
/// </summary>
public int TopLeftMbX { get; set; }
/// <summary>
/// Gets or sets the top-left y index of the macroblock that must be in-loop filtered.
/// </summary>
public int TopLeftMbY { get; set; }
/// <summary>
/// Gets or sets the last bottom-right x index of the macroblock that must be decoded.
/// </summary>
public int BotomRightMbX { get; set; }
/// <summary>
/// Gets or sets the last bottom-right y index of the macroblock that must be decoded.
/// </summary>
public int BottomRightMbY { get; set; }
/// <summary>
/// Gets or sets the current x position in macroblock units.
/// </summary>
@ -60,6 +207,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public Vp8MacroBlock[] MacroBlockInfo { get; set; }
public int MacroBlockPos { get; set; }
public LoopFilter Filter { get; set; }
public Vp8FilterInfo[,] FilterStrength { get; }
/// <summary>
/// Gets or sets filter strength info.
/// </summary>

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

@ -11,12 +11,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <summary>
/// Gets or sets the filter limit in [3..189], or 0 if no filtering.
/// </summary>
public sbyte Limit { get; set; }
public byte Limit { get; set; }
/// <summary>
/// Gets or sets the inner limit in [1..63].
/// </summary>
public sbyte InnerLevel { get; set; }
public byte InnerLevel { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to do inner filtering.
@ -26,6 +26,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <summary>
/// Gets or sets the high edge variance threshold in [0..2].
/// </summary>
public sbyte HighEdgeVarianceThreshold { get; set; }
public byte HighEdgeVarianceThreshold { get; set; }
}
}

10
src/ImageSharp/Formats/WebP/Vp8Io.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
@ -62,6 +62,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public int UvStride { get; set; }
public int CropLeft { get; set; }
public int CropRight { get; set; }
public int CropTop { get; set; }
public int CropBottom { get; set; }
/// <summary>
/// User data
/// </summary>

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

@ -121,6 +121,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
public const int NumCtx = 3;
/// <summary>
/// How many extra lines are needed on the MB boundary for caching, given a filtering level.
/// Simple filter: up to 2 luma samples are read and 1 is written.
/// Complex filter: up to 4 luma samples are read and 3 are written. Same for U/V, so it's 8 samples total (because of the 2x upsampling).
/// </summary>
public static readonly byte[] FilterExtraRows = { 0, 2, 8 };
// Paragraph 9.9
public static readonly int[] Bands =
{

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

@ -79,6 +79,33 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private void DecodeMacroBlock(Vp8Decoder dec)
{
Vp8MacroBlock left = dec.MacroBlockInfo[dec.MacroBlockPos - 1]; // TODO: not sure if this - 1 is correct here
Vp8MacroBlock macroBlock = dec.MacroBlockInfo[dec.MacroBlockPos + dec.MbX];
Vp8MacroBlockData blockData = dec.MacroBlockData[dec.MacroBlockPos + dec.MbX];
int skip = dec.UseSkipProba ? blockData.Skip : 0;
if (skip is 0)
{
this.ParseResiduals(dec, macroBlock);
}
else
{
left.NoneZeroAcDcCoeffs = macroBlock.NoneZeroAcDcCoeffs = 0;
if (blockData.IsI4x4)
{
left.NoneZeroDcCoeffs = macroBlock.NoneZeroDcCoeffs = 0;
}
blockData.NonZeroY = 0;
blockData.NonZeroUv = 0;
blockData.Dither = 0;
}
// TODO: store filter info
}
private bool ParseResiduals(Vp8Decoder decoder, Vp8MacroBlock mb)
{
byte tnz, lnz;

Loading…
Cancel
Save