Browse Source

Fix issues with EncPredLuma4 and CodeIntraModes

pull/1552/head
Brian Popow 6 years ago
parent
commit
8f92c467eb
  1. 19
      src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs
  2. 57
      src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs
  3. 42
      src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs

19
src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs

@ -561,6 +561,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
}
}
// Writes the partition #0 modes (that is: all intra modes)
private void CodeIntraModes(Vp8BitWriter bitWriter)
{
var it = new Vp8EncIterator(this.enc.YTop, this.enc.UvTop, this.enc.Nz, this.enc.MbInfo, this.enc.Preds, this.enc.Mbw, this.enc.Mbh);
@ -569,7 +570,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
do
{
Vp8MacroBlockInfo mb = it.CurrentMacroBlockInfo;
Span<byte> preds = it.Preds.AsSpan(it.PredIdx);
int predIdx = it.PredIdx;
Span<byte> preds = it.Preds.AsSpan(predIdx);
if (this.enc.SegmentHeader.UpdateMap)
{
bitWriter.PutSegment(mb.Segment, this.enc.Proba.Segments);
@ -587,19 +589,18 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
}
else
{
Span<byte> topPred = it.Preds.AsSpan(it.PredIdx);
int x, y;
for (y = 0; y < 4; ++y)
Span<byte> topPred = it.Preds.AsSpan(predIdx - predsWidth);
for (int y = 0; y < 4; ++y)
{
int left = preds[it.PredIdx - 1];
for (x = 0; x < 4; ++x)
int left = it.Preds[predIdx - 1];
for (int x = 0; x < 4; ++x)
{
byte[] probas = WebPLookupTables.ModesProba[topPred[x], left];
left = bitWriter.PutI4Mode(preds[x], probas);
left = bitWriter.PutI4Mode(it.Preds[predIdx + x], probas);
}
topPred = preds;
preds = preds.Slice(predsWidth);
topPred = it.Preds.AsSpan(predIdx);
predIdx += predsWidth;
}
}

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

@ -2,10 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Buffers.Binary;
using SixLabors.ImageSharp.Formats.WebP.Lossless;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.WebP.Lossy
{
@ -66,11 +64,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
private const int I4RD4 = I4DC4 + 16;
private const int I4VR4 = I4RD4 + 20;
private const int I4VR4 = I4DC4 + 20;
private const int I4LD4 = I4RD4 + 24;
private const int I4LD4 = I4DC4 + 24;
private const int I4VL4 = I4RD4 + 28;
private const int I4VL4 = I4DC4 + 28;
private const int I4HD4 = (3 * 16 * WebPConstants.Bps) + (4 * WebPConstants.Bps);
@ -797,14 +795,14 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
// located at top[0..3], and top right is top[4..7]
private void EncPredLuma4(Span<byte> dst, Span<byte> top, int topOffset)
{
this.Dc4(dst, top, topOffset);
this.Dc4(dst.Slice(I4DC4), top, topOffset);
this.Tm4(dst.Slice(I4TM4), top, topOffset);
this.Ve4(dst.Slice(I4VE4), top, topOffset);
this.He4(dst.Slice(I4HE4), top, topOffset);
this.Rd4(dst.Slice(I4RD4), top, topOffset);
this.Vr4(dst.Slice(I4VR4), top, topOffset);
this.Ld4(dst.Slice(I4LD4), top);
this.Vl4(dst.Slice(I4VL4), top);
this.Ld4(dst.Slice(I4LD4), top, topOffset);
this.Vl4(dst.Slice(I4VL4), top, topOffset);
this.Hd4(dst.Slice(I4HD4), top, topOffset);
this.Hu4(dst.Slice(I4HU4), top, topOffset);
}
@ -989,7 +987,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
val = 0x01010101U * LossyUtils.Avg3(j, k, l);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(2 * WebPConstants.Bps), val);
val = 0x01010101U * LossyUtils.Avg3(k, l, l);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(1 * WebPConstants.Bps), val);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(3 * WebPConstants.Bps), val);
}
private void Rd4(Span<byte> dst, Span<byte> top, int topOffset)
@ -1062,16 +1060,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
LossyUtils.Dst(dst, 3, 1, LossyUtils.Avg3(b, c, d));
}
private void Ld4(Span<byte> dst, Span<byte> top)
private void Ld4(Span<byte> dst, Span<byte> top, int topOffset)
{
byte a = top[0];
byte b = top[1];
byte c = top[2];
byte d = top[3];
byte e = top[4];
byte f = top[5];
byte g = top[6];
byte h = top[7];
byte a = top[topOffset + 0];
byte b = top[topOffset + 1];
byte c = top[topOffset + 2];
byte d = top[topOffset + 3];
byte e = top[topOffset + 4];
byte f = top[topOffset + 5];
byte g = top[topOffset + 6];
byte h = top[topOffset + 7];
LossyUtils.Dst(dst, 0, 0, LossyUtils.Avg3(a, b, c));
var bcd = LossyUtils.Avg3(b, c, d);
@ -1096,16 +1094,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
LossyUtils.Dst(dst, 3, 3, LossyUtils.Avg3(g, h, h));
}
private void Vl4(Span<byte> dst, Span<byte> top)
private void Vl4(Span<byte> dst, Span<byte> top, int topOffset)
{
byte a = top[0];
byte b = top[1];
byte c = top[2];
byte d = top[3];
byte e = top[4];
byte f = top[5];
byte g = top[6];
byte h = top[7];
byte a = top[topOffset + 0];
byte b = top[topOffset + 1];
byte c = top[topOffset + 2];
byte d = top[topOffset + 3];
byte e = top[topOffset + 4];
byte f = top[topOffset + 5];
byte g = top[topOffset + 6];
byte h = top[topOffset + 7];
LossyUtils.Dst(dst, 0, 0, LossyUtils.Avg2(a, b));
var bc = LossyUtils.Avg2(b, c);
@ -1294,6 +1292,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
this.YTop.AsSpan(0, topSize).Fill(127);
this.UvTop.AsSpan().Fill(127);
this.Nz.AsSpan().Fill(0);
int predsW = (4 * this.mbw) + 1;
int predsH = (4 * this.mbh) + 1;
int predsSize = predsW * predsH;
this.Preds.AsSpan(predsSize + this.predsWidth, this.mbw).Fill(0);
}
private int Bit(uint nz, int n)

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

