Browse Source

Fix some mistakes during macro block analysis

pull/1552/head
Brian Popow 6 years ago
parent
commit
05f1466a4e
  1. 61
      src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs
  2. 6
      src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs

61
src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs

@ -87,20 +87,18 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
this.YuvOut2 = new byte[WebPConstants.Bps * 16]; this.YuvOut2 = new byte[WebPConstants.Bps * 16];
this.YuvP = new byte[(32 * WebPConstants.Bps) + (16 * WebPConstants.Bps) + (8 * WebPConstants.Bps)]; // I16+Chroma+I4 preds this.YuvP = new byte[(32 * WebPConstants.Bps) + (16 * WebPConstants.Bps) + (8 * WebPConstants.Bps)]; // I16+Chroma+I4 preds
this.YLeft = new byte[32]; this.YLeft = new byte[32];
this.ULeft = new byte[32]; this.UvLeft = new byte[32];
this.VLeft = new byte[32];
this.TopNz = new int[9]; this.TopNz = new int[9];
this.LeftNz = new int[9]; this.LeftNz = new int[9];
// To match the C++ initial values, initialize all with 204. // To match the C++ initial values of the reference implementation, initialize all with 204.
byte defaultInitVal = 204; byte defaultInitVal = 204;
this.YuvIn.AsSpan().Fill(defaultInitVal); this.YuvIn.AsSpan().Fill(defaultInitVal);
this.YuvOut.AsSpan().Fill(defaultInitVal); this.YuvOut.AsSpan().Fill(defaultInitVal);
this.YuvOut2.AsSpan().Fill(defaultInitVal); this.YuvOut2.AsSpan().Fill(defaultInitVal);
this.YuvP.AsSpan().Fill(defaultInitVal); this.YuvP.AsSpan().Fill(defaultInitVal);
this.YLeft.AsSpan().Fill(defaultInitVal); this.YLeft.AsSpan().Fill(defaultInitVal);
this.ULeft.AsSpan().Fill(defaultInitVal); this.UvLeft.AsSpan().Fill(defaultInitVal);
this.VLeft.AsSpan().Fill(defaultInitVal);
for (int i = -255; i <= 255 + 255; ++i) for (int i = -255; i <= 255 + 255; ++i)
{ {
@ -146,14 +144,9 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
public byte[] YLeft { get; set; } public byte[] YLeft { get; set; }
/// <summary> /// <summary>
/// Gets or sets the left u samples. /// Gets or sets the left uv samples.
/// </summary> /// </summary>
public byte[] ULeft { get; set; } public byte[] UvLeft { get; set; }
/// <summary>
/// Gets or sets the left v samples.
/// </summary>
public byte[] VLeft { get; set; }
/// <summary> /// <summary>
/// Gets or sets the top luma samples at position 'X'. /// Gets or sets the top luma samples at position 'X'.
@ -228,8 +221,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
else else
{ {
Span<byte> yLeft = this.YLeft.AsSpan(); Span<byte> yLeft = this.YLeft.AsSpan();
Span<byte> uLeft = this.ULeft.AsSpan(); Span<byte> uLeft = this.UvLeft.AsSpan(0, 16);
Span<byte> vLeft = this.VLeft.AsSpan(); Span<byte> vLeft = this.UvLeft.AsSpan(16, 16);
if (this.Y == 0) if (this.Y == 0)
{ {
yLeft[0] = 127; yLeft[0] = 127;
@ -366,12 +359,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
private void SetIntra4Mode(byte[] modes) private void SetIntra4Mode(byte[] modes)
{ {
int modesIdx = 0; int modesIdx = 0;
Span<byte> preds = this.Preds.Slice(this.predIdx); int predIdx = this.predIdx;
for (int y = 4; y > 0; --y) for (int y = 4; y > 0; --y)
{ {
// TODO: modes.AsSpan(modesIdx, 4).CopyTo(this.Preds.Slice(predIdx));
// memcpy(preds, modes, 4 * sizeof(*modes)); predIdx += this.predsWidth;
preds = preds.Slice(this.predsWidth);
modesIdx += 4; modesIdx += 4;
} }
@ -457,12 +449,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
private void MakeChroma8Preds() private void MakeChroma8Preds()
{ {
Span<byte> left = this.X != 0 ? this.ULeft.AsSpan() : null; Span<byte> left = this.X != 0 ? this.UvLeft.AsSpan() : null;
Span<byte> top = this.Y != 0 ? this.UvTop.Slice(this.uvTopIdx) : null; Span<byte> top = this.Y != 0 ? this.UvTop.Slice(this.uvTopIdx) : null;
this.EncPredChroma8(this.YuvP, left, top); this.EncPredChroma8(this.YuvP, left, top);
} }
// luma 16x16 prediction (paragraph 12.3) // luma 16x16 prediction (paragraph 12.3).
private void EncPredLuma16(Span<byte> dst, Span<byte> left, Span<byte> top) private void EncPredLuma16(Span<byte> dst, Span<byte> left, Span<byte> top)
{ {
this.DcMode(dst.Slice(I16DC16), left, top, 16, 16, 5); this.DcMode(dst.Slice(I16DC16), left, top, 16, 16, 5);
@ -471,16 +463,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
this.TrueMotion(dst.Slice(I16TM16), left, top, 16); this.TrueMotion(dst.Slice(I16TM16), left, top, 16);
} }
// Chroma 8x8 prediction (paragraph 12.2) // Chroma 8x8 prediction (paragraph 12.2).
private void EncPredChroma8(Span<byte> dst, Span<byte> left, Span<byte> top) private void EncPredChroma8(Span<byte> dst, Span<byte> left, Span<byte> top)
{ {
// U block // U block.
this.DcMode(dst.Slice(C8DC8), left, top, 8, 8, 4); this.DcMode(dst.Slice(C8DC8), left, top, 8, 8, 4);
this.VerticalPred(dst.Slice(C8VE8), top, 8); this.VerticalPred(dst.Slice(C8VE8), top, 8);
this.HorizontalPred(dst.Slice(C8HE8), left, 8); this.HorizontalPred(dst.Slice(C8HE8), left, 8);
this.TrueMotion(dst.Slice(C8TM8), left, top, 8); this.TrueMotion(dst.Slice(C8TM8), left, top, 8);
// V block // V block.
dst = dst.Slice(8); dst = dst.Slice(8);
if (top != null) if (top != null)
{ {
@ -529,6 +521,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
else if (left != null) else if (left != null)
{ {
// left but no top. // left but no top.
left = left.Slice(1); // in the reference implementation, left starts at -1.
for (j = 0; j < size; ++j) for (j = 0; j < size; ++j)
{ {
dc += left[j]; dc += left[j];
@ -628,16 +621,17 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
private void ImportBlock(Span<byte> src, int srcStride, Span<byte> dst, int w, int h, int size) private void ImportBlock(Span<byte> src, int srcStride, Span<byte> dst, int w, int h, int size)
{ {
int dstIdx = 0; int dstIdx = 0;
int srcIdx = 0;
for (int i = 0; i < h; ++i) for (int i = 0; i < h; ++i)
{ {
src.Slice(0, w).CopyTo(dst.Slice(dstIdx)); src.Slice(srcIdx, w).CopyTo(dst.Slice(dstIdx));
if (w < size) if (w < size)
{ {
dst.Slice(dstIdx, size - w).Fill(dst[dstIdx + w - 1]); dst.Slice(dstIdx, size - w).Fill(dst[dstIdx + w - 1]);
} }
dstIdx += WebPConstants.Bps; dstIdx += WebPConstants.Bps;
src = src.Slice(srcStride); srcIdx += srcStride;
} }
for (int i = h; i < size; ++i) for (int i = h; i < size; ++i)
@ -650,10 +644,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
private void ImportLine(Span<byte> src, int srcStride, Span<byte> dst, int len, int totalLen) private void ImportLine(Span<byte> src, int srcStride, Span<byte> dst, int len, int totalLen)
{ {
int i; int i;
int srcIdx = 0;
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
{ {
dst[i] = src[i]; dst[i] = src[srcIdx];
src = src.Slice(srcStride); srcIdx += srcStride;
} }
for (; i < totalLen; ++i) for (; i < totalLen; ++i)
@ -686,30 +681,24 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
this.nzIdx = 0; this.nzIdx = 0;
this.yTopIdx = 0; this.yTopIdx = 0;
this.uvTopIdx = 0; this.uvTopIdx = 0;
this.predIdx = y * 4 * this.predsWidth;
this.InitLeft(); this.InitLeft();
// TODO:
// it->preds_ = enc->preds_ + y * 4 * enc->preds_w_;
} }
private void InitLeft() private void InitLeft()
{ {
Span<byte> yLeft = this.YLeft.AsSpan(); Span<byte> yLeft = this.YLeft.AsSpan();
Span<byte> uLeft = this.ULeft.AsSpan(); Span<byte> uLeft = this.UvLeft.AsSpan(0, 16);
Span<byte> vLeft = this.VLeft.AsSpan(); Span<byte> vLeft = this.UvLeft.AsSpan(16, 16);
byte val = (byte)((this.Y > 0) ? 129 : 127); byte val = (byte)((this.Y > 0) ? 129 : 127);
yLeft[0] = val; yLeft[0] = val;
uLeft[0] = val; uLeft[0] = val;
vLeft[0] = val; vLeft[0] = val;
uLeft[16] = val;
vLeft[16] = val;
yLeft.Slice(1, 16).Fill(129); yLeft.Slice(1, 16).Fill(129);
uLeft.Slice(1, 8).Fill(129); uLeft.Slice(1, 8).Fill(129);
vLeft.Slice(1, 8).Fill(129); vLeft.Slice(1, 8).Fill(129);
uLeft.Slice(1 + 16, 8).Fill(129);
vLeft.Slice(1 + 16, 8).Fill(129);
this.LeftNz[8] = 0; this.LeftNz[8] = 0;
} }

6
src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs

@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
alphas[bestAlpha]++; alphas[bestAlpha]++;
it.CurrentMacroBlockInfo.Alpha = bestAlpha; // For later remapping. it.CurrentMacroBlockInfo.Alpha = bestAlpha; // For later remapping.
return bestAlpha; // Mixed susceptibility (not just luma) return bestAlpha; // Mixed susceptibility (not just luma).
} }
private void ConvertRgbToYuv<TPixel>(Image<TPixel> image) private void ConvertRgbToYuv<TPixel>(Image<TPixel> image)
@ -420,8 +420,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private int Interpolate(int v) private int Interpolate(int v)
{ {
int tabPos = v >> (WebPConstants.GammaTabFix + 2); // integer part int tabPos = v >> (WebPConstants.GammaTabFix + 2); // integer part.
int x = v & ((WebPConstants.GammaTabScale << 2) - 1); // fractional part int x = v & ((WebPConstants.GammaTabScale << 2) - 1); // fractional part.
int v0 = WebPLookupTables.LinearToGammaTab[tabPos]; int v0 = WebPLookupTables.LinearToGammaTab[tabPos];
int v1 = WebPLookupTables.LinearToGammaTab[tabPos + 1]; int v1 = WebPLookupTables.LinearToGammaTab[tabPos + 1];
int y = (v1 * x) + (v0 * ((WebPConstants.GammaTabScale << 2) - x)); // interpolate int y = (v1 * x) + (v0 * ((WebPConstants.GammaTabScale << 2) - x)); // interpolate

Loading…
Cancel
Save