Browse Source

Implement partition context logic

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
a0fdf0239a
  1. 10
      src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
  2. 75
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs
  3. 76
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs
  4. 23
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionContext.cs
  5. 160
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
  6. 45
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileLocation.cs

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

@ -119,8 +119,18 @@ internal static class Av1Constants
/// </summary>
public const int MaxSegments = 8;
/// <summary>
/// Maximum number of color planes.
/// </summary>
public const int MaxPlanes = 3;
/// <summary>
/// Number of reference frame types (including intra type).
/// </summary>
public const int TotalReferencesPerFrame = 8;
/// <summary>
/// Number of values for palette_size.
/// </summary>
public const int PaletteMaxSize = 8;
}

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

@ -0,0 +1,75 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal class Av1ParseAboveNeighbor4x4Context
{
/* Buffer holding the transform sizes of the previous 4x4 block row. */
private readonly int[] aboveTransformWidth;
/* Buffer holding the partition context of the previous 4x4 block row. */
private int[] abovePartitionWidth;
/* Buffer holding the sign of the DC coefficients and the
cumulative sum of the coefficient levels of the above 4x4
blocks corresponding to the current super block row. */
private int[][] aboveContext = new int[Av1Constants.MaxPlanes][];
/* Buffer holding the seg_id_predicted of the previous 4x4 block row. */
private int[] aboveSegmentIdPredictionContext;
/* Value of base colors for Y, U, and V */
private int[][] abovePaletteColors = new int[Av1Constants.MaxPlanes][];
private int[] aboveCompGroupIndex;
public Av1ParseAboveNeighbor4x4Context(int planesCount, int modeInfoColumnCount)
{
int wide64x64Count = Av1BlockSize.Block64x64.Get4x4WideCount();
this.aboveTransformWidth = new int[modeInfoColumnCount];
this.abovePartitionWidth = new int[modeInfoColumnCount];
for (int i = 0; i < planesCount; i++)
{
this.aboveContext[i] = new int[modeInfoColumnCount];
this.abovePaletteColors[i] = new int[wide64x64Count * Av1Constants.PaletteMaxSize];
}
this.aboveSegmentIdPredictionContext = new int[modeInfoColumnCount];
this.aboveCompGroupIndex = new int[modeInfoColumnCount];
}
public int[] AbovePartitionWidth => this.abovePartitionWidth;
public void Clear(ObuSequenceHeader sequenceHeader)
{
int planeCount = sequenceHeader.ColorConfig.ChannelCount;
Array.Fill(this.aboveTransformWidth, Av1TransformSize.Size64x64.GetWidth());
Array.Fill(this.abovePartitionWidth, 0);
for (int i = 0; i < planeCount; i++)
{
Array.Fill(this.aboveContext[i], 0);
Array.Fill(this.abovePaletteColors[i], 0);
}
Array.Fill(this.aboveSegmentIdPredictionContext, 0);
Array.Fill(this.aboveCompGroupIndex, 0);
}
public void UpdatePartition(Point modeInfoLocation, Av1TileLocation tileLoc, Av1BlockSize subSize, Av1BlockSize blockSize)
{
int startIndex = modeInfoLocation.X - tileLoc.ModeInfoColumnStart;
int bw = blockSize.Get4x4WideCount();
int value = Av1PartitionContext.GetAboveContext(subSize);
for (int i = 0; i < bw; i++)
{
this.abovePartitionWidth[startIndex + i] = value;
}
}
internal void ClearContext(int plane, int offset, int length)
=> Array.Fill(this.aboveContext[plane], 0, offset, length);
}

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

