diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs index 92a651d60f..c38f620c41 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs @@ -72,7 +72,8 @@ internal enum Av1BlockSize : byte /// A block of samples, 64 samples wide and 16 samples high. Block64x16 = 21, - Invalid = 22, + SizesAll = 22, SizeS = Block4x16, + Invalid = 255, Largest = SizeS - 1, } diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs index 6f1490975e..3c5ce9e596 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs @@ -104,7 +104,7 @@ internal static class Av1BlockSizeExtensions { Av1BlockSize planeBlockSize = blockSize.GetSubsampled(subX, subY); Av1TransformSize uvTransformSize = Av1TransformSize.Invalid; - if (planeBlockSize < Av1BlockSize.SizeS) + if (planeBlockSize < Av1BlockSize.SizesAll) { uvTransformSize = planeBlockSize.GetMaximumTransformSize(); } diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs index 3d8194190d..1d1e9d162b 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs @@ -105,35 +105,20 @@ internal partial class Av1FrameBuffer return this.modeInfos[index]; } - public ref Av1TransformInfo GetTransformY(int index) + public Span GetSuperblockTransformY(Point index) { Span span = this.transformInfosY; - return ref span[index]; + int offset = ((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock; + int length = this.modeInfoCountPerSuperblock; + return span.Slice(offset, length); } - public void SetTransformY(int index, Av1TransformInfo transformInfo) - { - Span span = this.transformInfosY; - span[index] = transformInfo; - } - - public ref Av1TransformInfo GetTransformY(Point index) - { - Span span = this.transformInfosY; - int i = (index.Y * this.superblockColumnCount) + index.X; - return ref span[i * this.modeInfoCountPerSuperblock]; - } - - public ref Av1TransformInfo GetTransformUv(int index) + public Span GetSuperblockTransformUv(Point index) { Span span = this.transformInfosUv; - return ref span[index]; - } - - public void SetTransformUv(int index, Av1TransformInfo transformInfo) - { - Span span = this.transformInfosUv; - span[index] = transformInfo; + int offset = (((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock) << 1; + int length = this.modeInfoCountPerSuperblock << 1; + return span.Slice(offset, length); } public Span GetCoefficients(int plane) => @@ -198,14 +183,6 @@ internal partial class Av1FrameBuffer 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, - }; - public void UpdateModeInfo(Av1BlockModeInfo modeInfo, Av1SuperblockInfo superblockInfo) { this.modeInfos[this.modeInfoMap.NextIndex] = modeInfo; diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs index 6fe0f7cc7d..b76b8c87d8 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs @@ -36,5 +36,9 @@ internal class Av1SuperblockInfo public int TransformInfoIndexUv { get; internal set; } + public Span GetTransformInfoY() => this.frameBuffer.GetSuperblockTransformY(this.Position); + + public Span GetTransformInfoUv() => this.frameBuffer.GetSuperblockTransformUv(this.Position); + public Av1BlockModeInfo GetModeInfo(Point index) => this.frameBuffer.GetModeInfo(this.Position, index); } diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs index 5cb054682e..16e39555f2 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs @@ -373,6 +373,7 @@ internal class Av1TileDecoder : IAv1TileDecoder 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.TransformUnitsCount[(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]; @@ -409,16 +410,20 @@ internal class Av1TileDecoder : IAv1TileDecoder 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.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); - + Span transformInfos = plane == 0 ? superblockInfo.GetTransformInfoY() : superblockInfo.GetTransformInfoUv(); for (int tu = 0; tu < tusCount; tu++) { + Av1TransformInfo transformInfo = transformInfos[transformInfoIndices[plane]]; + DebugGuard.MustBeLessThanOrEqualTo(transformInfo.OffsetX, maxBlocksWide, nameof(transformInfo)); + DebugGuard.MustBeLessThanOrEqualTo(transformInfo.OffsetY, maxBlocksHigh, nameof(transformInfo)); + int coefficientIndex = this.coefficientIndex[plane]; int endOfBlock = 0; - Av1TransformInfo transformInfo = this.FrameBuffer.GetTransform(plane, transformInfoIndices[plane])!; int blockColumn = transformInfo.OffsetX; int blockRow = transformInfo.OffsetY; int startX = (partitionInfo.ColumnIndex >> subX) + blockColumn; @@ -432,12 +437,12 @@ internal class Av1TileDecoder : IAv1TileDecoder if (!partitionInfo.ModeInfo.Skip) { - endOfBlock = this.TransformBlock(ref reader, partitionInfo, coefficientIndex, transformInfo, plane, blockColumn, blockRow, startX, startY, transformInfo.Size, subX != 0, subY != 0); + endOfBlock = this.ParseTransformBlock(ref reader, partitionInfo, coefficientIndex, transformInfo, plane, blockColumn, blockRow, startX, startY, transformInfo.Size, subX != 0, subY != 0); } if (endOfBlock != 0) { - this.coefficientIndex[plane] += 2; + this.coefficientIndex[plane] += endOfBlock + 1; transformInfo.CodeBlockFlag = true; } else @@ -487,7 +492,7 @@ internal class Av1TileDecoder : IAv1TileDecoder /// /// The implementation is taken from SVT-AV1 library, which deviates from the code flow in the specification. /// - private int TransformBlock( + private int ParseTransformBlock( ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, int coefficientIndex, @@ -1279,10 +1284,10 @@ internal class Av1TileDecoder : IAv1TileDecoder private unsafe void UpdateTransformInfo(Av1PartitionInfo partitionInfo, Av1SuperblockInfo superblockInfo, Av1BlockSize blockSize, Av1TransformSize transformSize) { - int transformInfoYIndex = superblockInfo.TransformInfoIndexY + partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Y]; - int transformInfoUvIndex = superblockInfo.TransformInfoIndexUv + partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv]; - Av1TransformInfo lumaTransformInfo = this.FrameBuffer.GetTransformY(transformInfoYIndex); - Av1TransformInfo chromaTransformInfo = this.FrameBuffer.GetTransformUv(transformInfoUvIndex); + int transformInfoYIndex = partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Y]; + int transformInfoUvIndex = partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv]; + Span lumaTransformInfo = superblockInfo.GetTransformInfoY(); + Span chromaTransformInfo = superblockInfo.GetTransformInfoUv(); int totalLumaTusCount = 0; int totalChromaTusCount = 0; int forceSplitCount = 0; @@ -1315,8 +1320,8 @@ internal class Av1TileDecoder : IAv1TileDecoder { for (int blockColumn = idx; blockColumn < unitWidth; blockColumn += stepColumn) { - this.FrameBuffer.SetTransformY(transformInfoYIndex, new Av1TransformInfo( - transformSize, blockColumn, blockRow)); + lumaTransformInfo[transformInfoYIndex] = new Av1TransformInfo( + transformSize, blockColumn, blockRow); transformInfoYIndex++; lumaTusCount++; totalLumaTusCount++; @@ -1340,8 +1345,8 @@ internal class Av1TileDecoder : IAv1TileDecoder { for (int blockColumn = idx; blockColumn < unitWidth; blockColumn += stepColumn) { - this.FrameBuffer.SetTransformUv(transformInfoUvIndex, new Av1TransformInfo( - transformSizeUv, blockColumn, blockRow)); + chromaTransformInfo[transformInfoUvIndex] = new Av1TransformInfo( + transformSizeUv, blockColumn, blockRow); transformInfoUvIndex++; chromaTusCount++; totalChromaTusCount++; @@ -1359,7 +1364,7 @@ internal class Av1TileDecoder : IAv1TileDecoder int originalIndex = transformInfoUvIndex - totalChromaTusCount; for (int i = 0; i < totalChromaTusCount; i++) { - this.FrameBuffer.SetTransformUv(transformInfoUvIndex + i, this.FrameBuffer.GetTransformUv(originalIndex + i)); + chromaTransformInfo[transformInfoUvIndex + i] = chromaTransformInfo[originalIndex + i]; } }