Browse Source

Implement Residual

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
6c4e213a75
  1. 1
      src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs
  2. 35
      src/ImageSharp/Formats/Heif/Av1/Av1LookupTables.cs
  3. 2
      src/ImageSharp/Formats/Heif/Av1/Av1Math.cs
  4. 9
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs
  5. 6
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs
  6. 164
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
  7. 6
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformInfo.cs

1
src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs

@ -11,6 +11,7 @@ internal static class Av1BlockSizeExtensions
private static readonly int[] SizeWide = [1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 1, 4, 2, 8, 4, 16]; private static readonly int[] SizeWide = [1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 1, 4, 2, 8, 4, 16];
private static readonly int[] SizeHigh = [1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16, 32, 16, 32, 4, 1, 8, 2, 16, 4]; private static readonly int[] SizeHigh = [1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16, 32, 16, 32, 4, 1, 8, 2, 16, 4];
// The Subsampled_Size table in the spec (Section 5.11.38. Get plane residual size function).
private static readonly Av1BlockSize[][][] SubSampled = private static readonly Av1BlockSize[][][] SubSampled =
[ [

35
src/ImageSharp/Formats/Heif/Av1/Av1LookupTables.cs

@ -1,35 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal static class Av1LookupTables
{
// The Subsampled_Size table in the spec (Section 5.11.38. Get plane residual size function).
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1500:Braces for multi-line statements should not share line", Justification = "alignment should match the spec file definition")]
public static readonly Av1BlockSize[,,] SubSampledSize =
{
{ { Av1BlockSize.Block4x4, Av1BlockSize.Block4x4 }, { Av1BlockSize.Block4x4, Av1BlockSize.Block4x4 } },
{ { Av1BlockSize.Block4x8, Av1BlockSize.Block4x4 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x4 } },
{ { Av1BlockSize.Block8x4, Av1BlockSize.Invalid }, { Av1BlockSize.Block4x4, Av1BlockSize.Block4x4 } },
{ { Av1BlockSize.Block8x8, Av1BlockSize.Block8x4 }, { Av1BlockSize.Block4x8, Av1BlockSize.Block4x4 } },
{ { Av1BlockSize.Block8x16, Av1BlockSize.Block8x8 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x8 } },
{ { Av1BlockSize.Block16x8, Av1BlockSize.Invalid }, { Av1BlockSize.Block8x8, Av1BlockSize.Block8x4 } },
{ { Av1BlockSize.Block16x16, Av1BlockSize.Block16x8 }, { Av1BlockSize.Block8x16, Av1BlockSize.Block8x8 } },
{ { Av1BlockSize.Block16x32, Av1BlockSize.Block16x16 }, { Av1BlockSize.Invalid, Av1BlockSize.Block8x16 } },
{ { Av1BlockSize.Block32x16, Av1BlockSize.Invalid }, { Av1BlockSize.Block16x16, Av1BlockSize.Block16x8 } },
{ { Av1BlockSize.Block32x32, Av1BlockSize.Block32x16 }, { Av1BlockSize.Block16x32, Av1BlockSize.Block16x16 } },
{ { Av1BlockSize.Block32x64, Av1BlockSize.Block32x32 }, { Av1BlockSize.Invalid, Av1BlockSize.Block16x32 } },
{ { Av1BlockSize.Block64x32, Av1BlockSize.Invalid }, { Av1BlockSize.Block32x32, Av1BlockSize.Block32x16 } },
{ { Av1BlockSize.Block64x64, Av1BlockSize.Block64x32 }, { Av1BlockSize.Block32x64, Av1BlockSize.Block32x32 } },
{ { Av1BlockSize.Block64x128, Av1BlockSize.Block64x64 }, { Av1BlockSize.Invalid, Av1BlockSize.Block32x64 } },
{ { Av1BlockSize.Block128x64, Av1BlockSize.Invalid }, { Av1BlockSize.Block64x64, Av1BlockSize.Block64x32 } },
{ { Av1BlockSize.Block128x128, Av1BlockSize.Block128x64 }, { Av1BlockSize.Block64x128, Av1BlockSize.Block64x64 } },
{ { Av1BlockSize.Block4x16, Av1BlockSize.Block4x8 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x8 } },
{ { Av1BlockSize.Block16x4, Av1BlockSize.Invalid }, { Av1BlockSize.Block8x4, Av1BlockSize.Block8x4 } },
{ { Av1BlockSize.Block8x32, Av1BlockSize.Block8x16 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x16 } },
{ { Av1BlockSize.Block32x8, Av1BlockSize.Invalid }, { Av1BlockSize.Block16x8, Av1BlockSize.Block16x4 } },
{ { Av1BlockSize.Block16x64, Av1BlockSize.Block16x32 }, { Av1BlockSize.Invalid, Av1BlockSize.Block8x32 } },
{ { Av1BlockSize.Block64x16, Av1BlockSize.Invalid }, { Av1BlockSize.Block32x16, Av1BlockSize.Block32x8 } },
};
}

2
src/ImageSharp/Formats/Heif/Av1/Av1Math.cs

@ -137,6 +137,8 @@ internal static class Av1Math
return (value + mask) & ~mask; return (value + mask) & ~mask;
} }
internal static int RoundPowerOf2(int value, int n) => (value + ((1 << n) >> 1)) >> n;
internal static int Clamp(int value, int low, int high) internal static int Clamp(int value, int low, int high)
=> value < low ? low : (value > high ? high : value); => value < low ? low : (value > high ? high : value);
} }