@ -0,0 +1,76 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal class Av1ParseLeftNeighbor4x4Context
{
/* Buffer holding the transform sizes of the left 4x4 blocks corresponding
to the current super block row. */
private readonly int[] leftTransformHeight;
/* Buffer holding the partition context of the left 4x4 blocks corresponding
to the current super block row. */
private int[] leftPartitionHeight;
/* Buffer holding the sign of the DC coefficients and the
cumulative sum of the coefficient levels of the left 4x4
blocks corresponding to the current super block row. */
private int[][] leftContext = new int[Av1Constants.MaxPlanes][];
/* Buffer holding the seg_id_predicted of the previous 4x4 block row. */
private int[] leftSegmentIdPredictionContext;
/* Value of base colors for Y, U, and V */
private int[][] leftPaletteColors = new int[Av1Constants.MaxPlanes][];
private int[] leftCompGroupIndex;
public Av1ParseLeftNeighbor4x4Context(int planesCount, int superblockModeInfoSize)
{
this.leftTransformHeight = new int[superblockModeInfoSize];
this.leftPartitionHeight = new int[superblockModeInfoSize];
for (int i = 0; i < planesCount; i++)
{
this.leftContext[i] = new int[superblockModeInfoSize];
this.leftPaletteColors[i] = new int[superblockModeInfoSize * Av1Constants.PaletteMaxSize];
}
this.leftSegmentIdPredictionContext = new int[superblockModeInfoSize];
this.leftCompGroupIndex = new int[superblockModeInfoSize];
}
public int[] LeftPartitionHeight => this.leftPartitionHeight;
public void Clear(ObuSequenceHeader sequenceHeader)
{
int planeCount = sequenceHeader.ColorConfig.ChannelCount;
Array.Fill(this.leftTransformHeight, Av1TransformSize.Size64x64.GetHeight());
Array.Fill(this.leftPartitionHeight, 0);
for (int i = 0; i < planeCount; i++)
{
Array.Fill(this.leftContext[i], 0);
Array.Fill(this.leftPaletteColors[i], 0);
}
Array.Fill(this.leftSegmentIdPredictionContext, 0);
Array.Fill(this.leftCompGroupIndex, 0);
}
public void UpdatePartition(Point modeInfoLocation, Av1SuperblockInfo superblockInfo, Av1BlockSize subSize, Av1BlockSize blockSize)
{
int startIndex = (modeInfoLocation.Y - superblockInfo.Position.Y) & Av1PartitionContext.Mask;
int bh = blockSize.Get4x4HighCount();
int value = Av1PartitionContext.GetLeftContext(subSize);
for (int i = 0; i < bh; i++)
{
this.leftPartitionHeight[startIndex + i] = value;
}
}
internal void ClearContext(int plane, int offset, int length)
=> Array.Fill(this.leftContext[plane], 0, offset, length);
}

23
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionContext.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
// Generates 5 bit field in which each bit set to 1 represents
// a BlockSize partition 11111 means we split 128x128, 64x64, 32x32, 16x16
// and 8x8. 10000 means we just split the 128x128 to 64x64
internal class Av1PartitionContext
{
private static readonly int[] AboveLookup =
[31, 31, 30, 30, 30, 28, 28, 28, 24, 24, 24, 16, 16, 16, 0, 0, 31, 28, 30, 24, 28, 16];
private static readonly int[] LeftLookup =
[31, 30, 31, 30, 28, 30, 28, 24, 28, 24, 16, 24, 16, 0, 16, 0, 28, 31, 24, 30, 16, 28];
// Mask to extract ModeInfo offset within max ModeInfoBlock
public const int Mask = (1 << (7 - 2)) - 1;
public static int GetAboveContext(Av1BlockSize blockSize) => AboveLookup[(int)blockSize];
public static int GetLeftContext(Av1BlockSize blockSize) => LeftLookup[(int)blockSize];
}

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

