mirror of https://github.com/SixLabors/ImageSharp
6 changed files with 473 additions and 194 deletions
@ -0,0 +1,191 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; |
|||
|
|||
/// <summary>
|
|||
/// Determines whether extended intra-prediction references have already been reconstructed.
|
|||
/// </summary>
|
|||
internal static class Av1IntraReferenceAvailability |
|||
{ |
|||
/// <summary>
|
|||
/// Determines whether every bottom-left reference sample required by a transform is already reconstructed.
|
|||
/// </summary>
|
|||
/// <param name="superblockSize">The sequence superblock size.</param>
|
|||
/// <param name="blockSize">The containing block size in the current plane's geometry.</param>
|
|||
/// <param name="modeInfoRow">The containing block row in 4-by-4 mode-information units.</param>
|
|||
/// <param name="modeInfoColumn">The containing block column in 4-by-4 mode-information units.</param>
|
|||
/// <param name="bottomAvailable">A value indicating whether the required rows remain inside the frame and tile.</param>
|
|||
/// <param name="haveLeft">A value indicating whether reconstructed samples exist immediately to the left.</param>
|
|||
/// <param name="partition">The partition type that determines reconstruction order.</param>
|
|||
/// <param name="transformSize">The transform size whose extended edge is required.</param>
|
|||
/// <param name="blockModeInfoRowOffset">The transform row offset within the containing block.</param>
|
|||
/// <param name="blockModeInfoColumnOffset">The transform column offset within the containing block.</param>
|
|||
/// <param name="subX">The horizontal chroma subsampling shift.</param>
|
|||
/// <param name="subY">The vertical chroma subsampling shift.</param>
|
|||
/// <returns><see langword="true"/> when the bottom-left reference extension is available; otherwise, <see langword="false"/>.</returns>
|
|||
public static bool HasBottomLeft(Av1BlockSize superblockSize, Av1BlockSize blockSize, int modeInfoRow, int modeInfoColumn, bool bottomAvailable, bool haveLeft, Av1PartitionType partition, Av1TransformSize transformSize, int blockModeInfoRowOffset, int blockModeInfoColumnOffset, int subX, int subY) |
|||
{ |
|||
if (!bottomAvailable || !haveLeft) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// A 128-wide block is reconstructed as two 64-wide regions in raster order,
|
|||
// so the right half can consume references that already belong to the left half.
|
|||
if (blockSize.GetWidth() > 64 && blockModeInfoColumnOffset > 0) |
|||
{ |
|||
int block64WidthInUnits = Av1BlockSize.Block64x64.Get4x4WideCount(); |
|||
int planeBlockWidthInUnits64 = block64WidthInUnits >> subX; |
|||
int columnOffset64 = blockModeInfoColumnOffset % planeBlockWidthInUnits64; |
|||
if (columnOffset64 == 0) |
|||
{ |
|||
// We are at the left edge of top-right or bottom-right 64x* block.
|
|||
int block64HeightInUnits = Av1BlockSize.Block64x64.Get4x4HighCount(); |
|||
int planeBlockHeightInUnits64 = block64HeightInUnits >> subY; |
|||
int rowOffset64 = blockModeInfoRowOffset % planeBlockHeightInUnits64; |
|||
int planeBlockHeightInUnits = Math.Min(blockSize.Get4x4HighCount() >> subY, planeBlockHeightInUnits64); |
|||
|
|||
// Check if all bottom-left pixels are in the left 64x* block (which is
|
|||
// already coded).
|
|||
return rowOffset64 + transformSize.Get4x4HighCount() < planeBlockHeightInUnits; |
|||
} |
|||
} |
|||
|
|||
if (blockModeInfoColumnOffset > 0) |
|||
{ |
|||
// Bottom-left pixels are in the bottom-left block, which is not available.
|
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
int blockHeightInUnits = blockSize.GetHeight() >> Av1TransformSize.Size4x4.GetBlockHeightLog2(); |
|||
int planeBlockHeightInUnits = Math.Max(blockHeightInUnits >> subY, 1); |
|||
int bottomLeftUnitCount = transformSize.Get4x4HighCount(); |
|||
|
|||
// All bottom-left pixels are in the left block, which is already available.
|
|||
if (blockModeInfoRowOffset + bottomLeftUnitCount < planeBlockHeightInUnits) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
int blockWidthInModeInfoLog2 = blockSize.Get4x4WidthLog2(); |
|||
int blockHeightInModeInfoLog2 = blockSize.Get4x4HeightLog2(); |
|||
int superblockModeInfoSize = superblockSize.Get4x4HighCount(); |
|||
int blockRowInSuperblock = (modeInfoRow & (superblockModeInfoSize - 1)) >> blockHeightInModeInfoLog2; |
|||
int blockColumnInSuperblock = (modeInfoColumn & (superblockModeInfoSize - 1)) >> blockWidthInModeInfoLog2; |
|||
|
|||
// Leftmost column of superblock: so bottom-left pixels maybe in the left
|
|||
// and/or bottom-left superblocks. But only the left superblock is
|
|||
// available, so check if all required pixels fall in that superblock.
|
|||
if (blockColumnInSuperblock == 0) |
|||
{ |
|||
int blockStartRowOffset = blockRowInSuperblock << (blockHeightInModeInfoLog2 + Av1Constants.ModeInfoSizeLog2 - Av1TransformSize.Size4x4.GetBlockWidthLog2()) >> subY; |
|||
int rowOffsetInSuperblock = blockStartRowOffset + blockModeInfoRowOffset; |
|||
int superblockHeightInUnits = superblockModeInfoSize >> subY; |
|||
return rowOffsetInSuperblock + bottomLeftUnitCount < superblockHeightInUnits; |
|||
} |
|||
|
|||
// Bottom row of superblock (and not the leftmost column): so bottom-left
|
|||
// pixels fall in the bottom superblock, which is not available yet.
|
|||
if (((blockRowInSuperblock + 1) << blockHeightInModeInfoLog2) >= superblockModeInfoSize) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// General case (neither leftmost column nor bottom row): check if the
|
|||
// bottom-left block is coded before the current block.
|
|||
int thisBlockIndex = ((blockRowInSuperblock + 0) << (Av1Constants.MaxSuperBlockSizeLog2 - Av1Constants.ModeInfoSizeLog2 - blockWidthInModeInfoLog2)) + blockColumnInSuperblock + 0; |
|||
return Av1BottomRightTopLeftConstants.HasBottomLeft(partition, blockSize, thisBlockIndex); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines whether every top-right reference sample required by a transform is already reconstructed.
|
|||
/// </summary>
|
|||
/// <param name="superblockSize">The sequence superblock size.</param>
|
|||
/// <param name="blockSize">The containing block size in the current plane's geometry.</param>
|
|||
/// <param name="modeInfoRow">The containing block row in 4-by-4 mode-information units.</param>
|
|||
/// <param name="modeInfoColumn">The containing block column in 4-by-4 mode-information units.</param>
|
|||
/// <param name="haveTop">A value indicating whether reconstructed samples exist immediately above.</param>
|
|||
/// <param name="rightAvailable">A value indicating whether the required columns remain inside the frame and tile.</param>
|
|||
/// <param name="partition">The partition type that determines reconstruction order.</param>
|
|||
/// <param name="transformSize">The transform size whose extended edge is required.</param>
|
|||
/// <param name="blockModeInfoRowOffset">The transform row offset within the containing block.</param>
|
|||
/// <param name="blockModeInfoColumnOffset">The transform column offset within the containing block.</param>
|
|||
/// <param name="subX">The horizontal chroma subsampling shift.</param>
|
|||
/// <param name="subY">The vertical chroma subsampling shift.</param>
|
|||
/// <returns><see langword="true"/> when the top-right reference extension is available; otherwise, <see langword="false"/>.</returns>
|
|||
public static bool HasTopRight(Av1BlockSize superblockSize, Av1BlockSize blockSize, int modeInfoRow, int modeInfoColumn, bool haveTop, bool rightAvailable, Av1PartitionType partition, Av1TransformSize transformSize, int blockModeInfoRowOffset, int blockModeInfoColumnOffset, int subX, int subY) |
|||
{ |
|||
if (!haveTop || !rightAvailable) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
int blockWideInUnits = blockSize.GetWidth() >> 2; |
|||
int planeBlockWidthInUnits = Math.Max(blockWideInUnits >> subX, 1); |
|||
int topRightUnitCount = transformSize.Get4x4WideCount(); |
|||
|
|||
if (blockModeInfoRowOffset > 0) |
|||
{ |
|||
// Transforms below the first row obtain their top edge from the containing block,
|
|||
// so only the reconstructed width to their right constrains availability.
|
|||
if (blockSize.GetWidth() > 64) |
|||
{ |
|||
// Special case: For 128x128 blocks, the transform unit whose
|
|||
// top-right corner is at the center of the block does in fact have
|
|||
// pixels available at its top-right corner.
|
|||
int block64WidthInUnits = Av1BlockSize.Block64x64.Get4x4WideCount(); |
|||
int block64HeightInUnits = Av1BlockSize.Block64x64.Get4x4HighCount(); |
|||
if (blockModeInfoRowOffset == block64HeightInUnits >> subY && |
|||
blockModeInfoColumnOffset + topRightUnitCount == block64WidthInUnits >> subX) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
int planeBlockWidthInUnits64 = block64WidthInUnits >> subX; |
|||
int blockModeInfoColumnOffset64 = blockModeInfoColumnOffset % planeBlockWidthInUnits64; |
|||
return blockModeInfoColumnOffset64 + topRightUnitCount < planeBlockWidthInUnits64; |
|||
} |
|||
|
|||
return blockModeInfoColumnOffset + topRightUnitCount < planeBlockWidthInUnits; |
|||
} |
|||
else |
|||
{ |
|||
// All top-right pixels are in the block above, which is already available.
|
|||
if (blockModeInfoColumnOffset + topRightUnitCount < planeBlockWidthInUnits) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
int blockWidthInModeInfoLog2 = blockSize.Get4x4WidthLog2(); |
|||
int blockHeightInModeInfeLog2 = blockSize.Get4x4HeightLog2(); |
|||
int superBlockModeInfoSize = superblockSize.Get4x4HighCount(); |
|||
int blockRowInSuperblock = (modeInfoRow & (superBlockModeInfoSize - 1)) >> blockHeightInModeInfeLog2; |
|||
int blockColumnInSuperBlock = (modeInfoColumn & (superBlockModeInfoSize - 1)) >> blockWidthInModeInfoLog2; |
|||
|
|||
// Top row of superblock: so top-right pixels are in the top and/or
|
|||
// top-right superblocks, both of which are already available.
|
|||
if (blockRowInSuperblock == 0) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
// Rightmost column of superblock (and not the top row): so top-right pixels
|
|||
// fall in the right superblock, which is not available yet.
|
|||
if (((blockColumnInSuperBlock + 1) << blockWidthInModeInfoLog2) >= superBlockModeInfoSize) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// General case (neither top row nor rightmost column): check if the
|
|||
// top-right block is coded before the current block.
|
|||
int thisBlockIndex = ((blockRowInSuperblock + 0) << (Av1Constants.MaxSuperBlockSizeLog2 - Av1Constants.ModeInfoSizeLog2 - blockWidthInModeInfoLog2)) + blockColumnInSuperBlock + 0; |
|||
return Av1BottomRightTopLeftConstants.HasTopRight(partition, blockSize, thisBlockIndex); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue