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];
}
}