@ -19,6 +19,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
private int[][][] referenceLrWiener = [];
private Av1ParseAboveContext aboveContext = new();
private Av1ParseLeftContext leftContext = new();
private Av1ParseAboveNeighbor4x4Context aboveNeighborContext;
private Av1ParseLeftNeighbor4x4Context leftNeighborContext;
private int currentQuantizerIndex;
private int[][] aboveLevelContext = [];
private int[][] aboveDcContext = [];
@ -37,13 +39,22 @@ internal class Av1TileDecoder : IAv1TileDecoder
// init_main_frame_ctxt
this.FrameBuffer = new(this.SequenceHeader);
}
public bool SequenceHeaderDone { get; set; }
public bool ShowExistingFrame { get; set; }
this.segmentIds = new int[this.FrameInfo.ModeInfoRowCount][];
for (int y = 0; y < this.FrameInfo.ModeInfoRowCount; y++)
{
this.segmentIds[y] = new int[this.FrameInfo.ModeInfoColumnCount];
}
public bool SeenFrameHeader { get; set; }
// reallocate_parse_context_memory
// Hard code number of threads to 1 for now.
int planesCount = sequenceHeader.ColorConfig.IsMonochrome ? 1 : Av1Constants.MaxPlanes;
int superblockColumnCount =
AlignPowerOfTwo(sequenceHeader.MaxFrameWidth, sequenceHeader.SuperBlockSizeLog2) >> sequenceHeader.SuperBlockSizeLog2;
int modeInfoWideColumnCount = superblockColumnCount * sequenceHeader.ModeInfoSize;
modeInfoWideColumnCount = AlignPowerOfTwo(modeInfoWideColumnCount, sequenceHeader.SuperBlockSizeLog2 - 2);
this.aboveNeighborContext = new Av1ParseAboveNeighbor4x4Context(planesCount, modeInfoWideColumnCount);
this.leftNeighborContext = new Av1ParseLeftNeighbor4x4Context(planesCount, sequenceHeader.ModeInfoSize);
}
public ObuFrameHeader FrameInfo { get; }
@ -57,7 +68,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
int tileColumnIndex = tileNum % this.FrameInfo.TilesInfo.TileColumnCount;
int tileRowIndex = tileNum / this.FrameInfo.TilesInfo.TileColumnCount;
this.aboveContext.Clear(this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex], this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex - 1]);
this.aboveContext.Clear(this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex], this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1]);
this.ClearLoopFilterDelta();
int planesCount = this.SequenceHeader.ColorConfig.IsMonochrome ? 1 : 3;
this.referenceSgrXqd = new int[planesCount][];
@ -74,6 +85,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
}
}
// TODO: Initialize this.blockDecoded and this.segmentIds
Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128SuperBlock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64;
int superBlock4x4Size = superBlockSize.Get4x4WideCount();
for (int row = this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex]; row < this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex + 1]; row += this.SequenceHeader.ModeInfoSize)
@ -83,38 +95,43 @@ internal class Av1TileDecoder : IAv1TileDecoder
for (int column = this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex]; column < this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1]; column += this.SequenceHeader.ModeInfoSize)
{
int superBlockColumn = column << Av1Constants.ModeInfoSizeLog2 >> this.SequenceHeader.SuperBlockSizeLog2;
bool subSamplingX = this.SequenceHeader.ColorConfig.SubSamplingX;
bool subSamplingY = this.SequenceHeader.ColorConfig.SubSamplingY;
// bool subSamplingX = this.SequenceHeader.ColorConfig.SubSamplingX;
// bool subSamplingY = this.SequenceHeader.ColorConfig.SubSamplingY;
bool readDeltas = this.FrameInfo.DeltaQParameters.IsPresent;
Av1TileLocation tileLoc = new(row, column, this.FrameInfo);
this.ClearBlockDecodedFlags(row, column, superBlock4x4Size);
Point superblockPosition = new Point(superBlockColumn, superBlockRow);
// this.ClearBlockDecodedFlags(row, column, superBlock4x4Size);
Point superblockPosition = new(superBlockColumn, superBlockRow);
Av1SuperblockInfo superblockInfo = new(this.FrameBuffer, superblockPosition);
// Nothing to do for CDEF
// this.ClearCdef(row, column);
// this.ReadLoopRestoration(row, column, superBlockSize);
this.ParsePartition(ref reader, row, column, superBlockSize, superblockInfo);
this.ParsePartition(ref reader, new Point(column, row), superBlockSize, superblockInfo, tileLoc);
}
}
}
private static int AlignPowerOfTwo(int value, int n) => (value + ((1 << n) - 1)) & ~((1 << n) - 1);
private void ClearLoopFilterDelta()
=> this.FrameBuffer.ClearDeltaLoopFilter();
private void ClearBlockDecodedFlags(int row, int column, int superBlock4x4Size)
{
int planesCount = this.SequenceHeader.ColorConfig.ChannelCount;
this.blockDecoded = new bool[planesCount][][];
for (int plane = 0; plane < planesCount; plane++)
{
int subX = plane > 0 && this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0;
int subY = plane > 0 && this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0;
int superBlock4x4Width = (this.FrameInfo.ModeInfoColumnCount - column) >> subX;
int superBlock4x4Height = (this.FrameInfo.ModeInfoRowCount - row) >> subY;
this.blockDecoded[plane] = new bool[superBlock4x4Size >> subY][];
for (int y = -1; y <= superBlock4x4Size >> subY; y++)
{
this.blockDecoded[plane][y] = new bool[superBlock4x4Size >> subX];
for (int x = -1; x <= superBlock4x4Size >> subX; x++)
{
if (y < 0 && x < superBlock4x4Width)
@ -160,10 +177,11 @@ internal class Av1TileDecoder : IAv1TileDecoder
// TODO: Implement
}
private void ParsePartition(ref Av1SymbolDecoder reader, int rowIndex, int columnIndex, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo)
private void ParsePartition(ref Av1SymbolDecoder reader, Point modeInfoLocation, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1TileLocation tileLoc)
{
if (rowIndex >= this.FrameInfo.TilesInfo.TileRowStartModeInfo[rowIndex] ||
columnIndex >= this.FrameInfo.TilesInfo.TileColumnStartModeInfo[columnIndex])
int columnIndex = modeInfoLocation.X;
int rowIndex = modeInfoLocation.Y;
if (modeInfoLocation.Y >= this.FrameInfo.ModeInfoRowCount || modeInfoLocation.X >= this.FrameInfo.ModeInfoColumnCount)
{
return;
}
@ -173,8 +191,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
int block4x4Size = blockSize.Get4x4WideCount();
int halfBlock4x4Size = block4x4Size >> 1;
int quarterBlock4x4Size = halfBlock4x4Size >> 2;
bool hasRows = (rowIndex + halfBlock4x4Size) < this.FrameInfo.ModeInfoRowCount;
bool hasColumns = (columnIndex + halfBlock4x4Size) < this.FrameInfo.ModeInfoColumnCount;
bool hasRows = (modeInfoLocation.Y + halfBlock4x4Size) < this.FrameInfo.ModeInfoRowCount;
bool hasColumns = (modeInfoLocation.X + halfBlock4x4Size) < this.FrameInfo.ModeInfoColumnCount;
Av1PartitionType partitionType = Av1PartitionType.Split;
if (blockSize < Av1BlockSize.Block8x8)
{
@ -182,18 +200,18 @@ internal class Av1TileDecoder : IAv1TileDecoder
}
else if (hasRows && hasColumns)
{
int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize);
int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileLoc, this.FrameInfo.ModeInfoRowCount);
partitionType = reader.ReadPartitionType(ctx);
}
else if (hasColumns)
{
int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize);
int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileLoc, this.FrameInfo.ModeInfoRowCount);
bool splitOrHorizontal = reader.ReadSplitOrHorizontal(blockSize, ctx);
partitionType = splitOrHorizontal ? Av1PartitionType.Split : Av1PartitionType.Horizontal;
}
else if (hasRows)
{
int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize);
int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileLoc, this.FrameInfo.ModeInfoRowCount);
bool splitOrVertical = reader.ReadSplitOrVertical(blockSize, ctx);
partitionType = splitOrVertical ? Av1PartitionType.Split : Av1PartitionType.Vertical;
}
@ -203,10 +221,13 @@ internal class Av1TileDecoder : IAv1TileDecoder
switch (partitionType)
{
case Av1PartitionType.Split:
this.ParsePartition(ref reader, rowIndex, columnIndex, subSize, superblockInfo);
this.ParsePartition(ref reader, rowIndex, columnIndex + halfBlock4x4Size, subSize, superblockInfo);
this.ParsePartition(ref reader, rowIndex + halfBlock4x4Size, columnIndex, subSize, superblockInfo);
this.ParsePartition(ref reader, rowIndex + halfBlock4x4Size, columnIndex + halfBlock4x4Size, subSize, superblockInfo);
Point loc1 = new Point(modeInfoLocation.X, modeInfoLocation.Y + halfBlock4x4Size);
Point loc2 = new Point(modeInfoLocation.X + halfBlock4x4Size, modeInfoLocation.Y);
Point loc3 = new Point(modeInfoLocation.X + halfBlock4x4Size, modeInfoLocation.Y + halfBlock4x4Size);
this.ParsePartition(ref reader, modeInfoLocation, subSize, superblockInfo, tileLoc);
this.ParsePartition(ref reader, loc1, subSize, superblockInfo, tileLoc);
this.ParsePartition(ref reader, loc2, subSize, superblockInfo, tileLoc);
this.ParsePartition(ref reader, loc3, subSize, superblockInfo, tileLoc);
break;
case Av1PartitionType.None:
this.ParseBlock(ref reader, rowIndex, columnIndex, subSize, superblockInfo, Av1PartitionType.None);
@ -276,6 +297,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
default:
throw new NotImplementedException($"Partition type: {partitionType} is not supported.");
}
this.UpdatePartitionContext(new Point(columnIndex, rowIndex), tileLoc, superblockInfo, subSize, blockSize, partitionType);
}
private void ParseBlock(ref Av1SymbolDecoder reader, int rowIndex, int columnIndex, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1PartitionType partitionType)
@ -338,10 +361,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
int txsHigh = planeBlockSize.GetHeight() >> 2;
int aboveOffset = (partitionInfo.ColumnIndex - this.FrameInfo.TilesInfo.TileColumnStartModeInfo[partitionInfo.ColumnIndex]) >> (subX ? 1 : 0);
int leftOffset = (partitionInfo.RowIndex - this.FrameInfo.TilesInfo.TileRowStartModeInfo[partitionInfo.RowIndex]) >> (subY ? 1 : 0);
int[] aboveContext = this.aboveContext.AboveContext[i + aboveOffset];
int[] leftContext = this.leftContext.LeftContext[i + leftOffset];
Array.Fill(aboveContext, 0);
Array.Fill(leftContext, 0);
this.aboveNeighborContext.ClearContext(i, aboveOffset, txsWide);
this.leftNeighborContext.ClearContext(i, leftOffset, txsHigh);
}
}
@ -697,16 +718,17 @@ internal class Av1TileDecoder : IAv1TileDecoder
this.ReadSegmentId(ref reader, partitionInfo);
}
int bw4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount();
int bh4 = partitionInfo.ModeInfo.BlockSize.Get4x4HighCount();
int x_mis = Math.Min(this.FrameInfo.ModeInfoColumnCount - partitionInfo.ColumnIndex, bw4);
int y_mis = Math.Min(this.FrameInfo.ModeInfoRowCount - partitionInfo.RowIndex, bh4);
for (int y = 0; y < y_mis; y++)
int blockWidth4x4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount();
int blockHeight4x4 = partitionInfo.ModeInfo.BlockSize.Get4x4HighCount();
int modeInfoCountX = Math.Min(this.FrameInfo.ModeInfoColumnCount - partitionInfo.ColumnIndex, blockWidth4x4);
int modeInfoCountY = Math.Min(this.FrameInfo.ModeInfoRowCount - partitionInfo.RowIndex, blockHeight4x4);
int segmentId = partitionInfo.ModeInfo.SegmentId;
for (int y = 0; y < modeInfoCountY; y++)
{
for (int x = 0; x < x_mis; x++)
int[] segmentRow = this.segmentIds[partitionInfo.RowIndex + y];
for (int x = 0; x < modeInfoCountX; x++)
{
this.segmentIds[partitionInfo.RowIndex + y][partitionInfo.ColumnIndex + x] = partitionInfo.ModeInfo.SegmentId;
segmentRow[partitionInfo.ColumnIndex + x] = segmentId;
}
}
}
@ -954,14 +976,72 @@ internal class Av1TileDecoder : IAv1TileDecoder
return xPos && yPos;
}*/
private int GetPartitionContext(int rowIndex, int columnIndex, Av1BlockSize blockSize)
private int GetPartitionContext(Point location, Av1BlockSize blockSize, Av1TileLocation tileLoc, int superblockModeInfoRowCount)
{
// Maximum partition point is 8x8. Offset the log value occordingly.
int aboveCtx = this.aboveNeighborContext.AbovePartitionWidth[location.X - tileLoc.ModeInfoColumnStart];
int leftCtx = this.leftNeighborContext.LeftPartitionHeight[(location.Y - superblockModeInfoRowCount) & Av1PartitionContext.Mask];
int blockSizeLog = blockSize.Get4x4WidthLog2() - Av1BlockSize.Block8x8.Get4x4WidthLog2();
int aboveCtx = this.aboveContext.PartitionWidth + columnIndex - this.FrameInfo.TilesInfo.TileColumnStartModeInfo[columnIndex];
int leftCtx = this.leftContext.PartitionHeight + rowIndex - this.FrameInfo.TilesInfo.TileRowStartModeInfo[rowIndex];
int above = (aboveCtx >> blockSizeLog) & 0x1;
int left = (leftCtx >> blockSizeLog) & 0x1;
return (left * 2) + above + (blockSizeLog * PartitionProbabilitySet);
}
private void UpdatePartitionContext(Point modeInfoLocation, Av1TileLocation tileLoc, Av1SuperblockInfo superblockInfo, Av1BlockSize subSize, Av1BlockSize blockSize, Av1PartitionType partition)
{
if (blockSize >= Av1BlockSize.Block8x8)
{
int hbs = blockSize.Get4x4WideCount() / 2;
Av1BlockSize blockSize2 = Av1PartitionType.Split.GetBlockSubSize(blockSize);
switch (partition)
{
case Av1PartitionType.Split:
if (blockSize != Av1BlockSize.Block8x8)
{
break;
}
goto PARTITIONS;
case Av1PartitionType.None:
case Av1PartitionType.Horizontal:
case Av1PartitionType.Vertical:
case Av1PartitionType.Horizontal4:
case Av1PartitionType.Vertical4:
PARTITIONS:
this.aboveNeighborContext.UpdatePartition(modeInfoLocation, tileLoc, subSize, blockSize);
this.leftNeighborContext.UpdatePartition(modeInfoLocation, superblockInfo, subSize, blockSize);
break;
case Av1PartitionType.HorizontalA:
this.aboveNeighborContext.UpdatePartition(modeInfoLocation, tileLoc, blockSize2, subSize);
this.leftNeighborContext.UpdatePartition(modeInfoLocation, superblockInfo, blockSize2, subSize);
Point locHorizontalA = new(modeInfoLocation.X, modeInfoLocation.Y + hbs);
this.aboveNeighborContext.UpdatePartition(locHorizontalA, tileLoc, subSize, subSize);
this.leftNeighborContext.UpdatePartition(locHorizontalA, superblockInfo, subSize, subSize);
break;
case Av1PartitionType.HorizontalB:
this.aboveNeighborContext.UpdatePartition(modeInfoLocation, tileLoc, subSize, subSize);
this.leftNeighborContext.UpdatePartition(modeInfoLocation, superblockInfo, subSize, subSize);
Point locHorizontalB = new(modeInfoLocation.X, modeInfoLocation.Y + hbs);
this.aboveNeighborContext.UpdatePartition(locHorizontalB, tileLoc, blockSize2, subSize);
this.leftNeighborContext.UpdatePartition(locHorizontalB, superblockInfo, blockSize2, subSize);
break;
case Av1PartitionType.VerticalA:
this.aboveNeighborContext.UpdatePartition(modeInfoLocation, tileLoc, blockSize2, subSize);
this.leftNeighborContext.UpdatePartition(modeInfoLocation, superblockInfo, blockSize2, subSize);
Point locVerticalA = new(modeInfoLocation.X + hbs, modeInfoLocation.Y);
this.aboveNeighborContext.UpdatePartition(locVerticalA, tileLoc, subSize, subSize);
this.leftNeighborContext.UpdatePartition(locVerticalA, superblockInfo, subSize, subSize);
break;
case Av1PartitionType.VerticalB:
this.aboveNeighborContext.UpdatePartition(modeInfoLocation, tileLoc, subSize, subSize);
this.leftNeighborContext.UpdatePartition(modeInfoLocation, superblockInfo, subSize, subSize);
Point locVerticalB = new(modeInfoLocation.X, modeInfoLocation.Y + hbs);
this.aboveNeighborContext.UpdatePartition(locVerticalB, tileLoc, blockSize2, subSize);
this.leftNeighborContext.UpdatePartition(locVerticalB, superblockInfo, blockSize2, subSize);
break;
default:
throw new InvalidImageContentException($"Unknown partition type: {partition}");
}
}
}
}

45
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileLocation.cs

@ -0,0 +1,45 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal class Av1TileLocation
{
public Av1TileLocation(int row, int column, ObuFrameHeader frameInfo)
{
this.SetTileRow(frameInfo.TilesInfo, frameInfo.ModeInfoRowCount, row);
this.SetTileColumn(frameInfo.TilesInfo, frameInfo.ModeInfoColumnCount, column);
}
public int ModeInfoRowStart { get; private set; }
public int ModeInfoRowEnd { get; private set; }
public int ModeInfoColumnStart { get; private set; }
public int ModeInfoColumnEnd { get; private set; }
public Point TileIndex { get; private set; }
public int TileIndexInRasterOrder { get; }
public void SetTileRow(ObuTileGroupHeader tileGroupHeader, int modeInfoRowCount, int row)
{
this.ModeInfoRowStart = tileGroupHeader.TileRowStartModeInfo[row];
this.ModeInfoRowEnd = Math.Min(tileGroupHeader.TileRowStartModeInfo[row + 1], modeInfoRowCount);
Point loc = this.TileIndex;
loc.Y = row;
this.TileIndex = loc;
}
public void SetTileColumn(ObuTileGroupHeader tileGroupHeader, int modeInfoColumnCount, int column)
{
this.ModeInfoColumnStart = tileGroupHeader.TileColumnStartModeInfo[column];
this.ModeInfoColumnEnd = Math.Min(tileGroupHeader.TileColumnStartModeInfo[column + 1], modeInfoColumnCount);
Point loc = this.TileIndex;
loc.X = column;
this.TileIndex = loc;
}
}
Loading…
Cancel
Save