9
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Reflection.Metadata.Ecma335;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
@ -201,4 +202,12 @@ internal class Av1FrameBuffer
} }
public void ClearDeltaLoopFilter() => Array.Fill(this.deltaLoopFilter, 0); public void ClearDeltaLoopFilter() => Array.Fill(this.deltaLoopFilter, 0);
public Av1TransformInfo? GetTransform(int plane, int transformInfoIndex) =>
plane switch
{
0 => this.GetTransformY(transformInfoIndex),
1 or 2 => this.GetTransformUv(transformInfoIndex),
_ => null,
};
} }

6
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs

@ -25,11 +25,13 @@ internal class Av1SuperblockInfo
public Span<int> CoefficientsV => this.frameBuffer.GetCoefficientsV(this.Position); public Span<int> CoefficientsV => this.frameBuffer.GetCoefficientsV(this.Position);
public Av1TransformInfo SuperblockTransformInfo => this.frameBuffer.GetTransformY(this.Position);
public Span<int> CdefStrength => this.frameBuffer.GetCdefStrength(this.Position); public Span<int> CdefStrength => this.frameBuffer.GetCdefStrength(this.Position);
public Span<int> SuperblockDeltaLoopFilter => this.frameBuffer.GetDeltaLoopFilter(this.Position); public Span<int> SuperblockDeltaLoopFilter => this.frameBuffer.GetDeltaLoopFilter(this.Position);
public int TransformInfoIndexY { get; internal set; }
public int TransformInfoIndexUv { get; internal set; }
public Av1BlockModeInfo GetModeInfo(Point index) => this.frameBuffer.GetModeInfo(this.Position, index); public Av1BlockModeInfo GetModeInfo(Point index) => this.frameBuffer.GetModeInfo(this.Position, index);
} }

164
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs

@ -1,15 +1,10 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Data.Common;
using System.Drawing;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Heif.Av1; using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
using SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
using static SixLabors.ImageSharp.PixelFormats.Utils.Vector4Converters;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
@ -34,8 +29,10 @@ internal class Av1TileDecoder : IAv1TileDecoder
private int maxLumaHeight; private int maxLumaHeight;
private int deltaLoopFilterResolution = -1; private int deltaLoopFilterResolution = -1;
private bool readDeltas; private bool readDeltas;
private int[][] tusCount = []; private int[][] tusCount;
private int[] firstTransformOffset = new int[2]; private int[] firstTransformOffset = new int[2];
private int[][] coefficients = [];
private int[] coefficientIndex = [];
public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
{ {
@ -64,6 +61,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
this.tusCount[0] = new int[this.FrameBuffer.ModeInfoCount]; this.tusCount[0] = new int[this.FrameBuffer.ModeInfoCount];
this.tusCount[1] = new int[this.FrameBuffer.ModeInfoCount]; this.tusCount[1] = new int[this.FrameBuffer.ModeInfoCount];
this.tusCount[2] = new int[this.FrameBuffer.ModeInfoCount]; this.tusCount[2] = new int[this.FrameBuffer.ModeInfoCount];
this.coefficients = new int[3][];
this.coefficientIndex = new int[3];
} }
public ObuFrameHeader FrameInfo { get; } public ObuFrameHeader FrameInfo { get; }
@ -371,7 +370,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
this.ResetSkipContext(partitionInfo); this.ResetSkipContext(partitionInfo);
} }
this.Residual(rowIndex, columnIndex, blockSize); this.Residual(partitionInfo, superblockInfo, tileInfo, blockSize);
} }
private void ResetSkipContext(Av1PartitionInfo partitionInfo) private void ResetSkipContext(Av1PartitionInfo partitionInfo)
@ -394,46 +393,97 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// <summary> /// <summary>
/// 5.11.34. Residual syntax. /// 5.11.34. Residual syntax.
/// </summary> /// </summary>
private void Residual(int rowIndex, int columnIndex, Av1BlockSize blockSize) private void Residual(Av1PartitionInfo partitionInfo, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo, Av1BlockSize blockSize)
{ {
bool subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX; int maxBlocksWide = partitionInfo.GetMaxBlockWide(blockSize, false);
bool subsamplingY = this.SequenceHeader.ColorConfig.SubSamplingY; int maxBlocksHigh = partitionInfo.GetMaxBlockHigh(blockSize, false);
int superBlockMask = this.SequenceHeader.Use128x128SuperBlock ? 31 : 15; Av1BlockSize maxUnitSize = Av1BlockSize.Block64x64;
int widthChunks = Math.Max(1, blockSize.Get4x4WideCount() >> 6); int modeUnitBlocksWide = maxUnitSize.GetWidth() >> 2;
int heightChunks = Math.Max(1, blockSize.Get4x4HighCount() >> 6); int modeUnitBlocksHigh = maxUnitSize.GetHeight() >> 2;
Av1BlockSize sizeChunk = widthChunks > 1 || heightChunks > 1 ? Av1BlockSize.Block64x64 : blockSize; modeUnitBlocksWide = Math.Min(maxBlocksWide, modeUnitBlocksWide);
modeUnitBlocksHigh = Math.Min(maxBlocksHigh, modeUnitBlocksHigh);
int planeCount = this.SequenceHeader.ColorConfig.ChannelCount;
bool isLossless = this.FrameInfo.LosslessArray[partitionInfo.ModeInfo.SegmentId];
bool isLosslessBlock = isLossless && (blockSize >= Av1BlockSize.Block64x64) && (blockSize <= Av1BlockSize.Block128x128);
int subSampling = (this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0) + (this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0);
int chromaTusCount = isLosslessBlock ? ((maxBlocksWide * maxBlocksHigh) >> subSampling) : partitionInfo.ModeInfo.TusCount[(int)Av1PlaneType.Uv];
int[] transformInfoIndices = new int[3];
transformInfoIndices[0] = superblockInfo.TransformInfoIndexY + partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Y];
transformInfoIndices[1] = superblockInfo.TransformInfoIndexUv + partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv];
transformInfoIndices[2] = transformInfoIndices[1] + chromaTusCount;
int forceSplitCount = 0;
for (int chunkY = 0; chunkY < heightChunks; chunkY++) for (int row = 0; row < maxBlocksHigh; row += modeUnitBlocksHigh)
{ {
for (int chunkX = 0; chunkX < widthChunks; chunkX++) for (int column = 0; column < maxBlocksWide; column += modeUnitBlocksWide)
{ {
int rowChunk = rowIndex + (chunkY << 4); for (int plane = 0; plane < planeCount; ++plane)
int columnChunk = columnIndex + (chunkX << 4);
int subBlockRow = rowChunk & superBlockMask;
int subBlockColumn = columnChunk & superBlockMask;
int endPlane = 1 + (this.HasChroma(rowIndex, columnIndex, blockSize) ? 2 : 0);
for (int plane = 0; plane < endPlane; plane++)
{ {
Av1TransformSize transformSize = this.FrameInfo.CodedLossless ? Av1TransformSize.Size4x4 : this.GetSize(plane, -1); int totalTusCount;
int stepX = transformSize.GetWidth() >> 2; int tusCount;
int stepY = transformSize.GetHeight() >> 2; int subX = plane > 0 && this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0;
Av1BlockSize planeSize = this.GetPlaneResidualSize(sizeChunk, plane); int subY = plane > 0 && this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0;
int num4x4Width = planeSize.Get4x4WideCount();
int num4x4Height = planeSize.Get4x4HighCount(); if (plane != 0 && !partitionInfo.IsChroma)
int subX = plane > 0 && subsamplingX ? 1 : 0; {
int subY = plane > 0 && subsamplingY ? 1 : 0; continue;
int baseX = (columnChunk >> subX) * (1 << Av1Constants.ModeInfoSizeLog2); }
int baseY = (rowChunk >> subY) * (1 << Av1Constants.ModeInfoSizeLog2);
int baseXBlock = (columnIndex >> subX) * (1 << Av1Constants.ModeInfoSizeLog2); if (isLosslessBlock)
int baseYBlock = (rowIndex >> subY) * (1 << Av1Constants.ModeInfoSizeLog2); {
for (int y = 0; y < num4x4Height; y += stepY) // TODO: Implement.
int unitHeight = Av1Math.RoundPowerOf2(Math.Min(modeUnitBlocksHigh + row, maxBlocksHigh), 0);
int unitWidth = Av1Math.RoundPowerOf2(Math.Min(modeUnitBlocksWide + column, maxBlocksWide), 0);
totalTusCount = 0;
tusCount = ((unitWidth - column) * (unitHeight - row)) >> (subX + subY);
}
else
{
totalTusCount = partitionInfo.ModeInfo.TusCount[Math.Min(1, plane)];
tusCount = this.tusCount[plane][forceSplitCount];
DebugGuard.IsFalse(totalTusCount == 0, nameof(totalTusCount), string.Empty);
DebugGuard.IsTrue(totalTusCount == this.tusCount[plane][0] + this.tusCount[plane][1] + this.tusCount[plane][2] + this.tusCount[plane][3], nameof(totalTusCount), string.Empty);
}
DebugGuard.IsFalse(tusCount == 0, nameof(tusCount), string.Empty);
for (int tu = 0; tu < tusCount; tu++)
{ {
for (int x = 0; x < num4x4Width; x += stepX) int coefficientIndex = this.coefficientIndex[plane];
int endOfBlock = 0;
Av1TransformInfo transformInfo = this.FrameBuffer.GetTransform(plane, transformInfoIndices[plane])!;
int blockColumn = transformInfo.TransformOffsetX;
int blockRow = transformInfo.TransformOffsetY;
int startX = (partitionInfo.ColumnIndex >> subX) + blockColumn;
int startY = (partitionInfo.RowIndex >> subY) + blockRow;
if (startX >= (this.FrameInfo.ModeInfoColumnCount >> subX) ||
startY >= (this.FrameInfo.ModeInfoRowCount >> subY))
{ {
this.TransformBlock(plane, baseXBlock, baseYBlock, transformSize, x + (chunkX << 4 >> subX), y + (chunkY << 4 >> subY)); return;
} }
if (!partitionInfo.ModeInfo.Skip)
{
endOfBlock = this.TransformBlock(partitionInfo, coefficientIndex, transformInfo, plane, blockColumn, blockRow, startX, startY, transformInfo.TransformSize, subX, subY);
}
if (endOfBlock != 0)
{
this.coefficientIndex[plane] += 2;
transformInfo.CodeBlockFlag = true;
}
else
{
transformInfo.CodeBlockFlag = false;
}
transformInfoIndices[plane]++;
} }
} }
forceSplitCount++;
} }
} }
} }
@ -458,25 +508,29 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// </summary> /// </summary>
private Av1BlockSize GetPlaneResidualSize(Av1BlockSize sizeChunk, int plane) private Av1BlockSize GetPlaneResidualSize(Av1BlockSize sizeChunk, int plane)
{ {
int subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0; bool subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX;
int subsamplingY = this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0; bool subsamplingY = this.SequenceHeader.ColorConfig.SubSamplingY;
int subX = plane > 0 ? subsamplingX : 0; bool subX = plane > 0 && subsamplingX;
int subY = plane > 0 ? subsamplingY : 0; bool subY = plane > 0 && subsamplingY;
return Av1LookupTables.SubSampledSize[(byte)sizeChunk, subX, subY]; return sizeChunk.GetSubsampled(subX, subY);
} }
/// <summary> /// <summary>
/// 5.11.35. Transform block syntax. /// 5.11.35. Transform block syntax.
/// </summary> /// </summary>
private void TransformBlock(int plane, int baseX, int baseY, Av1TransformSize transformSize, int x, int y) private int TransformBlock(
Av1PartitionInfo partitionInfo,
int coefficientIndex,
Av1TransformInfo transformInfo,
int plane,
int blockColumn,
int blockRow,
int startX,
int startY,
Av1TransformSize transformSize,
int subX,
int subY)
{ {
Av1PartitionInfo partitionInfo = new(new(1, Av1BlockSize.Invalid, new Point(0, 0)), new(this.FrameBuffer, default), false, Av1PartitionType.None);
int startX = (baseX + 4) * x;
int startY = (baseY + 4) * y;
bool subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX;
bool subsamplingY = this.SequenceHeader.ColorConfig.SubSamplingY;
int subX = plane > 0 && subsamplingX ? 1 : 0;
int subY = plane > 0 && subsamplingY ? 1 : 0;
int columnIndex = startX << subX >> Av1Constants.ModeInfoSizeLog2; int columnIndex = startX << subX >> Av1Constants.ModeInfoSizeLog2;
int rowIndex = startY << subY >> Av1Constants.ModeInfoSizeLog2; int rowIndex = startY << subY >> Av1Constants.ModeInfoSizeLog2;
int superBlockMask = this.SequenceHeader.Use128x128SuperBlock ? 31 : 15; int superBlockMask = this.SequenceHeader.Use128x128SuperBlock ? 31 : 15;
@ -488,13 +542,13 @@ internal class Av1TileDecoder : IAv1TileDecoder
int maxY = (this.SequenceHeader.ModeInfoSize * (1 << Av1Constants.ModeInfoSizeLog2)) >> subY; int maxY = (this.SequenceHeader.ModeInfoSize * (1 << Av1Constants.ModeInfoSizeLog2)) >> subY;
if (startX >= maxX || startY >= maxY) if (startX >= maxX || startY >= maxY)
{ {
return; return 0;
} }
if ((plane == 0 && partitionInfo.ModeInfo.GetPaletteSize(Av1PlaneType.Y) > 0) || if ((plane == 0 && partitionInfo.ModeInfo.GetPaletteSize(Av1PlaneType.Y) > 0) ||
(plane != 0 && partitionInfo.ModeInfo.GetPaletteSize(Av1PlaneType.Uv) > 0)) (plane != 0 && partitionInfo.ModeInfo.GetPaletteSize(Av1PlaneType.Uv) > 0))
{ {
this.PredictPalette(plane, startX, startY, x, y, transformSize); this.PredictPalette(plane, startX, startY, blockColumn, blockRow, transformSize);
} }
else else
{ {
@ -511,8 +565,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
int log2Width = transformSize.GetWidthLog2(); int log2Width = transformSize.GetWidthLog2();
int log2Height = transformSize.GetHeightLog2(); int log2Height = transformSize.GetHeightLog2();
bool leftAvailable = x > 0 || plane == 0 ? partitionInfo.AvailableLeft : partitionInfo.AvailableLeftForChroma; bool leftAvailable = blockColumn > 0 || plane == 0 ? partitionInfo.AvailableLeft : partitionInfo.AvailableLeftForChroma;
bool upAvailable = y > 0 || plane == 0 ? partitionInfo.AvailableUp : partitionInfo.AvailableUpForChroma; bool upAvailable = blockRow > 0 || plane == 0 ? partitionInfo.AvailableUp : partitionInfo.AvailableUpForChroma;
bool haveAboveRight = this.blockDecoded[plane][(subBlockRow >> subY) - 1][(subBlockColumn >> subX) + stepX]; bool haveAboveRight = this.blockDecoded[plane][(subBlockRow >> subY) - 1][(subBlockColumn >> subX) + stepX];
bool haveBelowLeft = this.blockDecoded[plane][(subBlockRow >> subY) + stepY][(subBlockColumn >> subX) - 1]; bool haveBelowLeft = this.blockDecoded[plane][(subBlockRow >> subY) + stepY][(subBlockColumn >> subX) - 1];
this.PredictIntra(plane, startX, startY, leftAvailable, upAvailable, haveAboveRight, haveBelowLeft, mode, log2Width, log2Height); this.PredictIntra(plane, startX, startY, leftAvailable, upAvailable, haveAboveRight, haveBelowLeft, mode, log2Width, log2Height);
@ -545,6 +599,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
this.blockDecoded[plane][(subBlockRow >> subY) + i][(subBlockColumn >> subX) + j] = true; this.blockDecoded[plane][(subBlockRow >> subY) + i][(subBlockColumn >> subX) + j] = true;
} }
} }
return -1;
} }
private void Reconstruct(int plane, int startX, int startY, Av1TransformSize transformSize) => throw new NotImplementedException(); private void Reconstruct(int plane, int startX, int startY, Av1TransformSize transformSize) => throw new NotImplementedException();

6
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformInfo.cs

@ -23,4 +23,10 @@ internal class Av1TransformInfo
public int OffsetX { get; internal set; } public int OffsetX { get; internal set; }
public int OffsetY { get; internal set; } public int OffsetY { get; internal set; }
public bool CodeBlockFlag { get; internal set; }
public int TransformOffsetX { get; internal set; }
public int TransformOffsetY { get; internal set; }
} }

Loading…
Cancel
Save