mirror of https://github.com/SixLabors/ImageSharp
3 changed files with 163 additions and 67 deletions
@ -0,0 +1,137 @@ |
|||
// 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 Av1FrameBuffer |
|||
{ |
|||
// Number of Coefficients in a single ModeInfo 4x4 block of pixels (1 length + 4 x 4).
|
|||
public const int CoefficientCountPerModeInfo = 1 + 16; |
|||
|
|||
private readonly int[] coefficientsY = []; |
|||
private readonly int[] coefficientsU = []; |
|||
private readonly int[] coefficientsV = []; |
|||
private readonly int modeInfoSizePerSuperblock; |
|||
private readonly int modeInfoCountPerSuperblock; |
|||
private readonly int superblockColumnCount; |
|||
private readonly int superblockRowCount; |
|||
private readonly int subsamplingFactor; |
|||
private readonly Av1SuperblockInfo[] superblockInfos; |
|||
private readonly Av1BlockModeInfo[] modeInfos; |
|||
private readonly Av1TransformInfo[] transformInfosY; |
|||
private readonly Av1TransformInfo[] transformInfosUv; |
|||
private readonly int[] deltaQ; |
|||
private readonly int cdefStrengthFactorLog2; |
|||
private readonly int[] cdefStrength; |
|||
private readonly int deltaLoopFactorLog2 = 2; |
|||
private readonly int[] deltaLoopFilter; |
|||
|
|||
public Av1FrameBuffer(ObuSequenceHeader sequenceHeader) |
|||
{ |
|||
// init_main_frame_ctxt
|
|||
int superblockSizeLog2 = sequenceHeader.SuperBlockSizeLog2; |
|||
int superblockAlignedWidth = Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameWidth, superblockSizeLog2); |
|||
int superblockAlignedHeight = Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameHeight, superblockSizeLog2); |
|||
this.superblockColumnCount = superblockAlignedWidth >> superblockSizeLog2; |
|||
this.superblockRowCount = superblockAlignedHeight >> superblockSizeLog2; |
|||
int superblockCount = this.superblockColumnCount * this.superblockRowCount; |
|||
this.modeInfoSizePerSuperblock = 1 << (superblockSizeLog2 - Av1Constants.ModeInfoSizeLog2); |
|||
this.modeInfoCountPerSuperblock = this.modeInfoSizePerSuperblock * this.modeInfoSizePerSuperblock; |
|||
this.superblockInfos = new Av1SuperblockInfo[superblockCount]; |
|||
this.modeInfos = new Av1BlockModeInfo[superblockCount * this.modeInfoCountPerSuperblock]; |
|||
this.transformInfosY = new Av1TransformInfo[superblockCount * this.modeInfoCountPerSuperblock]; |
|||
this.transformInfosUv = new Av1TransformInfo[2 * superblockCount * this.modeInfoCountPerSuperblock]; |
|||
this.coefficientsY = new int[superblockCount * this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo]; |
|||
bool subX = sequenceHeader.ColorConfig.SubSamplingX; |
|||
bool subY = sequenceHeader.ColorConfig.SubSamplingY; |
|||
|
|||
// Factor: 444 => 0, 422 => 1, 420 => 2.
|
|||
this.subsamplingFactor = (subX && subY) ? 2 : (subX && !subY) ? 1 : (!subX && !subY) ? 0 : -1; |
|||
Guard.IsFalse(this.subsamplingFactor == -1, nameof(this.subsamplingFactor), "Invalid combination of subsampling."); |
|||
this.coefficientsU = new int[(this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo) >> this.subsamplingFactor]; |
|||
this.coefficientsV = new int[(this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo) >> this.subsamplingFactor]; |
|||
this.deltaQ = new int[superblockCount]; |
|||
|
|||
// Superblock size: 128x128 has sizelog2 = 7, 64x64 = 6. Factor should be 128x128 => 4 and 64x64 => 1.
|
|||
this.cdefStrengthFactorLog2 = (superblockSizeLog2 - 6) << 2; |
|||
this.cdefStrength = new int[superblockCount << this.cdefStrengthFactorLog2]; |
|||
Array.Fill(this.cdefStrength, -1); |
|||
this.deltaLoopFilter = new int[superblockCount << this.deltaLoopFactorLog2]; |
|||
} |
|||
|
|||
public Av1SuperblockInfo GetSuperblock(Point index) |
|||
{ |
|||
Span<Av1SuperblockInfo> span = this.superblockInfos; |
|||
int i = (index.Y * this.superblockColumnCount) + index.X; |
|||
return span[i]; |
|||
} |
|||
|
|||
public Av1BlockModeInfo GetModeInfo(Point superblockIndex, Point modeInfoIndex) |
|||
{ |
|||
Span<Av1BlockModeInfo> span = this.modeInfos; |
|||
int baseIndex = ((superblockIndex.Y * this.superblockColumnCount) + superblockIndex.X) * this.modeInfoCountPerSuperblock; |
|||
int offset = (modeInfoIndex.Y * this.modeInfoSizePerSuperblock) + modeInfoIndex.X; |
|||
return span[baseIndex + offset]; |
|||
} |
|||
|
|||
public Av1TransformInfo GetTransformY(Point index) |
|||
{ |
|||
Span<Av1TransformInfo> span = this.transformInfosY; |
|||
int i = (index.Y * this.superblockColumnCount) + index.X; |
|||
return span[i * this.modeInfoCountPerSuperblock]; |
|||
} |
|||
|
|||
public void GetTransformUv(Point index, out Av1TransformInfo transformU, out Av1TransformInfo transformV) |
|||
{ |
|||
Span<Av1TransformInfo> span = this.transformInfosUv; |
|||
int i = 2 * ((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock; |
|||
transformU = span[i]; |
|||
transformV = span[i + 1]; |
|||
} |
|||
|
|||
public Span<int> GetCoefficientsY(Point index) |
|||
{ |
|||
Span<int> span = this.coefficientsY; |
|||
int i = ((index.Y * this.modeInfoCountPerSuperblock) + index.X) * CoefficientCountPerModeInfo; |
|||
return span.Slice(i, CoefficientCountPerModeInfo); |
|||
} |
|||
|
|||
public Span<int> GetCoefficientsU(Point index) |
|||
{ |
|||
Span<int> span = this.coefficientsU; |
|||
int i = ((index.Y * this.modeInfoCountPerSuperblock) + index.X) * CoefficientCountPerModeInfo; |
|||
return span.Slice(i >> this.subsamplingFactor, CoefficientCountPerModeInfo); |
|||
} |
|||
|
|||
public Span<int> GetCoefficientsV(Point index) |
|||
{ |
|||
Span<int> span = this.coefficientsV; |
|||
int i = ((index.Y * this.modeInfoCountPerSuperblock) + index.X) * CoefficientCountPerModeInfo; |
|||
return span.Slice(i >> this.subsamplingFactor, CoefficientCountPerModeInfo); |
|||
} |
|||
|
|||
public ref int GetDeltaQuantizationIndex(Point index) |
|||
{ |
|||
Span<int> span = this.deltaQ; |
|||
int i = (index.Y * this.superblockColumnCount) + index.X; |
|||
return ref span[i]; |
|||
} |
|||
|
|||
public Span<int> GetCdefStrength(Point index) |
|||
{ |
|||
Span<int> span = this.cdefStrength; |
|||
int i = ((index.Y * this.superblockColumnCount) + index.X) << this.cdefStrengthFactorLog2; |
|||
return span.Slice(i, 1 << this.cdefStrengthFactorLog2); |
|||
} |
|||
|
|||
public Span<int> GetDeltaLoopFilter(Point index) |
|||
{ |
|||
Span<int> span = this.deltaLoopFilter; |
|||
int i = ((index.Y * this.superblockColumnCount) + index.X) << this.deltaLoopFactorLog2; |
|||
return span.Slice(i, 1 << this.deltaLoopFactorLog2); |
|||
} |
|||
|
|||
internal void ClearDeltaLoopFilter() => Array.Fill(this.deltaLoopFilter, 0); |
|||
} |
|||
Loading…
Reference in new issue