@ -4,6 +4,7 @@
using System;
using System.Buffers;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.WebP.BitWriter;
@ -22,11 +23,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// A bit writer for writing lossy webp streams.
/// </summary>
private readonly Vp8BitWriter bitWriter;
/// <summary>
/// The quality, that will be used to encode the image.
/// </summary>
@ -57,6 +53,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
/// </summary>
private readonly int mbh;
/// <summary>
/// A bit writer for writing lossy webp streams.
/// </summary>
private Vp8BitWriter bitWriter;
/// <summary>
/// The segment features.
/// </summary>
@ -205,15 +206,9 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
this.Nz.AsSpan().Fill(3452816845);
this.ResetBoundaryPredictions();
// Initialize the bitwriter.
this.BaseQuant = 36; // TODO: hardCoded for now.
int averageBytesPerMacroBlock = this.averageBytesPerMb[this.BaseQuant >> 4];
int expectedSize = this.mbw * this.mbh * averageBytesPerMacroBlock;
this.bitWriter = new Vp8BitWriter(expectedSize, this);
}
public int BaseQuant { get; }
public int BaseQuant { get; set; }
/// <summary>
/// Gets the probabilities.
@ -378,6 +373,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
this.AssignSegments(alphas);
this.SetLoopParams(this.quality);
// Initialize the bitwriter.
int averageBytesPerMacroBlock = this.averageBytesPerMb[this.BaseQuant >> 4];
int expectedSize = this.mbw * this.mbh * averageBytesPerMacroBlock;
this.bitWriter = new Vp8BitWriter(expectedSize, this);
// TODO: EncodeAlpha();
// Stats-collection loop.
this.StatLoop(width, height, yStride, uvStride);
@ -589,6 +589,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
left[i * this.predsWidth] = (int)IntraPredictionMode.DcPrediction;
}
int predsW = (4 * this.mbw) + 1;
int predsH = (4 * this.mbh) + 1;
int predsSize = predsW * predsH;
this.Preds.AsSpan(predsSize + this.predsWidth - 4, 4).Fill(0);
this.Nz[0] = 0; // constant
}
@ -740,6 +745,9 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
dqm[i].Quant = Clip(q, 0, 127);
}
// Purely indicative in the bitstream (except for the 1-segment case).
this.BaseQuant = dqm[0].Quant;
// uvAlpha is normally spread around ~60. The useful range is
// typically ~30 (quite bad) to ~100 (ok to decimate UV more).
// We map it to the safe maximal range of MAX/MIN_DQ_UV for dq_uv.
@ -1035,9 +1043,9 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
}
else
{
// Reconstruct partial block inside yuv_out2 buffer
// Reconstruct partial block inside YuvOut2 buffer
Span<byte> tmpDst = it.YuvOut2.AsSpan(Vp8EncIterator.YOffEnc + WebPLookupTables.Vp8Scan[it.I4]);
nz |= this.ReconstructIntra4(it, dqm, rd.YAcLevels.AsSpan(it.I4, 16), src, tmpDst, bestI4Mode) << it.I4;
nz |= this.ReconstructIntra4(it, dqm, rd.YAcLevels.AsSpan(it.I4 * 16, 16), src, tmpDst, bestI4Mode) << it.I4;
}
}
while (it.RotateI4(it.YuvOut2.AsSpan(Vp8EncIterator.YOffEnc)));
@ -1111,7 +1119,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
for (x = 0; x < 4; ++x)
{
int ctx = it.TopNz[x] + it.LeftNz[y];
residual.SetCoeffs(rd.YAcLevels.AsSpan(16 * (x + (y * 4)), 16));
Span<short> coeffs = rd.YAcLevels.AsSpan(16 * (x + (y * 4)), 16);
residual.SetCoeffs(coeffs);
int res = this.bitWriter.PutCoeffs(ctx, residual);
it.TopNz[x] = it.LeftNz[y] = res;
}
@ -1176,7 +1185,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
for (x = 0; x < 4; ++x)
{
int ctx = it.TopNz[x] + it.LeftNz[y];
residual.SetCoeffs(rd.YAcLevels.AsSpan(16 * (x + (y * 4)), 16));
Span<short> coeffs = rd.YAcLevels.AsSpan(16 * (x + (y * 4)), 16);
residual.SetCoeffs(coeffs);
var res = residual.RecordCoeffs(ctx);
it.TopNz[x] = res;
it.LeftNz[y] = res;

Loading…
Cancel
Save