Browse Source

Implement TransformBlock

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
1ff01503ac
  1. 14
      src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs
  2. 2
      src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
  3. 8
      src/ImageSharp/Formats/Heif/Av1/Av1MainParseContext.cs
  4. 1
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
  5. 9
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs
  6. 2
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs
  7. 2
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs
  8. 4
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionInfo.cs
  9. 272
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
  10. 11
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformBlockContext.cs
  11. 25
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs

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

@ -50,6 +50,9 @@ internal static class Av1BlockSizeExtensions
Av1TransformSize.Size16x64, Av1TransformSize.Size64x16
];
private static readonly int[] PelsLog2Count =
[4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 6, 6, 8, 8, 10, 10];
public static int Get4x4WideCount(this Av1BlockSize blockSize) => SizeWide[(int)blockSize];
public static int Get4x4HighCount(this Av1BlockSize blockSize) => SizeHigh[(int)blockSize];
@ -82,13 +85,19 @@ internal static class Av1BlockSizeExtensions
/// Returns the block size of a sub sampled block.
/// </summary>
public static Av1BlockSize GetSubsampled(this Av1BlockSize blockSize, bool subX, bool subY)
=> GetSubsampled(blockSize, subX ? 1 : 0, subY ? 1 : 0);
/// <summary>
/// Returns the block size of a sub sampled block.
/// </summary>
public static Av1BlockSize GetSubsampled(this Av1BlockSize blockSize, int subX, int subY)
{
if (blockSize == Av1BlockSize.Invalid)
{
return Av1BlockSize.Invalid;
}
return SubSampled[(int)blockSize][subX ? 1 : 0][subY ? 1 : 0];
return SubSampled[(int)blockSize][subX][subY];
}
public static Av1TransformSize GetMaxUvTransformSize(this Av1BlockSize blockSize, bool subX, bool subY)
@ -115,4 +124,7 @@ internal static class Av1BlockSizeExtensions
/// </summary>
public static Av1TransformSize GetMaximumTransformSize(this Av1BlockSize blockSize)
=> MaxTransformSize[(int)blockSize];
public static int GetPelsLog2Count(this Av1BlockSize blockSize)
=> PelsLog2Count[(int)blockSize];
}

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

@ -138,4 +138,6 @@ internal static class Av1Constants
/// Maximum transform size categories.
/// </summary>
public const int MaxTransformCategories = 4;
public const int CoefficientContextCount = 6;
}

8
src/ImageSharp/Formats/Heif/Av1/Av1MainParseContext.cs

@ -1,8 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal class Av1MainParseContext
{
}

1
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs

@ -1095,7 +1095,6 @@ internal class ObuReader
ReadFrameDeltaLoopFilterParameters(ref reader, frameInfo);
// SetupSegmentationDequantization();
Av1MainParseContext mainParseContext = new();
if (frameInfo.PrimaryReferenceFrame == Av1Constants.PrimaryReferenceFrameNone)
{
// ResetParseContext(mainParseContext, frameInfo.QuantizationParameters.BaseQIndex);

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

@ -150,6 +150,15 @@ internal class Av1FrameBuffer
span[index] = transformInfo;
}
public Span<int> GetCoefficients(int plane) =>
plane switch
{
0 => (Span<int>)this.coefficientsY,
2 => (Span<int>)this.coefficientsY,
3 => (Span<int>)this.coefficientsY,
_ => null,
};
public Span<int> GetCoefficientsY(Point index)
{
Span<int> span = this.coefficientsY;

2
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs

@ -46,6 +46,8 @@ internal class Av1ParseAboveNeighbor4x4Context
public int[] AboveTransformWidth => this.aboveTransformWidth;
public int[] GetContext(int plane) => this.aboveContext[plane];
public void Clear(ObuSequenceHeader sequenceHeader)
{
int planeCount = sequenceHeader.ColorConfig.ChannelCount;

2
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs

@ -91,4 +91,6 @@ internal class Av1ParseLeftNeighbor4x4Context
internal void ClearContext(int plane, int offset, int length)
=> Array.Fill(this.leftContext[plane], 0, offset, length);
internal int[] GetContext(int plane) => this.leftContext[plane];
}

4
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionInfo.cs

@ -50,6 +50,10 @@ internal class Av1PartitionInfo
public int[] ReferenceFrame { get; set; }
public int ModeBlockToRightEdge => this.modeBlockToRightEdge;
public int ModeBlockToBottomEdge => this.modeBlockToBottomEdge;
public void ComputeBoundaryOffsets(ObuFrameHeader frameInfo, Av1TileInfo tileInfo)
{
Av1BlockSize blockSize = this.ModeInfo.BlockSize;

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

@ -13,6 +13,13 @@ internal class Av1TileDecoder : IAv1TileDecoder
private static readonly int[] SgrprojXqdMid = [-32, 31];
private static readonly int[] WienerTapsMid = [3, -7, 15];
private const int PartitionProbabilitySet = 4;
private static readonly int[] Signs = [0, -1, 1];
private static readonly int[] DcSignContexts = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2];
private static readonly int[][] SkipContexts = [
[1, 2, 2, 2, 3], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 6]];
private bool[][][] blockDecoded = [];
private int[][] referenceSgrXqd = [];
@ -25,13 +32,10 @@ internal class Av1TileDecoder : IAv1TileDecoder
private int[][] leftLevelContext = [];
private int[][] leftDcContext = [];
private int[][] segmentIds = [];
private int maxLumaWidth;
private int maxLumaHeight;
private int deltaLoopFilterResolution = -1;
private bool readDeltas;
private int[][] tusCount;
private int[] firstTransformOffset = new int[2];
private int[][] coefficients = [];
private int[] coefficientIndex = [];
public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
@ -61,8 +65,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
this.tusCount[0] = new int[this.FrameBuffer.ModeInfoCount];
this.tusCount[1] = new int[this.FrameBuffer.ModeInfoCount];
this.tusCount[2] = new int[this.FrameBuffer.ModeInfoCount];
this.coefficients = new int[3][];
this.coefficientIndex = new int[3];
this.coefficientIndex = new int[Av1Constants.MaxPlanes];
}
public ObuFrameHeader FrameInfo { get; }
@ -370,7 +373,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
this.ResetSkipContext(partitionInfo);
}
this.Residual(partitionInfo, superblockInfo, tileInfo, blockSize);
this.Residual(ref reader, partitionInfo, superblockInfo, tileInfo, blockSize);
}
private void ResetSkipContext(Av1PartitionInfo partitionInfo)
@ -393,7 +396,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// <summary>
/// 5.11.34. Residual syntax.
/// </summary>
private void Residual(Av1PartitionInfo partitionInfo, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo, Av1BlockSize blockSize)
private void Residual(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo, Av1BlockSize blockSize)
{
int maxBlocksWide = partitionInfo.GetMaxBlockWide(blockSize, false);
int maxBlocksHigh = partitionInfo.GetMaxBlockHigh(blockSize, false);
@ -466,7 +469,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
if (!partitionInfo.ModeInfo.Skip)
{
endOfBlock = this.TransformBlock(partitionInfo, coefficientIndex, transformInfo, plane, blockColumn, blockRow, startX, startY, transformInfo.TransformSize, subX, subY);
endOfBlock = this.TransformBlock(ref reader, partitionInfo, coefficientIndex, transformInfo, plane, blockColumn, blockRow, startX, startY, transformInfo.TransformSize, subX != 0, subY != 0);
}
if (endOfBlock != 0)
@ -519,6 +522,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// 5.11.35. Transform block syntax.
/// </summary>
private int TransformBlock(
ref Av1SymbolDecoder reader,
Av1PartitionInfo partitionInfo,
int coefficientIndex,
Av1TransformInfo transformInfo,
@ -528,79 +532,227 @@ internal class Av1TileDecoder : IAv1TileDecoder
int startX,
int startY,
Av1TransformSize transformSize,
int subX,
int subY)
bool subX,
bool subY)
{
int columnIndex = startX << subX >> Av1Constants.ModeInfoSizeLog2;
int rowIndex = startY << subY >> Av1Constants.ModeInfoSizeLog2;
int superBlockMask = this.SequenceHeader.Use128x128SuperBlock ? 31 : 15;
int subBlockColumn = columnIndex & superBlockMask;
int subBlockRow = rowIndex & superBlockMask;
int stepX = transformSize.GetWidth() >> Av1Constants.ModeInfoSizeLog2;
int stepY = transformSize.GetHeight() >> Av1Constants.ModeInfoSizeLog2;
int maxX = (this.SequenceHeader.ModeInfoSize * (1 << Av1Constants.ModeInfoSizeLog2)) >> subX;
int maxY = (this.SequenceHeader.ModeInfoSize * (1 << Av1Constants.ModeInfoSizeLog2)) >> subY;
if (startX >= maxX || startY >= maxY)
int endOfBlock = 0;
Av1BlockSize planeBlockSize = partitionInfo.ModeInfo.BlockSize.GetSubsampled(subX, subY);
int transformBlockUnitWideCount = transformSize.Get4x4WideCount();
int transformBlockUnitHighCount = transformSize.Get4x4HighCount();
if (partitionInfo.ModeBlockToRightEdge < 0)
{
return 0;
int blocksWide = partitionInfo.GetMaxBlockWide(planeBlockSize, subX);
transformBlockUnitWideCount = Math.Min(transformBlockUnitWideCount, blocksWide - blockColumn);
}
if ((plane == 0 && partitionInfo.ModeInfo.GetPaletteSize(Av1PlaneType.Y) > 0) ||
(plane != 0 && partitionInfo.ModeInfo.GetPaletteSize(Av1PlaneType.Uv) > 0))
if (partitionInfo.ModeBlockToBottomEdge < 0)
{
this.PredictPalette(plane, startX, startY, blockColumn, blockRow, transformSize);
int blocksHigh = partitionInfo.GetMaxBlockHigh(planeBlockSize, subY);
transformBlockUnitHighCount = Math.Min(transformBlockUnitHighCount, blocksHigh - blockRow);
}
else
Av1TransformBlockContext transformBlockContext = this.GetTransformBlockContext(transformSize, plane, planeBlockSize, transformBlockUnitHighCount, transformBlockUnitWideCount, startY, startX);
endOfBlock = this.ParseCoefficients(ref reader, partitionInfo, startY, startX, blockRow, blockColumn, plane, transformBlockContext, transformSize, coefficientIndex, transformInfo);
return endOfBlock;
}
/// <summary>
/// 5.11.39. Coefficients syntax.
/// </summary>
private int ParseCoefficients(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, int startY, int startX, int blockRow, int blockColumn, int plane, Av1TransformBlockContext transformBlockContext, Av1TransformSize transformSize, int coefficientIndex, Av1TransformInfo transformInfo) => throw new NotImplementedException();
private Av1TransformBlockContext GetTransformBlockContext(Av1TransformSize transformSize, int plane, Av1BlockSize planeBlockSize, int transformBlockUnitHighCount, int transformBlockUnitWideCount, int startY, int startX)
{
Av1TransformBlockContext transformBlockContext = new();
int[] aboveContext = this.aboveNeighborContext.GetContext(plane);
int[] leftContext = this.leftNeighborContext.GetContext(plane);
int dcSign = 0;
int k = 0;
int mask = (1 << Av1Constants.CoefficientContextCount) - 1;
do
{
bool isChromaFromLuma = plane > 0 && partitionInfo.ModeInfo.UvMode == Av1PredictionMode.UvChromaFromLuma;
Av1PredictionMode mode;
if (plane == 0)
int sign = aboveContext[k] >> Av1Constants.CoefficientContextCount;
DebugGuard.MustBeLessThanOrEqualTo(sign, 2, nameof(sign));
dcSign += Signs[sign];
}
while (++k < transformBlockUnitHighCount);
transformBlockContext.DcSignContext = dcSign;
if (plane == 0)
{
if (planeBlockSize == transformSize.GetBlockSize())
{
mode = partitionInfo.ModeInfo.YMode;
transformBlockContext.SkipContext = 0;
}
else
{
mode = isChromaFromLuma ? Av1PredictionMode.DC : partitionInfo.ModeInfo.UvMode;
}
int top = 0;
int left = 0;
int log2Width = transformSize.GetWidthLog2();
int log2Height = transformSize.GetHeightLog2();
bool leftAvailable = blockColumn > 0 || plane == 0 ? partitionInfo.AvailableLeft : partitionInfo.AvailableLeftForChroma;
bool upAvailable = blockRow > 0 || plane == 0 ? partitionInfo.AvailableUp : partitionInfo.AvailableUpForChroma;
bool haveAboveRight = this.blockDecoded[plane][(subBlockRow >> subY) - 1][(subBlockColumn >> subX) + stepX];
bool haveBelowLeft = this.blockDecoded[plane][(subBlockRow >> subY) + stepY][(subBlockColumn >> subX) - 1];
this.PredictIntra(plane, startX, startY, leftAvailable, upAvailable, haveAboveRight, haveBelowLeft, mode, log2Width, log2Height);
if (isChromaFromLuma)
{
this.PredictChromaFromLuma(plane, startX, startY, transformSize);
k = 0;
do
{
top |= aboveContext[k];
}
while (++k < transformBlockUnitWideCount);
top &= mask;
k = 0;
do
{
left |= leftContext[k];
}
while (++k < transformBlockUnitHighCount);
left &= mask;
int max = Math.Min(top | left, 4);
int min = Math.Min(Math.Min(top, left), 4);
transformBlockContext.SkipContext = SkipContexts[min][max];
}
}
if (plane == 0)
else
{
this.maxLumaWidth = startX + (stepX * 4);
this.maxLumaHeight = startY + (stepY * 4);
int contextBase = GetEntropyContext(transformSize, aboveContext, leftContext);
int contextOffset = planeBlockSize.GetPelsLog2Count() > transformSize.GetBlockSize().GetPelsLog2Count() ? 10 : 7;
transformBlockContext.SkipContext = contextBase + contextOffset;
}
if (!partitionInfo.ModeInfo.Skip)
{
int eob = this.Coefficients(plane, startX, startY, transformSize);
if (eob > 0)
{
this.Reconstruct(plane, startX, startY, transformSize);
}
}
return transformBlockContext;
}
for (int i = 0; i < stepY; i++)
private static int GetEntropyContext(Av1TransformSize transformSize, int[] above, int[] left)
{
bool aboveEntropyContext = false;
bool leftEntropyContext = false;
switch (transformSize)
{
for (int j = 0; j < stepX; j++)
{
// Ignore loop filter.
this.blockDecoded[plane][(subBlockRow >> subY) + i][(subBlockColumn >> subX) + j] = true;
}
case Av1TransformSize.Size4x4:
aboveEntropyContext = above[0] != 0;
leftEntropyContext = left[0] != 0;
break;
case Av1TransformSize.Size4x8:
aboveEntropyContext = above[0] != 0;
leftEntropyContext = (left[0] & (left[1] << 8)) != 0; // !!*(const uint16_t*)left;
break;
case Av1TransformSize.Size8x4:
aboveEntropyContext = (above[0] & (above[1] << 8)) != 0; // !!*(const uint16_t*)above;
leftEntropyContext = left[0] != 0;
break;
case Av1TransformSize.Size8x16:
aboveEntropyContext = (above[0] & (above[1] << 8)) != 0; // !!*(const uint16_t*)above;
leftEntropyContext = (left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0; // !!*(const uint32_t*)left;
break;
case Av1TransformSize.Size16x8:
aboveEntropyContext = (above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0; // !!*(const uint32_t*)above;
leftEntropyContext = (left[0] & (left[1] << 8)) != 0; // !!*(const uint16_t*)left;
break;
case Av1TransformSize.Size16x32:
aboveEntropyContext = (above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0; // !!*(const uint32_t*)above;
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0; // !!*(const uint64_t*)left;
break;
case Av1TransformSize.Size32x16:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0; // !!*(const uint64_t*)above;
leftEntropyContext = (left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0; // !!*(const uint32_t*)left;
break;
case Av1TransformSize.Size8x8:
aboveEntropyContext = (above[0] & (above[1] << 8)) != 0; // !!*(const uint16_t*)above;
leftEntropyContext = (left[0] & (left[1] << 8)) != 0; // !!*(const uint16_t*)left;
break;
case Av1TransformSize.Size16x16:
aboveEntropyContext = (above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0; // !!*(const uint32_t*)above;
leftEntropyContext = (left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0; // !!*(const uint32_t*)left;
break;
case Av1TransformSize.Size32x32:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0; // !!*(const uint64_t*)above;
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0; // !!*(const uint64_t*)left;
break;
case Av1TransformSize.Size64x64:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0 ||
(above[8] & (above[9] << 8) & (above[10] << 16) & (above[11] << 24)) != 0 ||
(above[12] & (above[13] << 8) & (above[14] << 16) & (above[15] << 24)) != 0; // !!(*(const uint64_t*)above | *(const uint64_t*)(above + 8));
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0 ||
(left[8] & (left[9] << 8) & (left[10] << 16) & (left[11] << 24)) != 0 ||
(left[12] & (left[13] << 8) & (left[14] << 16) & (left[15] << 24)) != 0; // !!(*(const uint64_t*)left | *(const uint64_t*)(left + 8));
break;
case Av1TransformSize.Size32x64:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0; // !!*(const uint64_t*)above;
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0 ||
(left[8] & (left[9] << 8) & (left[10] << 16) & (left[11] << 24)) != 0 ||
(left[12] & (left[13] << 8) & (left[14] << 16) & (left[15] << 24)) != 0; // !!(*(const uint64_t*)left | *(const uint64_t*)(left + 8));
break;
case Av1TransformSize.Size64x32:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0 ||
(above[8] & (above[9] << 8) & (above[10] << 16) & (above[11] << 24)) != 0 ||
(above[12] & (above[13] << 8) & (above[14] << 16) & (above[15] << 24)) != 0; // !!(*(const uint64_t*)above | *(const uint64_t*)(above + 8));
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0; // !!*(const uint64_t*)left;
break;
case Av1TransformSize.Size4x16:
aboveEntropyContext = above[0] != 0;
leftEntropyContext = (left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0; // !!*(const uint32_t*)left;
break;
case Av1TransformSize.Size16x4:
aboveEntropyContext = (above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0; // !!*(const uint32_t*)above;
leftEntropyContext = left[0] != 0;
break;
case Av1TransformSize.Size8x32:
aboveEntropyContext = (above[0] & (above[1] << 8)) != 0; // !!*(const uint16_t*)above;
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0; // !!*(const uint64_t*)left;
break;
case Av1TransformSize.Size32x8:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0; // !!*(const uint64_t*)above;
leftEntropyContext = (left[0] & (left[1] << 8)) != 0; // !!*(const uint16_t*)left;
break;
case Av1TransformSize.Size16x64:
aboveEntropyContext = (above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0; // !!*(const uint32_t*)above;
leftEntropyContext =
(left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0 ||
(left[4] & (left[5] << 8) & (left[6] << 16) & (left[7] << 24)) != 0 ||
(left[8] & (left[9] << 8) & (left[10] << 16) & (left[11] << 24)) != 0 ||
(left[12] & (left[13] << 8) & (left[14] << 16) & (left[15] << 24)) != 0; // !!(*(const uint64_t*)left | *(const uint64_t*)(left + 8));
break;
case Av1TransformSize.Size64x16:
aboveEntropyContext =
(above[0] & (above[1] << 8) & (above[2] << 16) & (above[3] << 24)) != 0 ||
(above[4] & (above[5] << 8) & (above[6] << 16) & (above[7] << 24)) != 0 ||
(above[8] & (above[9] << 8) & (above[10] << 16) & (above[11] << 24)) != 0 ||
(above[12] & (above[13] << 8) & (above[14] << 16) & (above[15] << 24)) != 0; // !!(*(const uint64_t*)above | *(const uint64_t*)(above + 8));
leftEntropyContext = (left[0] & (left[1] << 8) & (left[2] << 16) & (left[3] << 24)) != 0; // !!*(const uint32_t*)left;
break;
default:
Guard.IsTrue(false, nameof(transformSize), "Invalid transform size.");
break;
}
return -1;
return (aboveEntropyContext ? 1 : 0) + (leftEntropyContext ? 1 : 0);
}
private void Reconstruct(int plane, int startX, int startY, Av1TransformSize transformSize) => throw new NotImplementedException();

11
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformBlockContext.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal class Av1TransformBlockContext
{
public int DcSignContext { get; set; }
public int SkipContext { get; set; }
}

25
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs

@ -36,6 +36,29 @@ internal static class Av1TransformSizeExtensions
// Transform block height in unit
private static readonly int[] HighUnit = [1, 2, 4, 8, 16, 2, 1, 4, 2, 8, 4, 16, 8, 4, 1, 8, 2, 16, 4];
// Transform size conversion into Block Size
private static readonly Av1BlockSize[] BlockSize = [
Av1BlockSize.Block4x4, // TX_4X4
Av1BlockSize.Block8x8, // TX_8X8
Av1BlockSize.Block16x16, // TX_16X16
Av1BlockSize.Block32x32, // TX_32X32
Av1BlockSize.Block64x64, // TX_64X64
Av1BlockSize.Block4x8, // TX_4X8
Av1BlockSize.Block8x4, // TX_8X4
Av1BlockSize.Block8x16, // TX_8X16
Av1BlockSize.Block16x8, // TX_16X8
Av1BlockSize.Block16x32, // TX_16X32
Av1BlockSize.Block32x16, // TX_32X16
Av1BlockSize.Block32x64, // TX_32X64
Av1BlockSize.Block64x32, // TX_64X32
Av1BlockSize.Block4x16, // TX_4X16
Av1BlockSize.Block16x4, // TX_16X4
Av1BlockSize.Block8x32, // TX_8X32
Av1BlockSize.Block32x8, // TX_32X8
Av1BlockSize.Block16x64, // TX_16X64
Av1BlockSize.Block64x16, // TX_64X16
];
public static int GetScale(this Av1TransformSize size)
{
int pels = Size2d[(int)size];
@ -55,4 +78,6 @@ internal static class Av1TransformSizeExtensions
public static int Get4x4HighCount(this Av1TransformSize size) => HighUnit[(int)size];
public static Av1TransformSize GetSubSize(this Av1TransformSize size) => SubTransformSize[(int)size];
public static Av1BlockSize GetBlockSize(this Av1TransformSize transformSize) => (Av1BlockSize)BlockSize[(int)transformSize];
}

Loading…
Cancel
Save