Browse Source

Vp8Decoder now uses memory allocator

pull/1552/head
Brian Popow 6 years ago
parent
commit
c0bbd0631e
  1. 92
      src/ImageSharp/Formats/WebP/LossyUtils.cs
  2. 82
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  3. 151
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void DC16(Span<byte> dst, byte[] yuv, int offset)
public static void DC16(Span<byte> dst, Span<byte> yuv, int offset)
{
int dc = 16;
for (int j = 0; j < 16; ++j)
@ -28,15 +28,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put16(dc >> 5, dst);
}
public static void TM16(Span<byte> dst, byte[] yuv, int offset)
public static void TM16(Span<byte> dst, Span<byte> yuv, int offset)
{
TrueMotion(dst, yuv, offset, 16);
}
public static void VE16(Span<byte> dst, byte[] yuv, int offset)
public static void VE16(Span<byte> dst, Span<byte> yuv, int offset)
{
// vertical
Span<byte> src = yuv.AsSpan(offset - WebPConstants.Bps, 16);
Span<byte> src = yuv.Slice(offset - WebPConstants.Bps, 16);
for (int j = 0; j < 16; ++j)
{
// memcpy(dst + j * BPS, dst - BPS, 16);
@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HE16(Span<byte> dst, byte[] yuv, int offset)
public static void HE16(Span<byte> dst, Span<byte> yuv, int offset)
{
// horizontal
for (int j = 16; j > 0; --j)
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void DC16NoTop(Span<byte> dst, byte[] yuv, int offset)
public static void DC16NoTop(Span<byte> dst, Span<byte> yuv, int offset)
{
// DC with top samples not available.
int dc = 8;
@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put16(dc >> 4, dst);
}
public static void DC16NoLeft(Span<byte> dst, byte[] yuv, int offset)
public static void DC16NoLeft(Span<byte> dst, Span<byte> yuv, int offset)
{
// DC with left samples not available.
int dc = 8;
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put16(0x80, dst);
}
public static void DC8uv(Span<byte> dst, byte[] yuv, int offset)
public static void DC8uv(Span<byte> dst, Span<byte> yuv, int offset)
{
int dc0 = 8;
for (int i = 0; i < 8; ++i)
@ -101,16 +101,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv((byte)(dc0 >> 4), dst);
}
public static void TM8uv(Span<byte> dst, byte[] yuv, int offset)
public static void TM8uv(Span<byte> dst, Span<byte> yuv, int offset)
{
// TrueMotion
TrueMotion(dst, yuv, offset, 8);
}
public static void VE8uv(Span<byte> dst, byte[] yuv, int offset)
public static void VE8uv(Span<byte> dst, Span<byte> yuv, int offset)
{
// vertical
Span<byte> src = yuv.AsSpan(offset - WebPConstants.Bps, 8);
Span<byte> src = yuv.Slice(offset - WebPConstants.Bps, 8);
for (int j = 0; j < 8; ++j)
{
@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HE8uv(Span<byte> dst, byte[] yuv, int offset)
public static void HE8uv(Span<byte> dst, Span<byte> yuv, int offset)
{
// horizontal
for (int j = 0; j < 8; ++j)
@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void DC8uvNoTop(Span<byte> dst, byte[] yuv, int offset)
public static void DC8uvNoTop(Span<byte> dst, Span<byte> yuv, int offset)
{
// DC with no top samples.
int dc0 = 4;
@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv((byte)(dc0 >> 3), dst);
}
public static void DC8uvNoLeft(Span<byte> dst, byte[] yuv, int offset)
public static void DC8uvNoLeft(Span<byte> dst, Span<byte> yuv, int offset)
{
// DC with no left samples.
int dc0 = 4;
@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv(0x80, dst);
}
public static void DC4(Span<byte> dst, byte[] yuv, int offset)
public static void DC4(Span<byte> dst, Span<byte> yuv, int offset)
{
int dc = 4;
for (int i = 0; i < 4; ++i)
@ -180,12 +180,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void TM4(Span<byte> dst, byte[] yuv, int offset)
public static void TM4(Span<byte> dst, Span<byte> yuv, int offset)
{
TrueMotion(dst, yuv, offset, 4);
}
public static void VE4(Span<byte> dst, byte[] yuv, int offset)
public static void VE4(Span<byte> dst, Span<byte> yuv, int offset)
{
// vertical
int topOffset = offset - WebPConstants.Bps;
@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HE4(Span<byte> dst, byte[] yuv, int offset)
public static void HE4(Span<byte> dst, Span<byte> yuv, int offset)
{
// horizontal
byte a = yuv[offset - 1 - WebPConstants.Bps];
@ -221,7 +221,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(3 * WebPConstants.Bps), val);
}
public static void RD4(Span<byte> dst, byte[] yuv, int offset)
public static void RD4(Span<byte> dst, Span<byte> yuv, int offset)
{
// Down-right
byte i = yuv[offset - 1];
@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Dst(dst, 3, 0, Avg3(d, c, b));
}
public static void VR4(Span<byte> dst, byte[] yuv, int offset)
public static void VR4(Span<byte> dst, Span<byte> yuv, int offset)
{
// Vertical-Right
byte i = yuv[offset - 1];
@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Dst(dst, 3, 1, Avg3(b, c, d));
}
public static void LD4(Span<byte> dst, byte[] yuv, int offset)
public static void LD4(Span<byte> dst, Span<byte> yuv, int offset)
{
// Down-Left
byte a = yuv[offset - WebPConstants.Bps];
@ -328,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Dst(dst, 3, 3, Avg3(g, h, h));
}
public static void VL4(Span<byte> dst, byte[] yuv, int offset)
public static void VL4(Span<byte> dst, Span<byte> yuv, int offset)
{
// Vertical-Left
byte a = yuv[offset - WebPConstants.Bps];
@ -364,7 +364,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Dst(dst, 3, 3, Avg3(f, g, h));
}
public static void HD4(Span<byte> dst, byte[] yuv, int offset)
public static void HD4(Span<byte> dst, Span<byte> yuv, int offset)
{
// Horizontal-Down
byte i = yuv[offset - 1];
@ -400,7 +400,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Dst(dst, 1, 3, Avg3(l, k, j));
}
public static void HU4(Span<byte> dst, byte[] yuv, int offset)
public static void HU4(Span<byte> dst, Span<byte> yuv, int offset)
{
// Horizontal-Up
byte i = yuv[offset - 1];
@ -537,11 +537,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void TrueMotion(Span<byte> dst, byte[] yuv, int offset, int size)
private static void TrueMotion(Span<byte> dst, Span<byte> yuv, int offset, int size)
{
// For information about how true motion works, see rfc6386, page 52. ff and section 20.14.
int topOffset = offset - WebPConstants.Bps;
Span<byte> top = yuv.AsSpan(topOffset);
Span<byte> top = yuv.Slice(topOffset);
byte p = yuv[topOffset - 1];
int leftOffset = offset - 1;
byte left = yuv[leftOffset];
@ -559,7 +559,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
// Simple In-loop filtering (Paragraph 15.2)
public static void SimpleVFilter16(byte[] p, int offset, int stride, int thresh)
public static void SimpleVFilter16(Span<byte> p, int offset, int stride, int thresh)
{
int thresh2 = (2 * thresh) + 1;
for (int i = 0; i < 16; ++i)
@ -571,7 +571,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void SimpleHFilter16(byte[] p, int offset, int stride, int thresh)
public static void SimpleHFilter16(Span<byte> p, int offset, int stride, int thresh)
{
int thresh2 = (2 * thresh) + 1;
for (int i = 0; i < 16; ++i)
@ -583,7 +583,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void SimpleVFilter16i(byte[] p, int offset, int stride, int thresh)
public static void SimpleVFilter16i(Span<byte> p, int offset, int stride, int thresh)
{
for (int k = 3; k > 0; --k)
{
@ -592,7 +592,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void SimpleHFilter16i(byte[] p, int offset, int stride, int thresh)
public static void SimpleHFilter16i(Span<byte> p, int offset, int stride, int thresh)
{
for (int k = 3; k > 0; --k)
{
@ -601,17 +601,17 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void VFilter16(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void VFilter16(Span<byte> p, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
FilterLoop26(p, offset, stride, 1, 16, thresh, ithresh, hevThresh);
}
public static void HFilter16(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void HFilter16(Span<byte> p, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
FilterLoop26(p, offset, 1, stride, 16, thresh, ithresh, hevThresh);
}
public static void VFilter16i(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void VFilter16i(Span<byte> p, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
for (int k = 3; k > 0; --k)
{
@ -620,7 +620,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HFilter16i(byte[] p, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void HFilter16i(Span<byte> p, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
for (int k = 3; k > 0; --k)
{
@ -630,25 +630,25 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
// 8-pixels wide variant, for chroma filtering.
public static void VFilter8(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void VFilter8(Span<byte> u, Span<byte> v, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
FilterLoop26(u, offset, stride, 1, 8, thresh, ithresh, hevThresh);
FilterLoop26(v, offset, stride, 1, 8, thresh, ithresh, hevThresh);
}
public static void HFilter8(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void HFilter8(Span<byte> u, Span<byte> v, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
FilterLoop26(u, offset, 1, stride, 8, thresh, ithresh, hevThresh);
FilterLoop26(v, offset, 1, stride, 8, thresh, ithresh, hevThresh);
}
public static void VFilter8i(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void VFilter8i(Span<byte> u, Span<byte> v, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
FilterLoop24(u, offset + (4 * stride), stride, 1, 8, thresh, ithresh, hevThresh);
FilterLoop24(v, offset + (4 * stride), stride, 1, 8, thresh, ithresh, hevThresh);
}
public static void HFilter8i(byte[] u, byte[] v, int offset, int stride, int thresh, int ithresh, int hevThresh)
public static void HFilter8i(Span<byte> u, Span<byte> v, int offset, int stride, int thresh, int ithresh, int hevThresh)
{
FilterLoop24(u, offset + 4, 1, stride, 8, thresh, ithresh, hevThresh);
FilterLoop24(v, offset + 4, 1, stride, 8, thresh, ithresh, hevThresh);
@ -684,7 +684,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Complex In-loop filtering (Paragraph 15.3)
private static void FilterLoop24(
byte[] p,
Span<byte> p,
int offset,
int hStride,
int vStride,
@ -713,7 +713,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
private static void FilterLoop26(
byte[] p,
Span<byte> p,
int offset,
int hStride,
int vStride,
@ -741,7 +741,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void DoFilter2(byte[] p, int offset, int step)
private static void DoFilter2(Span<byte> p, int offset, int step)
{
// 4 pixels in, 2 pixels out.
int p1 = p[offset - (2 * step)];
@ -755,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
p[offset] = WebPLookupTables.Clip1[q0 - a1];
}
private static void DoFilter4(byte[] p, int offset, int step)
private static void DoFilter4(Span<byte> p, int offset, int step)
{
// 4 pixels in, 4 pixels out.
int p1 = p[offset - (2 * step)];
@ -772,7 +772,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
p[offset + step] = WebPLookupTables.Clip1[q1 - a3];
}
private static void DoFilter6(byte[] p, int offset, int step)
private static void DoFilter6(Span<byte> p, int offset, int step)
{
// 6 pixels in, 6 pixels out.
int p2 = p[offset - (3 * step)];
@ -795,7 +795,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
p[offset + (2 * step)] = WebPLookupTables.Clip1[q2 - a3];
}
private static bool NeedsFilter(byte[] p, int offset, int step, int t)
private static bool NeedsFilter(Span<byte> p, int offset, int step, int t)
{
int p1 = p[offset + (-2 * step)];
int p0 = p[offset - step];
@ -804,7 +804,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return ((4 * WebPLookupTables.Abs0[p0 - q0]) + WebPLookupTables.Abs0[p1 - q1]) <= t;
}
private static bool NeedsFilter2(byte[] p, int offset, int step, int t, int it)
private static bool NeedsFilter2(Span<byte> p, int offset, int step, int t, int it)
{
int p3 = p[offset - (4 * step)];
int p2 = p[offset - (3 * step)];
@ -824,7 +824,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
WebPLookupTables.Abs0[q2 - q1] <= it && WebPLookupTables.Abs0[q1 - q0] <= it;
}
private static bool Hev(byte[] p, int offset, int step, int thresh)
private static bool Hev(Span<byte> p, int offset, int step, int thresh)
{
int p1 = p[offset - (2 * step)];
int p0 = p[offset - step];

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

@ -1,12 +1,17 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Holds information for decoding a lossy webp image.
/// </summary>
internal class Vp8Decoder
internal class Vp8Decoder : IDisposable
{
private Vp8MacroBlock leftMacroBlock;
@ -17,7 +22,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <param name="pictureHeader">The picture header.</param>
/// <param name="segmentHeader">The segment header.</param>
/// <param name="probabilities">The probabilities.</param>
public Vp8Decoder(Vp8FrameHeader frameHeader, Vp8PictureHeader pictureHeader, Vp8SegmentHeader segmentHeader, Vp8Proba probabilities)
/// <param name="memoryAllocator">Used for allocating memory for the pixel data output and the temporary buffers.</param>
public Vp8Decoder(Vp8FrameHeader frameHeader, Vp8PictureHeader pictureHeader, Vp8SegmentHeader segmentHeader, Vp8Proba probabilities, MemoryAllocator memoryAllocator)
{
this.FilterHeader = new Vp8FilterHeader();
this.FrameHeader = frameHeader;
@ -57,34 +63,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint width = pictureHeader.Width;
uint height = pictureHeader.Height;
// TODO: use memory allocator
int extraRows = WebPConstants.FilterExtraRows[(int)LoopFilter.Complex]; // assuming worst case: complex filter
int extraY = extraRows * this.CacheYStride;
int extraUv = (extraRows / 2) * this.CacheUvStride;
this.YuvBuffer = new byte[(WebPConstants.Bps * 17) + (WebPConstants.Bps * 9) + extraY];
this.CacheY = new byte[(16 * this.CacheYStride) + extraY];
this.CacheU = new byte[(16 * this.CacheUvStride) + extraUv];
this.CacheV = new byte[(16 * this.CacheUvStride) + extraUv];
this.TmpYBuffer = new byte[width];
this.TmpUBuffer = new byte[width];
this.TmpVBuffer = new byte[width];
this.Pixels = new byte[width * height * 4];
for (int i = 0; i < this.YuvBuffer.Length; i++)
{
this.YuvBuffer[i] = 205;
}
for (int i = 0; i < this.CacheY.Length; i++)
{
this.CacheY[i] = 205;
}
for (int i = 0; i < this.CacheU.Length; i++)
{
this.CacheU[i] = 205;
this.CacheV[i] = 205;
}
this.YuvBuffer = memoryAllocator.Allocate<byte>((WebPConstants.Bps * 17) + (WebPConstants.Bps * 9) + extraY);
this.CacheY = memoryAllocator.Allocate<byte>((16 * this.CacheYStride) + extraY);
this.CacheU = memoryAllocator.Allocate<byte>((16 * this.CacheUvStride) + extraUv);
this.CacheV = memoryAllocator.Allocate<byte>((16 * this.CacheUvStride) + extraUv);
this.TmpYBuffer = memoryAllocator.Allocate<byte>((int)width);
this.TmpUBuffer = memoryAllocator.Allocate<byte>((int)width);
this.TmpVBuffer = memoryAllocator.Allocate<byte>((int)width);
this.Pixels = memoryAllocator.Allocate<byte>((int)(width * height * 4));
this.YuvBuffer.Memory.Span.Fill(205);
this.CacheY.Memory.Span.Fill(205);
this.CacheU.Memory.Span.Fill(205);
this.CacheV.Memory.Span.Fill(205);
this.Vp8BitReaders = new Vp8BitReader[WebPConstants.MaxNumPartitions];
}
@ -206,19 +200,19 @@ namespace SixLabors.ImageSharp.Formats.WebP
public LoopFilter Filter { get; set; }
/// <summary>
/// Gets or sets the filter strengths.
/// Gets the filter strengths.
/// </summary>
public Vp8FilterInfo[,] FilterStrength { get; }
public byte[] YuvBuffer { get; }
public IMemoryOwner<byte> YuvBuffer { get; }
public Vp8TopSamples[] YuvTopSamples { get; }
public byte[] CacheY { get; }
public IMemoryOwner<byte> CacheY { get; }
public byte[] CacheU { get; }
public IMemoryOwner<byte> CacheU { get; }
public byte[] CacheV { get; }
public IMemoryOwner<byte> CacheV { get; }
public int CacheYOffset { get; set; }
@ -228,13 +222,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
public int CacheUvStride { get; }
public byte[] TmpYBuffer { get; }
public IMemoryOwner<byte> TmpYBuffer { get; }
public byte[] TmpUBuffer { get; }
public IMemoryOwner<byte> TmpUBuffer { get; }
public byte[] TmpVBuffer { get; }
public IMemoryOwner<byte> TmpVBuffer { get; }
public byte[] Pixels { get; }
/// <summary>
/// Gets the pixel buffer where the decoded pixel data will be stored.
/// </summary>
public IMemoryOwner<byte> Pixels { get; }
/// <summary>
/// Gets or sets filter strength info.
@ -348,5 +345,18 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
}
/// <inheritdoc/>
public void Dispose()
{
this.YuvBuffer.Dispose();
this.CacheY.Dispose();
this.CacheU.Dispose();
this.CacheV.Dispose();
this.TmpYBuffer.Dispose();
this.TmpUBuffer.Dispose();
this.TmpVBuffer.Dispose();
this.Pixels.Dispose();
}
}
}

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

@ -55,39 +55,46 @@ namespace SixLabors.ImageSharp.Formats.WebP
var proba = new Vp8Proba();
Vp8SegmentHeader vp8SegmentHeader = this.ParseSegmentHeader(proba);
var decoder = new Vp8Decoder(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba);
Vp8Io io = InitializeVp8Io(decoder, pictureHeader);
using (var decoder = new Vp8Decoder(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba, this.memoryAllocator))
{
Vp8Io io = InitializeVp8Io(decoder, pictureHeader);
// Paragraph 9.4: Parse the filter specs.
this.ParseFilterHeader(decoder);
decoder.PrecomputeFilterStrengths();
// Paragraph 9.4: Parse the filter specs.
this.ParseFilterHeader(decoder);
decoder.PrecomputeFilterStrengths();
// Paragraph 9.5: Parse partitions.
this.ParsePartitions(decoder);
// Paragraph 9.5: Parse partitions.
this.ParsePartitions(decoder);
// Paragraph 9.6: Dequantization Indices.
this.ParseDequantizationIndices(decoder);
// Paragraph 9.6: Dequantization Indices.
this.ParseDequantizationIndices(decoder);
// Ignore the value of update probabilities.
this.bitReader.ReadBool();
// Ignore the value of update probabilities.
this.bitReader.ReadBool();
// Paragraph 13.4: Parse probabilities.
this.ParseProbabilities(decoder);
// Paragraph 13.4: Parse probabilities.
this.ParseProbabilities(decoder);
// Decode image data.
this.ParseFrame(decoder, io);
// Decode image data.
this.ParseFrame(decoder, io);
if (info.Features?.Alpha is true)
{
using (var alphaDecoder = new AlphaDecoder(width, height, info.Features.AlphaData, info.Features.AlphaChunkHeader, this.memoryAllocator))
if (info.Features?.Alpha is true)
{
alphaDecoder.Decode();
this.DecodePixelValues(width, height, decoder.Pixels, pixels, alphaDecoder.Alpha);
using (var alphaDecoder = new AlphaDecoder(
width,
height,
info.Features.AlphaData,
info.Features.AlphaChunkHeader,
this.memoryAllocator))
{
alphaDecoder.Decode();
this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha);
}
}
else
{
this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels);
}
}
else
{
this.DecodePixelValues(width, height, decoder.Pixels, pixels);
}
}
@ -252,10 +259,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
int uOff = yOff + (WebPConstants.Bps * 16) + WebPConstants.Bps;
int vOff = uOff + 16;
byte[] yuv = dec.YuvBuffer;
Span<byte> yDst = dec.YuvBuffer.AsSpan(yOff);
Span<byte> uDst = dec.YuvBuffer.AsSpan(uOff);
Span<byte> vDst = dec.YuvBuffer.AsSpan(vOff);
Span<byte> yuv = dec.YuvBuffer.Memory.Span;
Span<byte> yDst = yuv.Slice(yOff);
Span<byte> uDst = yuv.Slice(uOff);
Span<byte> vDst = yuv.Slice(vOff);
// Initialize left-most block.
for (int i = 0; i < 16; ++i)
@ -278,19 +285,19 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
// 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);
Span<byte> tmp = yuv.Slice(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);
tmp = yuv.Slice(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);
tmp = yuv.Slice(vOff - WebPConstants.Bps - 1, 8 + 1);
for (int i = 0; i < tmp.Length; ++i)
{
tmp[i] = 127;
@ -310,17 +317,17 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
int srcIdx = (i * WebPConstants.Bps) + 12 + yOff;
int dstIdx = (i * WebPConstants.Bps) - 4 + yOff;
yuv.AsSpan(srcIdx, 4).CopyTo(yuv.AsSpan(dstIdx));
yuv.Slice(srcIdx, 4).CopyTo(yuv.Slice(dstIdx));
}
for (int i = -1; i < 8; ++i)
{
int srcIdx = (i * WebPConstants.Bps) + 4 + uOff;
int dstIdx = (i * WebPConstants.Bps) - 4 + uOff;
yuv.AsSpan(srcIdx, 4).CopyTo(yuv.AsSpan(dstIdx));
yuv.Slice(srcIdx, 4).CopyTo(yuv.Slice(dstIdx));
srcIdx = (i * WebPConstants.Bps) + 4 + vOff;
dstIdx = (i * WebPConstants.Bps) - 4 + vOff;
yuv.AsSpan(srcIdx, 4).CopyTo(yuv.AsSpan(dstIdx));
yuv.Slice(srcIdx, 4).CopyTo(yuv.Slice(dstIdx));
}
}
@ -330,15 +337,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint bits = block.NonZeroY;
if (mby > 0)
{
topYuv.Y.CopyTo(yuv.AsSpan(yOff - WebPConstants.Bps));
topYuv.U.CopyTo(yuv.AsSpan(uOff - WebPConstants.Bps));
topYuv.V.CopyTo(yuv.AsSpan(vOff - WebPConstants.Bps));
topYuv.Y.CopyTo(yuv.Slice(yOff - WebPConstants.Bps));
topYuv.U.CopyTo(yuv.Slice(uOff - WebPConstants.Bps));
topYuv.V.CopyTo(yuv.Slice(vOff - WebPConstants.Bps));
}
// Predict and add residuals.
if (block.IsI4x4)
{
Span<byte> topRight = yuv.AsSpan(yOff - WebPConstants.Bps + 16);
Span<byte> topRight = yuv.Slice(yOff - WebPConstants.Bps + 16);
if (mby > 0)
{
if (mbx >= dec.MbWidth - 1)
@ -356,14 +363,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
// Replicate the top-right pixels below.
Span<uint> topRightUint = MemoryMarshal.Cast<byte, uint>(yuv.AsSpan(yOff - WebPConstants.Bps + 16));
Span<uint> topRightUint = MemoryMarshal.Cast<byte, uint>(yuv.Slice(yOff - WebPConstants.Bps + 16));
topRightUint[WebPConstants.Bps] = topRightUint[2 * WebPConstants.Bps] = topRightUint[3 * WebPConstants.Bps] = topRightUint[0];
// Predict and add residuals for all 4x4 blocks in turn.
for (int n = 0; n < 16; ++n, bits <<= 2)
{
int offset = yOff + WebPConstants.Scan[n];
Span<byte> dst = yuv.AsSpan(offset);
Span<byte> dst = yuv.Slice(offset);
byte lumaMode = block.Modes[n];
switch (lumaMode)
{
@ -487,9 +494,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
// Transfer reconstructed samples from yuv_buffer cache to final destination.
Span<byte> yOut = dec.CacheY.AsSpan(dec.CacheYOffset + (mbx * 16));
Span<byte> uOut = dec.CacheU.AsSpan(dec.CacheUvOffset + (mbx * 8));
Span<byte> vOut = dec.CacheV.AsSpan(dec.CacheUvOffset + (mbx * 8));
Span<byte> yOut = dec.CacheY.Memory.Span.Slice(dec.CacheYOffset + (mbx * 16));
Span<byte> uOut = dec.CacheU.Memory.Span.Slice(dec.CacheUvOffset + (mbx * 8));
Span<byte> vOut = dec.CacheV.Memory.Span.Slice(dec.CacheUvOffset + (mbx * 8));
for (int j = 0; j < 16; ++j)
{
yDst.Slice(j * WebPConstants.Bps, Math.Min(16, yOut.Length)).CopyTo(yOut.Slice(j * dec.CacheYStride));
@ -529,22 +536,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
int offset = dec.CacheYOffset + (mbx * 16);
if (mbx > 0)
{
LossyUtils.SimpleHFilter16(dec.CacheY, offset, yBps, limit + 4);
LossyUtils.SimpleHFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4);
}
if (filterInfo.UseInnerFiltering > 0)
{
LossyUtils.SimpleHFilter16i(dec.CacheY, offset, yBps, limit);
LossyUtils.SimpleHFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit);
}
if (mby > 0)
{
LossyUtils.SimpleVFilter16(dec.CacheY, offset, yBps, limit + 4);
LossyUtils.SimpleVFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4);
}
if (filterInfo.UseInnerFiltering > 0)
{
LossyUtils.SimpleVFilter16i(dec.CacheY, offset, yBps, limit);
LossyUtils.SimpleVFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit);
}
}
else if (dec.Filter is LoopFilter.Complex)
@ -555,26 +562,26 @@ namespace SixLabors.ImageSharp.Formats.WebP
int hevThresh = filterInfo.HighEdgeVarianceThreshold;
if (mbx > 0)
{
LossyUtils.HFilter16(dec.CacheY, yOffset, yBps, limit + 4, iLevel, hevThresh);
LossyUtils.HFilter8(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit + 4, iLevel, hevThresh);
LossyUtils.HFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh);
LossyUtils.HFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh);
}
if (filterInfo.UseInnerFiltering > 0)
{
LossyUtils.HFilter16i(dec.CacheY, yOffset, yBps, limit, iLevel, hevThresh);
LossyUtils.HFilter8i(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit, iLevel, hevThresh);
LossyUtils.HFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh);
LossyUtils.HFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh);
}
if (mby > 0)
{
LossyUtils.VFilter16(dec.CacheY, yOffset, yBps, limit + 4, iLevel, hevThresh);
LossyUtils.VFilter8(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit + 4, iLevel, hevThresh);
LossyUtils.VFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh);
LossyUtils.VFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh);
}
if (filterInfo.UseInnerFiltering > 0)
{
LossyUtils.VFilter16i(dec.CacheY, yOffset, yBps, limit, iLevel, hevThresh);
LossyUtils.VFilter8i(dec.CacheU, dec.CacheV, uvOffset, uvBps, limit, iLevel, hevThresh);
LossyUtils.VFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh);
LossyUtils.VFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh);
}
}
}
@ -584,9 +591,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
int extraYRows = WebPConstants.FilterExtraRows[(int)dec.Filter];
int ySize = extraYRows * dec.CacheYStride;
int uvSize = (extraYRows / 2) * dec.CacheUvStride;
Span<byte> yDst = dec.CacheY.AsSpan();
Span<byte> uDst = dec.CacheU.AsSpan();
Span<byte> vDst = dec.CacheV.AsSpan();
Span<byte> yDst = dec.CacheY.Memory.Span;
Span<byte> uDst = dec.CacheU.Memory.Span;
Span<byte> vDst = dec.CacheV.Memory.Span;
int mby = dec.MbY;
bool isFirstRow = mby is 0;
bool isLastRow = mby >= dec.BottomRightMbY - 1;
@ -609,9 +616,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
else
{
io.Y = dec.CacheY.AsSpan(dec.CacheYOffset);
io.U = dec.CacheU.AsSpan(dec.CacheUvOffset);
io.V = dec.CacheV.AsSpan(dec.CacheUvOffset);
io.Y = dec.CacheY.Memory.Span.Slice(dec.CacheYOffset);
io.U = dec.CacheU.Memory.Span.Slice(dec.CacheUvOffset);
io.V = dec.CacheV.Memory.Span.Slice(dec.CacheUvOffset);
}
if (!isLastRow)
@ -639,28 +646,28 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Rotate top samples if needed.
if (!isLastRow)
{
yDst.Slice(16 * dec.CacheYStride, ySize).CopyTo(dec.CacheY.AsSpan());
uDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheU.AsSpan());
vDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheV.AsSpan());
yDst.Slice(16 * dec.CacheYStride, ySize).CopyTo(dec.CacheY.Memory.Span);
uDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheU.Memory.Span);
vDst.Slice(8 * dec.CacheUvStride, uvSize).CopyTo(dec.CacheV.Memory.Span);
}
}
private int EmitRgb(Vp8Decoder dec, Vp8Io io)
{
byte[] buf = dec.Pixels;
Span<byte> buf = dec.Pixels.Memory.Span;
int numLinesOut = io.MbH; // a priori guess.
Span<byte> curY = io.Y;
Span<byte> curU = io.U;
Span<byte> curV = io.V;
byte[] tmpYBuffer = dec.TmpYBuffer;
byte[] tmpUBuffer = dec.TmpUBuffer;
byte[] tmpVBuffer = dec.TmpVBuffer;
Span<byte> topU = tmpUBuffer.AsSpan();
Span<byte> topV = tmpVBuffer.AsSpan();
Span<byte> tmpYBuffer = dec.TmpYBuffer.Memory.Span;
Span<byte> tmpUBuffer = dec.TmpUBuffer.Memory.Span;
Span<byte> tmpVBuffer = dec.TmpVBuffer.Memory.Span;
Span<byte> topU = tmpUBuffer;
Span<byte> topV = tmpVBuffer;
int bpp = 3;
int bufferStride = bpp * io.Width;
int dstStartIdx = io.MbY * bufferStride;
Span<byte> dst = buf.AsSpan(dstStartIdx);
Span<byte> dst = buf.Slice(dstStartIdx);
int yEnd = io.MbY + io.MbH;
int mbw = io.MbW;
int uvw = (mbw + 1) / 2;
@ -674,7 +681,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
else
{
// We can finish the left-over line from previous call.
this.UpSample(tmpYBuffer.AsSpan(), curY, topU, topV, curU, curV, buf.AsSpan(dstStartIdx - bufferStride), dst, mbw);
this.UpSample(tmpYBuffer, curY, topU, topV, curU, curV, buf.Slice(dstStartIdx - bufferStride), dst, mbw);
numLinesOut++;
}

Loading…
Cancel
Save