Browse Source

Introduce Av1FrameBuffer class and renaming others

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
0ff8911047
  1. 17
      src/ImageSharp/Formats/Heif/Av1/Av1BlockModeInfo.cs
  2. 6
      src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs
  3. 188
      src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs
  4. 252
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
  5. 88
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuWriter.cs
  6. 2
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockModeInfo.cs
  7. 27
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameInfo.cs
  8. 4
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameModeInfoMap.cs
  9. 6
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionInfo.cs
  10. 26
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs
  11. 6
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileInfo.cs
  12. 172
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs
  13. 8
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1FrameDecoder.cs
  14. 1
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseQuantizer.cs

17
src/ImageSharp/Formats/Heif/Av1/Av1BlockModeInfo.cs

@ -1,17 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal class Av1BlockModeInfo
{
public Av1BlockSize BlockSize { get; }
public Av1PredictionMode PredictionMode { get; }
public Av1PartitionType Partition { get; set; }
public int SegmentId { get; }
}

6
src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs

@ -19,7 +19,7 @@ internal class Av1Decoder : IAv1TileReader
public ObuSequenceHeader? SequenceHeader { get; private set; } public ObuSequenceHeader? SequenceHeader { get; private set; }
public Av1FrameBuffer? FrameBuffer { get; private set; } public Av1FrameInfo? FrameInfo { get; private set; }
public void Decode(Span<byte> buffer) public void Decode(Span<byte> buffer)
{ {
@ -29,8 +29,8 @@ internal class Av1Decoder : IAv1TileReader
Guard.NotNull(this.SequenceHeader, nameof(this.SequenceHeader)); Guard.NotNull(this.SequenceHeader, nameof(this.SequenceHeader));
Guard.NotNull(this.FrameHeader, nameof(this.FrameHeader)); Guard.NotNull(this.FrameHeader, nameof(this.FrameHeader));
this.FrameBuffer = this.tileReader.FrameBuffer; this.FrameInfo = this.tileReader.FrameInfo;
this.frameDecoder = new(this.SequenceHeader, this.FrameHeader, this.FrameBuffer); this.frameDecoder = new(this.SequenceHeader, this.FrameHeader, this.FrameInfo);
this.frameDecoder.DecodeFrame(); this.frameDecoder.DecodeFrame();
} }

188
src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs

@ -0,0 +1,188 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
/// <summary>
/// Buffer for the pixels of a single frame.
/// </summary>
internal class Av1FrameBuffer : IDisposable
{
private const int DecoderPaddingValue = 72;
private const int PictureBufferYFlag = 1 << 0;
private const int PictureBufferCbFlag = 1 << 1;
private const int PictureBufferCrFlag = 1 << 2;
private const int PictureBufferLumaMask = PictureBufferYFlag;
private const int PictureBufferFullMask = PictureBufferYFlag | PictureBufferCbFlag | PictureBufferCrFlag;
public Av1FrameBuffer(Configuration configuration, ObuSequenceHeader sequenceHeader, Av1ColorFormat maxColorFormat, bool is16BitPipeline)
{
Av1ColorFormat colorFormat = sequenceHeader.ColorConfig.IsMonochrome ? Av1ColorFormat.Yuv400 : maxColorFormat;
this.MaxWidth = sequenceHeader.MaxFrameWidth;
this.MaxHeight = sequenceHeader.MaxFrameHeight;
this.BitDepth = (Av1BitDepth)sequenceHeader.ColorConfig.BitDepth;
int bitsPerPixel = this.BitDepth > Av1BitDepth.EightBit || is16BitPipeline ? 2 : 1;
this.ColorFormat = colorFormat;
this.BufferEnableMask = sequenceHeader.ColorConfig.IsMonochrome ? PictureBufferLumaMask : PictureBufferFullMask;
int leftPadding = DecoderPaddingValue;
int rightPadding = DecoderPaddingValue;
int topPadding = DecoderPaddingValue;
int bottomPadding = DecoderPaddingValue;
this.Width = this.MaxWidth;
this.Height = this.MaxHeight;
int strideY = this.MaxWidth + leftPadding + rightPadding;
int heightY = this.MaxHeight + topPadding + bottomPadding;
this.OriginX = leftPadding;
this.OriginY = topPadding;
this.OriginOriginY = bottomPadding;
int strideChroma = 0;
int heightChroma = 0;
switch (this.ColorFormat)
{
case Av1ColorFormat.Yuv420:
strideChroma = (strideY + 1) >> 1;
heightChroma = (this.Height + 1) >> 1;
break;
case Av1ColorFormat.Yuv422:
strideChroma = (strideY + 1) >> 1;
heightChroma = this.Height;
break;
case Av1ColorFormat.Yuv444:
strideChroma = strideY;
heightChroma = this.Height;
break;
}
this.PackedFlag = false;
this.BufferY = null;
this.BufferCb = null;
this.BufferCr = null;
if ((this.BufferEnableMask & PictureBufferYFlag) != 0)
{
this.BufferY = configuration.MemoryAllocator.Allocate2D<byte>(strideY * bitsPerPixel, heightY);
}
if ((this.BufferEnableMask & PictureBufferCbFlag) != 0)
{
this.BufferCb = configuration.MemoryAllocator.Allocate2D<byte>(strideChroma * bitsPerPixel, heightChroma);
}
if ((this.BufferEnableMask & PictureBufferCrFlag) != 0)
{
this.BufferCr = configuration.MemoryAllocator.Allocate2D<byte>(strideChroma * bitsPerPixel, heightChroma);
}
this.BitIncrementY = null;
this.BitIncrementCb = null;
this.BitIncrementCr = null;
this.BitIncrementY = null;
this.BitIncrementCb = null;
this.BitIncrementCr = null;
}
/// <summary>
/// Gets the Y luma buffer.
/// </summary>
public Buffer2D<byte>? BufferY { get; private set; }
/// <summary>
/// Gets the U chroma buffer.
/// </summary>
public Buffer2D<byte>? BufferCb { get; private set; }
/// <summary>
/// Gets the V chroma buffer.
/// </summary>
public Buffer2D<byte>? BufferCr { get; private set; }
public Buffer2D<byte>? BitIncrementY { get; private set; }
public Buffer2D<byte>? BitIncrementCb { get; private set; }
public Buffer2D<byte>? BitIncrementCr { get; private set; }
/// <summary>
/// Gets or sets the horizontal padding distance.
/// </summary>
public int OriginX { get; set; }
/// <summary>
/// Gets or sets the vertical padding distance.
/// </summary>
public int OriginY { get; set; }
/// <summary>
/// Gets or sets the vertical bottom padding distance
/// </summary>
public int OriginOriginY { get; set; }
/// <summary>
/// Gets or sets the Luma picture width, which excludes the padding.
/// </summary>
public int Width { get; set; }
/// <summary>
/// Gets or sets the Luma picture height, which excludes the padding.
/// </summary>
public int Height { get; set; }
/// <summary>
/// Gets or sets the Lume picture width.
/// </summary>
public int MaxWidth { get; set; }
/// <summary>
/// Gets or sets the pixel bit depth.
/// </summary>
public Av1BitDepth BitDepth { get; set; }
/// <summary>
/// Gets or sets the chroma subsampling.
/// </summary>
public Av1ColorFormat ColorFormat { get; set; }
/// <summary>
/// Gets or sets the Luma picture height.
/// </summary>
public int MaxHeight { get; set; }
public int LumaSize { get; }
public int ChromaSize { get; }
/// <summary>
/// Gets or sets a value indicating whether the bytes of the buffers are packed.
/// </summary>
public bool PackedFlag { get; set; }
/// <summary>
/// Gets or sets a value indicating whether film grain parameters are present for this frame.
/// </summary>
public bool FilmGrainFlag { get; set; }
public int BufferEnableMask { get; set; }
public bool Is16BitPipeline { get; set; }
public void Dispose()
{
this.BufferY?.Dispose();
this.BufferY = null;
this.BufferCb?.Dispose();
this.BufferCb = null;
this.BufferCr?.Dispose();
this.BufferCr = null;
this.BitIncrementY?.Dispose();
this.BitIncrementY = null;
this.BitIncrementCb?.Dispose();
this.BitIncrementCb = null;
this.BitIncrementCr?.Dispose();
this.BitIncrementCr = null;
}
}

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

@ -241,10 +241,10 @@ internal class ObuReader
private void ComputeImageSize(ObuSequenceHeader sequenceHeader) private void ComputeImageSize(ObuSequenceHeader sequenceHeader)
{ {
ObuFrameHeader frameInfo = this.FrameHeader!; ObuFrameHeader frameHeader = this.FrameHeader!;
frameInfo.ModeInfoColumnCount = 2 * ((frameInfo.FrameSize.FrameWidth + 7) >> 3); frameHeader.ModeInfoColumnCount = 2 * ((frameHeader.FrameSize.FrameWidth + 7) >> 3);
frameInfo.ModeInfoRowCount = 2 * ((frameInfo.FrameSize.FrameHeight + 7) >> 3); frameHeader.ModeInfoRowCount = 2 * ((frameHeader.FrameSize.FrameHeight + 7) >> 3);
frameInfo.ModeInfoStride = Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameWidth, Av1Constants.MaxSuperBlockSizeLog2) >> Av1Constants.ModeInfoSizeLog2; frameHeader.ModeInfoStride = Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameWidth, Av1Constants.MaxSuperBlockSizeLog2) >> Av1Constants.ModeInfoSizeLog2;
} }
/// <summary> /// <summary>
@ -582,7 +582,7 @@ internal class ObuReader
private void ReadSuperResolutionParameters(ref Av1BitStreamReader reader) private void ReadSuperResolutionParameters(ref Av1BitStreamReader reader)
{ {
ObuSequenceHeader sequenceHeader = this.SequenceHeader!; ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!; ObuFrameHeader frameHeader = this.FrameHeader!;
bool useSuperResolution = false; bool useSuperResolution = false;
if (sequenceHeader.EnableSuperResolution) if (sequenceHeader.EnableSuperResolution)
{ {
@ -591,24 +591,24 @@ internal class ObuReader
if (useSuperResolution) if (useSuperResolution)
{ {
frameInfo.FrameSize.SuperResolutionDenominator = (int)reader.ReadLiteral(Av1Constants.SuperResolutionScaleBits) + Av1Constants.SuperResolutionScaleDenominatorMinimum; frameHeader.FrameSize.SuperResolutionDenominator = (int)reader.ReadLiteral(Av1Constants.SuperResolutionScaleBits) + Av1Constants.SuperResolutionScaleDenominatorMinimum;
} }
else else
{ {
frameInfo.FrameSize.SuperResolutionDenominator = Av1Constants.ScaleNumerator; frameHeader.FrameSize.SuperResolutionDenominator = Av1Constants.ScaleNumerator;
} }
frameInfo.FrameSize.SuperResolutionUpscaledWidth = frameInfo.FrameSize.FrameWidth; frameHeader.FrameSize.SuperResolutionUpscaledWidth = frameHeader.FrameSize.FrameWidth;
frameInfo.FrameSize.FrameWidth = frameHeader.FrameSize.FrameWidth =
((frameInfo.FrameSize.SuperResolutionUpscaledWidth * Av1Constants.ScaleNumerator) + ((frameHeader.FrameSize.SuperResolutionUpscaledWidth * Av1Constants.ScaleNumerator) +
(frameInfo.FrameSize.SuperResolutionDenominator / 2)) / (frameHeader.FrameSize.SuperResolutionDenominator / 2)) /
frameInfo.FrameSize.SuperResolutionDenominator; frameHeader.FrameSize.SuperResolutionDenominator;
/* /*
if (frameInfo.FrameSize.SuperResolutionDenominator != Av1Constants.ScaleNumerator) if (frameHeader.FrameSize.SuperResolutionDenominator != Av1Constants.ScaleNumerator)
{ {
int manWidth = Math.Min(16, frameInfo.FrameSize.SuperResolutionUpscaledWidth); int manWidth = Math.Min(16, frameHeader.FrameSize.SuperResolutionUpscaledWidth);
frameInfo.FrameSize.FrameWidth = Math.Max(manWidth, frameInfo.FrameSize.FrameWidth); frameHeader.FrameSize.FrameWidth = Math.Max(manWidth, frameHeader.FrameSize.FrameWidth);
} }
*/ */
} }
@ -618,17 +618,17 @@ internal class ObuReader
/// </summary> /// </summary>
private void ReadRenderSize(ref Av1BitStreamReader reader) private void ReadRenderSize(ref Av1BitStreamReader reader)
{ {
ObuFrameHeader frameInfo = this.FrameHeader!; ObuFrameHeader frameHeader = this.FrameHeader!;
bool renderSizeAndFrameSizeDifferent = reader.ReadBoolean(); bool renderSizeAndFrameSizeDifferent = reader.ReadBoolean();
if (renderSizeAndFrameSizeDifferent) if (renderSizeAndFrameSizeDifferent)
{ {
frameInfo.FrameSize.RenderWidth = (int)reader.ReadLiteral(16) + 1; frameHeader.FrameSize.RenderWidth = (int)reader.ReadLiteral(16) + 1;
frameInfo.FrameSize.RenderHeight = (int)reader.ReadLiteral(16) + 1; frameHeader.FrameSize.RenderHeight = (int)reader.ReadLiteral(16) + 1;
} }
else else
{ {
frameInfo.FrameSize.RenderWidth = frameInfo.FrameSize.SuperResolutionUpscaledWidth; frameHeader.FrameSize.RenderWidth = frameHeader.FrameSize.SuperResolutionUpscaledWidth;
frameInfo.FrameSize.RenderHeight = frameInfo.FrameSize.FrameHeight; frameHeader.FrameSize.RenderHeight = frameHeader.FrameSize.FrameHeight;
} }
} }
@ -638,16 +638,16 @@ internal class ObuReader
private void ReadFrameSize(ref Av1BitStreamReader reader, bool frameSizeOverrideFlag) private void ReadFrameSize(ref Av1BitStreamReader reader, bool frameSizeOverrideFlag)
{ {
ObuSequenceHeader sequenceHeader = this.SequenceHeader!; ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!; ObuFrameHeader frameHeader = this.FrameHeader!;
if (frameSizeOverrideFlag) if (frameSizeOverrideFlag)
{ {
frameInfo.FrameSize.FrameWidth = (int)reader.ReadLiteral(sequenceHeader.FrameWidthBits) + 1; frameHeader.FrameSize.FrameWidth = (int)reader.ReadLiteral(sequenceHeader.FrameWidthBits) + 1;
frameInfo.FrameSize.FrameHeight = (int)reader.ReadLiteral(sequenceHeader.FrameHeightBits) + 1; frameHeader.FrameSize.FrameHeight = (int)reader.ReadLiteral(sequenceHeader.FrameHeightBits) + 1;
} }
else else
{ {
frameInfo.FrameSize.FrameWidth = sequenceHeader.MaxFrameWidth; frameHeader.FrameSize.FrameWidth = sequenceHeader.MaxFrameWidth;
frameInfo.FrameSize.FrameHeight = sequenceHeader.MaxFrameHeight; frameHeader.FrameSize.FrameHeight = sequenceHeader.MaxFrameHeight;
} }
this.ReadSuperResolutionParameters(ref reader); this.ReadSuperResolutionParameters(ref reader);
@ -657,15 +657,15 @@ internal class ObuReader
/// <summary> /// <summary>
/// 5.9.15. Tile info syntax. /// 5.9.15. Tile info syntax.
/// </summary> /// </summary>
private static ObuTileGroupHeader ReadTileInfo(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) private static ObuTileGroupHeader ReadTileInfo(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
ObuTileGroupHeader tileInfo = new(); ObuTileGroupHeader tileInfo = new();
int superblockColumnCount; int superblockColumnCount;
int superblockRowCount; int superblockRowCount;
int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2; int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2;
int superblockShift = superblockSizeLog2 - Av1Constants.ModeInfoSizeLog2; int superblockShift = superblockSizeLog2 - Av1Constants.ModeInfoSizeLog2;
superblockColumnCount = (frameInfo.ModeInfoColumnCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift; superblockColumnCount = (frameHeader.ModeInfoColumnCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift;
superblockRowCount = (frameInfo.ModeInfoRowCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift; superblockRowCount = (frameHeader.ModeInfoRowCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift;
int maxTileAreaOfSuperBlock = Av1Constants.MaxTileArea >> (superblockSizeLog2 << 1); int maxTileAreaOfSuperBlock = Av1Constants.MaxTileArea >> (superblockSizeLog2 << 1);
@ -701,7 +701,7 @@ internal class ObuReader
i++; i++;
} }
tileInfo.TileColumnStartModeInfo[i] = frameInfo.ModeInfoColumnCount; tileInfo.TileColumnStartModeInfo[i] = frameHeader.ModeInfoColumnCount;
tileInfo.TileColumnCount = i; tileInfo.TileColumnCount = i;
tileInfo.MinLog2TileRowCount = Math.Max(tileInfo.MinLog2TileCount - tileInfo.TileColumnCountLog2, 0); tileInfo.MinLog2TileRowCount = Math.Max(tileInfo.MinLog2TileCount - tileInfo.TileColumnCountLog2, 0);
@ -728,7 +728,7 @@ internal class ObuReader
i++; i++;
} }
tileInfo.TileRowStartModeInfo[i] = frameInfo.ModeInfoRowCount; tileInfo.TileRowStartModeInfo[i] = frameHeader.ModeInfoRowCount;
tileInfo.TileRowCount = i; tileInfo.TileRowCount = i;
} }
else else
@ -750,7 +750,7 @@ internal class ObuReader
throw new ImageFormatException("Super block tiles width does not add up to total width."); throw new ImageFormatException("Super block tiles width does not add up to total width.");
} }
tileInfo.TileColumnStartModeInfo[i] = frameInfo.ModeInfoColumnCount; tileInfo.TileColumnStartModeInfo[i] = frameHeader.ModeInfoColumnCount;
tileInfo.TileColumnCount = i; tileInfo.TileColumnCount = i;
tileInfo.TileColumnCountLog2 = TileLog2(1, tileInfo.TileColumnCount); tileInfo.TileColumnCountLog2 = TileLog2(1, tileInfo.TileColumnCount);
if (tileInfo.MinLog2TileCount > 0) if (tileInfo.MinLog2TileCount > 0)
@ -779,7 +779,7 @@ internal class ObuReader
throw new ImageFormatException("Super block tiles height does not add up to total height."); throw new ImageFormatException("Super block tiles height does not add up to total height.");
} }
tileInfo.TileRowStartModeInfo[i] = frameInfo.ModeInfoRowCount; tileInfo.TileRowStartModeInfo[i] = frameHeader.ModeInfoRowCount;
tileInfo.TileRowCount = i; tileInfo.TileRowCount = i;
tileInfo.TileRowCountLog2 = TileLog2(1, tileInfo.TileRowCount); tileInfo.TileRowCountLog2 = TileLog2(1, tileInfo.TileRowCount);
} }
@ -1035,10 +1035,10 @@ internal class ObuReader
throw new InvalidImageContentException("AVIF image can only contain INTRA frames."); throw new InvalidImageContentException("AVIF image can only contain INTRA frames.");
} }
// SetupFrameBufferReferences(sequenceHeader, frameInfo); // SetupFrameBufferReferences(sequenceHeader, frameHeader);
// CheckAddTemporalMotionVectorBuffer(sequenceHeader, frameInfo); // CheckAddTemporalMotionVectorBuffer(sequenceHeader, frameHeader);
// SetupFrameSignBias(sequenceHeader, frameInfo); // SetupFrameSignBias(sequenceHeader, frameHeader);
if (sequenceHeader.IsReducedStillPictureHeader || frameHeader.DisableCdfUpdate) if (sequenceHeader.IsReducedStillPictureHeader || frameHeader.DisableCdfUpdate)
{ {
frameHeader.DisableFrameEndUpdateCdf = true; frameHeader.DisableFrameEndUpdateCdf = true;
@ -1055,7 +1055,7 @@ internal class ObuReader
} }
else else
{ {
// LoadCdfs(frameInfo.PrimaryReferenceFrame); // LoadCdfs(frameHeader.PrimaryReferenceFrame);
// LoadPrevious(); // LoadPrevious();
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -1066,7 +1066,7 @@ internal class ObuReader
throw new NotImplementedException(); throw new NotImplementedException();
} }
// GenerateNextReferenceFrameMap(sequenceHeader, frameInfo); // GenerateNextReferenceFrameMap(sequenceHeader, frameHeader);
frameHeader.TilesInfo = ReadTileInfo(ref reader, sequenceHeader, frameHeader); frameHeader.TilesInfo = ReadTileInfo(ref reader, sequenceHeader, frameHeader);
ReadQuantizationParameters(ref reader, sequenceHeader, frameHeader); ReadQuantizationParameters(ref reader, sequenceHeader, frameHeader);
ReadSegmentationParameters(ref reader, frameHeader); ReadSegmentationParameters(ref reader, frameHeader);
@ -1076,7 +1076,7 @@ internal class ObuReader
// SetupSegmentationDequantization(); // SetupSegmentationDequantization();
if (frameHeader.PrimaryReferenceFrame == Av1Constants.PrimaryReferenceFrameNone) if (frameHeader.PrimaryReferenceFrame == Av1Constants.PrimaryReferenceFrameNone)
{ {
// ResetParseContext(mainParseContext, frameInfo.QuantizationParameters.BaseQIndex); // ResetParseContext(mainParseContext, frameHeader.QuantizationParameters.BaseQIndex);
} }
else else
{ {
@ -1190,7 +1190,7 @@ internal class ObuReader
private void ReadTileGroup(ref Av1BitStreamReader reader, IAv1TileReader decoder, ObuHeader header, out bool isLastTileGroup) private void ReadTileGroup(ref Av1BitStreamReader reader, IAv1TileReader decoder, ObuHeader header, out bool isLastTileGroup)
{ {
ObuSequenceHeader sequenceHeader = this.SequenceHeader!; ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!; ObuFrameHeader frameHeader = this.FrameHeader!;
ObuTileGroupHeader tileInfo = this.FrameHeader!.TilesInfo; ObuTileGroupHeader tileInfo = this.FrameHeader!.TilesInfo;
int tileCount = tileInfo.TileColumnCount * tileInfo.TileRowCount; int tileCount = tileInfo.TileColumnCount * tileInfo.TileRowCount;
int startBitPosition = reader.BitPosition; int startBitPosition = reader.BitPosition;
@ -1220,16 +1220,16 @@ internal class ObuReader
int headerBytes = (endBitPosition - startBitPosition) / 8; int headerBytes = (endBitPosition - startBitPosition) / 8;
header.PayloadSize -= headerBytes; header.PayloadSize -= headerBytes;
bool noIbc = !frameInfo.AllowIntraBlockCopy; bool noIbc = !frameHeader.AllowIntraBlockCopy;
bool doLoopFilter = noIbc && (frameInfo.LoopFilterParameters.FilterLevel[0] != 0 || frameInfo.LoopFilterParameters.FilterLevel[1] != 0); bool doLoopFilter = noIbc && (frameHeader.LoopFilterParameters.FilterLevel[0] != 0 || frameHeader.LoopFilterParameters.FilterLevel[1] != 0);
bool doCdef = noIbc && (!frameInfo.CodedLossless && bool doCdef = noIbc && (!frameHeader.CodedLossless &&
(frameInfo.CdefParameters.BitCount != 0 || (frameHeader.CdefParameters.BitCount != 0 ||
frameInfo.CdefParameters.YStrength[0] != 0 || frameHeader.CdefParameters.YStrength[0] != 0 ||
frameInfo.CdefParameters.UvStrength[0] != 0)); frameHeader.CdefParameters.UvStrength[0] != 0));
bool doLoopRestoration = noIbc && bool doLoopRestoration = noIbc &&
(frameInfo.LoopRestorationParameters.Items[(int)Av1Plane.Y].Type != ObuRestorationType.None || (frameHeader.LoopRestorationParameters.Items[(int)Av1Plane.Y].Type != ObuRestorationType.None ||
frameInfo.LoopRestorationParameters.Items[(int)Av1Plane.U].Type != ObuRestorationType.None || frameHeader.LoopRestorationParameters.Items[(int)Av1Plane.U].Type != ObuRestorationType.None ||
frameInfo.LoopRestorationParameters.Items[(int)Av1Plane.V].Type != ObuRestorationType.None); frameHeader.LoopRestorationParameters.Items[(int)Av1Plane.V].Type != ObuRestorationType.None);
for (int tileNum = tileGroupStart; tileNum <= tileGroupEnd; tileNum++) for (int tileNum = tileGroupStart; tileNum <= tileGroupEnd; tileNum++)
{ {
@ -1270,40 +1270,40 @@ internal class ObuReader
/// <summary> /// <summary>
/// 5.9.17. Quantizer index delta parameters syntax. /// 5.9.17. Quantizer index delta parameters syntax.
/// </summary> /// </summary>
private static void ReadFrameDeltaQParameters(ref Av1BitStreamReader reader, ObuFrameHeader frameInfo) private static void ReadFrameDeltaQParameters(ref Av1BitStreamReader reader, ObuFrameHeader frameHeader)
{ {
frameInfo.DeltaQParameters.Resolution = 0; frameHeader.DeltaQParameters.Resolution = 0;
frameInfo.DeltaQParameters.IsPresent = false; frameHeader.DeltaQParameters.IsPresent = false;
if (frameInfo.QuantizationParameters.BaseQIndex > 0) if (frameHeader.QuantizationParameters.BaseQIndex > 0)
{ {
frameInfo.DeltaQParameters.IsPresent = reader.ReadBoolean(); frameHeader.DeltaQParameters.IsPresent = reader.ReadBoolean();
} }
if (frameInfo.DeltaQParameters.IsPresent) if (frameHeader.DeltaQParameters.IsPresent)
{ {
frameInfo.DeltaQParameters.Resolution = (int)reader.ReadLiteral(2); frameHeader.DeltaQParameters.Resolution = (int)reader.ReadLiteral(2);
} }
} }
/// <summary> /// <summary>
/// 5.9.18. Loop filter delta parameters syntax. /// 5.9.18. Loop filter delta parameters syntax.
/// </summary> /// </summary>
private static void ReadFrameDeltaLoopFilterParameters(ref Av1BitStreamReader reader, ObuFrameHeader frameInfo) private static void ReadFrameDeltaLoopFilterParameters(ref Av1BitStreamReader reader, ObuFrameHeader frameHeader)
{ {
frameInfo.DeltaLoopFilterParameters.IsPresent = false; frameHeader.DeltaLoopFilterParameters.IsPresent = false;
frameInfo.DeltaLoopFilterParameters.Resolution = 0; frameHeader.DeltaLoopFilterParameters.Resolution = 0;
frameInfo.DeltaLoopFilterParameters.IsMulti = false; frameHeader.DeltaLoopFilterParameters.IsMulti = false;
if (frameInfo.DeltaQParameters.IsPresent) if (frameHeader.DeltaQParameters.IsPresent)
{ {
if (!frameInfo.AllowIntraBlockCopy) if (!frameHeader.AllowIntraBlockCopy)
{ {
frameInfo.DeltaLoopFilterParameters.IsPresent = reader.ReadBoolean(); frameHeader.DeltaLoopFilterParameters.IsPresent = reader.ReadBoolean();
} }
if (frameInfo.DeltaLoopFilterParameters.IsPresent) if (frameHeader.DeltaLoopFilterParameters.IsPresent)
{ {
frameInfo.DeltaLoopFilterParameters.Resolution = (int)reader.ReadLiteral(2); frameHeader.DeltaLoopFilterParameters.Resolution = (int)reader.ReadLiteral(2);
frameInfo.DeltaLoopFilterParameters.IsMulti = reader.ReadBoolean(); frameHeader.DeltaLoopFilterParameters.IsMulti = reader.ReadBoolean();
} }
} }
} }
@ -1372,30 +1372,30 @@ internal class ObuReader
/// <summary> /// <summary>
/// 5.9.14. Segmentation params syntax. /// 5.9.14. Segmentation params syntax.
/// </summary> /// </summary>
private static void ReadSegmentationParameters(ref Av1BitStreamReader reader, ObuFrameHeader frameInfo) private static void ReadSegmentationParameters(ref Av1BitStreamReader reader, ObuFrameHeader frameHeader)
{ {
frameInfo.SegmentationParameters.Enabled = reader.ReadBoolean(); frameHeader.SegmentationParameters.Enabled = reader.ReadBoolean();
if (frameInfo.SegmentationParameters.Enabled) if (frameHeader.SegmentationParameters.Enabled)
{ {
if (frameInfo.PrimaryReferenceFrame == PrimaryRefNone) if (frameHeader.PrimaryReferenceFrame == PrimaryRefNone)
{ {
frameInfo.SegmentationParameters.SegmentationUpdateMap = 1; frameHeader.SegmentationParameters.SegmentationUpdateMap = 1;
frameInfo.SegmentationParameters.SegmentationTemporalUpdate = 0; frameHeader.SegmentationParameters.SegmentationTemporalUpdate = 0;
frameInfo.SegmentationParameters.SegmentationUpdateData = 1; frameHeader.SegmentationParameters.SegmentationUpdateData = 1;
} }
else else
{ {
frameInfo.SegmentationParameters.SegmentationUpdateMap = reader.ReadBoolean() ? 1 : 0; frameHeader.SegmentationParameters.SegmentationUpdateMap = reader.ReadBoolean() ? 1 : 0;
if (frameInfo.SegmentationParameters.SegmentationUpdateMap == 1) if (frameHeader.SegmentationParameters.SegmentationUpdateMap == 1)
{ {
frameInfo.SegmentationParameters.SegmentationTemporalUpdate = reader.ReadBoolean() ? 1 : 0; frameHeader.SegmentationParameters.SegmentationTemporalUpdate = reader.ReadBoolean() ? 1 : 0;
} }
frameInfo.SegmentationParameters.SegmentationUpdateData = reader.ReadBoolean() ? 1 : 0; frameHeader.SegmentationParameters.SegmentationUpdateData = reader.ReadBoolean() ? 1 : 0;
} }
if (frameInfo.SegmentationParameters.SegmentationUpdateData == 1) if (frameHeader.SegmentationParameters.SegmentationUpdateData == 1)
{ {
for (int i = 0; i < MaxSegments; i++) for (int i = 0; i < MaxSegments; i++)
{ {
@ -1403,7 +1403,7 @@ internal class ObuReader
{ {
int featureValue = 0; int featureValue = 0;
bool featureEnabled = reader.ReadBoolean(); bool featureEnabled = reader.ReadBoolean();
frameInfo.SegmentationParameters.FeatureEnabled[i, j] = featureEnabled; frameHeader.SegmentationParameters.FeatureEnabled[i, j] = featureEnabled;
int clippedValue = 0; int clippedValue = 0;
if (featureEnabled) if (featureEnabled)
{ {
@ -1420,7 +1420,7 @@ internal class ObuReader
} }
} }
frameInfo.SegmentationParameters.FeatureData[i, j] = clippedValue; frameHeader.SegmentationParameters.FeatureData[i, j] = clippedValue;
} }
} }
} }
@ -1431,24 +1431,24 @@ internal class ObuReader
{ {
for (int j = 0; j < Av1Constants.SegmentationLevelMax; j++) for (int j = 0; j < Av1Constants.SegmentationLevelMax; j++)
{ {
frameInfo.SegmentationParameters.FeatureEnabled[i, j] = false; frameHeader.SegmentationParameters.FeatureEnabled[i, j] = false;
frameInfo.SegmentationParameters.FeatureData[i, j] = 0; frameHeader.SegmentationParameters.FeatureData[i, j] = 0;
} }
} }
} }
frameInfo.SegmentationParameters.SegmentIdPrecedesSkip = false; frameHeader.SegmentationParameters.SegmentIdPrecedesSkip = false;
frameInfo.SegmentationParameters.LastActiveSegmentId = 0; frameHeader.SegmentationParameters.LastActiveSegmentId = 0;
for (int i = 0; i < Av1Constants.MaxSegmentCount; i++) for (int i = 0; i < Av1Constants.MaxSegmentCount; i++)
{ {
for (int j = 0; j < Av1Constants.SegmentationLevelMax; j++) for (int j = 0; j < Av1Constants.SegmentationLevelMax; j++)
{ {
if (frameInfo.SegmentationParameters.FeatureEnabled[i, j]) if (frameHeader.SegmentationParameters.FeatureEnabled[i, j])
{ {
frameInfo.SegmentationParameters.LastActiveSegmentId = i; frameHeader.SegmentationParameters.LastActiveSegmentId = i;
if (j >= SegLvlRefFrame) if (j >= SegLvlRefFrame)
{ {
frameInfo.SegmentationParameters.SegmentIdPrecedesSkip = true; frameHeader.SegmentationParameters.SegmentIdPrecedesSkip = true;
} }
} }
} }
@ -1460,36 +1460,36 @@ internal class ObuReader
/// </summary> /// </summary>
private void ReadLoopFilterParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader) private void ReadLoopFilterParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader)
{ {
ObuFrameHeader frameInfo = this.FrameHeader!; ObuFrameHeader frameHeader = this.FrameHeader!;
if (frameInfo.CodedLossless || frameInfo.AllowIntraBlockCopy) if (frameHeader.CodedLossless || frameHeader.AllowIntraBlockCopy)
{ {
return; return;
} }
frameInfo.LoopFilterParameters.FilterLevel[0] = (int)reader.ReadLiteral(6); frameHeader.LoopFilterParameters.FilterLevel[0] = (int)reader.ReadLiteral(6);
frameInfo.LoopFilterParameters.FilterLevel[1] = (int)reader.ReadLiteral(6); frameHeader.LoopFilterParameters.FilterLevel[1] = (int)reader.ReadLiteral(6);
if (sequenceHeader.ColorConfig.PlaneCount > 1) if (sequenceHeader.ColorConfig.PlaneCount > 1)
{ {
if (frameInfo.LoopFilterParameters.FilterLevel[0] > 0 || frameInfo.LoopFilterParameters.FilterLevel[1] > 0) if (frameHeader.LoopFilterParameters.FilterLevel[0] > 0 || frameHeader.LoopFilterParameters.FilterLevel[1] > 0)
{ {
frameInfo.LoopFilterParameters.FilterLevelU = (int)reader.ReadLiteral(6); frameHeader.LoopFilterParameters.FilterLevelU = (int)reader.ReadLiteral(6);
frameInfo.LoopFilterParameters.FilterLevelV = (int)reader.ReadLiteral(6); frameHeader.LoopFilterParameters.FilterLevelV = (int)reader.ReadLiteral(6);
} }
} }
frameInfo.LoopFilterParameters.SharpnessLevel = (int)reader.ReadLiteral(3); frameHeader.LoopFilterParameters.SharpnessLevel = (int)reader.ReadLiteral(3);
frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled = reader.ReadBoolean(); frameHeader.LoopFilterParameters.ReferenceDeltaModeEnabled = reader.ReadBoolean();
if (frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled) if (frameHeader.LoopFilterParameters.ReferenceDeltaModeEnabled)
{ {
frameInfo.LoopFilterParameters.ReferenceDeltaModeUpdate = reader.ReadBoolean(); frameHeader.LoopFilterParameters.ReferenceDeltaModeUpdate = reader.ReadBoolean();
if (frameInfo.LoopFilterParameters.ReferenceDeltaModeUpdate) if (frameHeader.LoopFilterParameters.ReferenceDeltaModeUpdate)
{ {
for (int i = 0; i < Av1Constants.TotalReferencesPerFrame; i++) for (int i = 0; i < Av1Constants.TotalReferencesPerFrame; i++)
{ {
if (reader.ReadBoolean()) if (reader.ReadBoolean())
{ {
frameInfo.LoopFilterParameters.ReferenceDeltas[i] = reader.ReadSignedFromUnsigned(7); frameHeader.LoopFilterParameters.ReferenceDeltas[i] = reader.ReadSignedFromUnsigned(7);
} }
} }
@ -1497,7 +1497,7 @@ internal class ObuReader
{ {
if (reader.ReadBoolean()) if (reader.ReadBoolean())
{ {
frameInfo.LoopFilterParameters.ModeDeltas[i] = reader.ReadSignedFromUnsigned(7); frameHeader.LoopFilterParameters.ModeDeltas[i] = reader.ReadSignedFromUnsigned(7);
} }
} }
} }
@ -1507,21 +1507,21 @@ internal class ObuReader
/// <summary> /// <summary>
/// 5.9.21. TX mode syntax. /// 5.9.21. TX mode syntax.
/// </summary> /// </summary>
private static void ReadTransformMode(ref Av1BitStreamReader reader, ObuFrameHeader frameInfo) private static void ReadTransformMode(ref Av1BitStreamReader reader, ObuFrameHeader frameHeader)
{ {
if (frameInfo.CodedLossless) if (frameHeader.CodedLossless)
{ {
frameInfo.TransformMode = Av1TransformMode.Only4x4; frameHeader.TransformMode = Av1TransformMode.Only4x4;
} }
else else
{ {
if (reader.ReadBoolean()) if (reader.ReadBoolean())
{ {
frameInfo.TransformMode = Av1TransformMode.Select; frameHeader.TransformMode = Av1TransformMode.Select;
} }
else else
{ {
frameInfo.TransformMode = Av1TransformMode.Largest; frameHeader.TransformMode = Av1TransformMode.Largest;
} }
} }
} }
@ -1529,54 +1529,54 @@ internal class ObuReader
/// <summary> /// <summary>
/// See section 5.9.20. Loop restoration params syntax. /// See section 5.9.20. Loop restoration params syntax.
/// </summary> /// </summary>
private static void ReadLoopRestorationParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) private static void ReadLoopRestorationParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
if (frameInfo.CodedLossless || frameInfo.AllowIntraBlockCopy || !sequenceHeader.EnableRestoration) if (frameHeader.CodedLossless || frameHeader.AllowIntraBlockCopy || !sequenceHeader.EnableRestoration)
{ {
return; return;
} }
frameInfo.LoopRestorationParameters.UsesLoopRestoration = false; frameHeader.LoopRestorationParameters.UsesLoopRestoration = false;
frameInfo.LoopRestorationParameters.UsesChromaLoopRestoration = false; frameHeader.LoopRestorationParameters.UsesChromaLoopRestoration = false;
int planesCount = sequenceHeader.ColorConfig.PlaneCount; int planesCount = sequenceHeader.ColorConfig.PlaneCount;
for (int i = 0; i < planesCount; i++) for (int i = 0; i < planesCount; i++)
{ {
frameInfo.LoopRestorationParameters.Items[i].Type = (ObuRestorationType)reader.ReadLiteral(2); frameHeader.LoopRestorationParameters.Items[i].Type = (ObuRestorationType)reader.ReadLiteral(2);
if (frameInfo.LoopRestorationParameters.Items[i].Type != ObuRestorationType.None) if (frameHeader.LoopRestorationParameters.Items[i].Type != ObuRestorationType.None)
{ {
frameInfo.LoopRestorationParameters.UsesLoopRestoration = true; frameHeader.LoopRestorationParameters.UsesLoopRestoration = true;
if (i > 0) if (i > 0)
{ {
frameInfo.LoopRestorationParameters.UsesChromaLoopRestoration = true; frameHeader.LoopRestorationParameters.UsesChromaLoopRestoration = true;
} }
} }
} }
if (frameInfo.LoopRestorationParameters.UsesLoopRestoration) if (frameHeader.LoopRestorationParameters.UsesLoopRestoration)
{ {
frameInfo.LoopRestorationParameters.UnitShift = (int)reader.ReadLiteral(1); frameHeader.LoopRestorationParameters.UnitShift = (int)reader.ReadLiteral(1);
if (sequenceHeader.Use128x128Superblock) if (sequenceHeader.Use128x128Superblock)
{ {
frameInfo.LoopRestorationParameters.UnitShift++; frameHeader.LoopRestorationParameters.UnitShift++;
} }
else else
{ {
if (reader.ReadBoolean()) if (reader.ReadBoolean())
{ {
frameInfo.LoopRestorationParameters.UnitShift += (int)reader.ReadLiteral(1); frameHeader.LoopRestorationParameters.UnitShift += (int)reader.ReadLiteral(1);
} }
} }
frameInfo.LoopRestorationParameters.Items[0].Size = Av1Constants.RestorationMaxTileSize >> (2 - frameInfo.LoopRestorationParameters.UnitShift); frameHeader.LoopRestorationParameters.Items[0].Size = Av1Constants.RestorationMaxTileSize >> (2 - frameHeader.LoopRestorationParameters.UnitShift);
frameInfo.LoopRestorationParameters.UVShift = 0; frameHeader.LoopRestorationParameters.UVShift = 0;
if (sequenceHeader.ColorConfig.SubSamplingX && sequenceHeader.ColorConfig.SubSamplingY && frameInfo.LoopRestorationParameters.UsesChromaLoopRestoration) if (sequenceHeader.ColorConfig.SubSamplingX && sequenceHeader.ColorConfig.SubSamplingY && frameHeader.LoopRestorationParameters.UsesChromaLoopRestoration)
{ {
frameInfo.LoopRestorationParameters.UVShift = (int)reader.ReadLiteral(1); frameHeader.LoopRestorationParameters.UVShift = (int)reader.ReadLiteral(1);
} }
frameInfo.LoopRestorationParameters.Items[1].Size = frameInfo.LoopRestorationParameters.Items[0].Size >> frameInfo.LoopRestorationParameters.UVShift; frameHeader.LoopRestorationParameters.Items[1].Size = frameHeader.LoopRestorationParameters.Items[0].Size >> frameHeader.LoopRestorationParameters.UVShift;
frameInfo.LoopRestorationParameters.Items[2].Size = frameInfo.LoopRestorationParameters.Items[0].Size >> frameInfo.LoopRestorationParameters.UVShift; frameHeader.LoopRestorationParameters.Items[2].Size = frameHeader.LoopRestorationParameters.Items[0].Size >> frameHeader.LoopRestorationParameters.UVShift;
} }
} }
@ -1668,10 +1668,10 @@ internal class ObuReader
/// <summary> /// <summary>
/// 5.9.30. Film grain params syntax. /// 5.9.30. Film grain params syntax.
/// </summary> /// </summary>
private static ObuFilmGrainParameters ReadFilmGrainFilterParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) private static ObuFilmGrainParameters ReadFilmGrainFilterParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
ObuFilmGrainParameters grainParams = new(); ObuFilmGrainParameters grainParams = new();
if (!sequenceHeader.AreFilmGrainingParametersPresent || (!frameInfo.ShowFrame && !frameInfo.ShowableFrame)) if (!sequenceHeader.AreFilmGrainingParametersPresent || (!frameHeader.ShowFrame && !frameHeader.ShowableFrame))
{ {
return grainParams; return grainParams;
} }
@ -1684,7 +1684,7 @@ internal class ObuReader
grainParams.GrainSeed = reader.ReadLiteral(16); grainParams.GrainSeed = reader.ReadLiteral(16);
if (frameInfo.FrameType == ObuFrameType.InterFrame) if (frameHeader.FrameType == ObuFrameType.InterFrame)
{ {
grainParams.UpdateGrain = reader.ReadBoolean(); grainParams.UpdateGrain = reader.ReadBoolean();
} }

88
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuWriter.cs

@ -14,7 +14,7 @@ internal class ObuWriter
/// <summary> /// <summary>
/// Encode a single frame into OBU's. /// Encode a single frame into OBU's.
/// </summary> /// </summary>
public void WriteAll(Configuration configuration, Stream stream, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, IAv1TileWriter tileWriter) public void WriteAll(Configuration configuration, Stream stream, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, IAv1TileWriter tileWriter)
{ {
// TODO: Determine inital size dynamically // TODO: Determine inital size dynamically
int initialBufferSize = 2000; int initialBufferSize = 2000;
@ -30,12 +30,12 @@ internal class ObuWriter
WriteObuHeaderAndSize(stream, ObuType.SequenceHeader, buffer.GetSpan(bytesWritten)); WriteObuHeaderAndSize(stream, ObuType.SequenceHeader, buffer.GetSpan(bytesWritten));
} }
if (frameInfo != null && sequenceHeader != null) if (frameHeader != null && sequenceHeader != null)
{ {
this.WriteFrameHeader(ref writer, sequenceHeader, frameInfo, false); this.WriteFrameHeader(ref writer, sequenceHeader, frameHeader, false);
if (frameInfo.TilesInfo != null) if (frameHeader.TilesInfo != null)
{ {
WriteTileGroup(ref writer, frameInfo.TilesInfo, tileWriter); WriteTileGroup(ref writer, frameHeader.TilesInfo, tileWriter);
} }
int bytesWritten = (writer.BitPosition + 7) >> 3; int bytesWritten = (writer.BitPosition + 7) >> 3;
@ -192,7 +192,7 @@ internal class ObuWriter
} }
} }
private static void WriteSuperResolutionParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) private static void WriteSuperResolutionParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
bool useSuperResolution = false; bool useSuperResolution = false;
if (sequenceHeader.EnableSuperResolution) if (sequenceHeader.EnableSuperResolution)
@ -202,22 +202,22 @@ internal class ObuWriter
if (useSuperResolution) if (useSuperResolution)
{ {
writer.WriteLiteral((uint)frameInfo.FrameSize.SuperResolutionDenominator - Av1Constants.SuperResolutionScaleDenominatorMinimum, Av1Constants.SuperResolutionScaleBits); writer.WriteLiteral((uint)frameHeader.FrameSize.SuperResolutionDenominator - Av1Constants.SuperResolutionScaleDenominatorMinimum, Av1Constants.SuperResolutionScaleBits);
} }
} }
private static void WriteRenderSize(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) private static void WriteRenderSize(ref Av1BitStreamWriter writer, ObuFrameHeader frameHeader)
{ {
bool renderSizeAndFrameSizeDifferent = false; bool renderSizeAndFrameSizeDifferent = false;
writer.WriteBoolean(false); writer.WriteBoolean(false);
if (renderSizeAndFrameSizeDifferent) if (renderSizeAndFrameSizeDifferent)
{ {
writer.WriteLiteral((uint)frameInfo.FrameSize.RenderWidth - 1, 16); writer.WriteLiteral((uint)frameHeader.FrameSize.RenderWidth - 1, 16);
writer.WriteLiteral((uint)frameInfo.FrameSize.RenderHeight - 1, 16); writer.WriteLiteral((uint)frameHeader.FrameSize.RenderHeight - 1, 16);
} }
} }
private static void WriteFrameSizeWithReferences(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool frameSizeOverrideFlag) private static void WriteFrameSizeWithReferences(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, bool frameSizeOverrideFlag)
{ {
bool foundReference = false; bool foundReference = false;
for (int i = 0; i < Av1Constants.ReferencesPerFrame; i++) for (int i = 0; i < Av1Constants.ReferencesPerFrame; i++)
@ -232,35 +232,35 @@ internal class ObuWriter
if (!foundReference) if (!foundReference)
{ {
WriteFrameSize(ref writer, sequenceHeader, frameInfo, frameSizeOverrideFlag); WriteFrameSize(ref writer, sequenceHeader, frameHeader, frameSizeOverrideFlag);
WriteRenderSize(ref writer, frameInfo); WriteRenderSize(ref writer, frameHeader);
} }
else else
{ {
WriteSuperResolutionParameters(ref writer, sequenceHeader, frameInfo); WriteSuperResolutionParameters(ref writer, sequenceHeader, frameHeader);
} }
} }
private static void WriteFrameSize(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool frameSizeOverrideFlag) private static void WriteFrameSize(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, bool frameSizeOverrideFlag)
{ {
if (frameSizeOverrideFlag) if (frameSizeOverrideFlag)
{ {
writer.WriteLiteral((uint)frameInfo.FrameSize.FrameWidth - 1, sequenceHeader.FrameWidthBits + 1); writer.WriteLiteral((uint)frameHeader.FrameSize.FrameWidth - 1, sequenceHeader.FrameWidthBits + 1);
writer.WriteLiteral((uint)frameInfo.FrameSize.FrameHeight - 1, sequenceHeader.FrameHeightBits + 1); writer.WriteLiteral((uint)frameHeader.FrameSize.FrameHeight - 1, sequenceHeader.FrameHeightBits + 1);
} }
WriteSuperResolutionParameters(ref writer, sequenceHeader, frameInfo); WriteSuperResolutionParameters(ref writer, sequenceHeader, frameHeader);
} }
private static void WriteTileInfo(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) private static void WriteTileInfo(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
ObuTileGroupHeader tileInfo = frameInfo.TilesInfo; ObuTileGroupHeader tileInfo = frameHeader.TilesInfo;
int superblockColumnCount; int superblockColumnCount;
int superblockRowCount; int superblockRowCount;
int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2; int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2;
int superblockShift = superblockSizeLog2 - Av1Constants.ModeInfoSizeLog2; int superblockShift = superblockSizeLog2 - Av1Constants.ModeInfoSizeLog2;
superblockColumnCount = (frameInfo.ModeInfoColumnCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift; superblockColumnCount = (frameHeader.ModeInfoColumnCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift;
superblockRowCount = (frameInfo.ModeInfoRowCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift; superblockRowCount = (frameHeader.ModeInfoRowCount + sequenceHeader.SuperblockModeInfoSize - 1) >> superblockShift;
int superBlockSize = superblockShift + 2; int superBlockSize = superblockShift + 2;
int maxTileAreaOfSuperBlock = Av1Constants.MaxTileArea >> (2 * superBlockSize); int maxTileAreaOfSuperBlock = Av1Constants.MaxTileArea >> (2 * superBlockSize);
@ -341,7 +341,7 @@ internal class ObuWriter
writer.WriteLiteral((uint)tileInfo.TileSizeBytes - 1, 2); writer.WriteLiteral((uint)tileInfo.TileSizeBytes - 1, 2);
} }
frameInfo.TilesInfo = tileInfo; frameHeader.TilesInfo = tileInfo;
} }
private void WriteUncompressedFrameHeader(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader) private void WriteUncompressedFrameHeader(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
@ -356,7 +356,7 @@ internal class ObuWriter
} }
else else
{ {
// Guard.IsTrue(frameInfo.AllowScreenContentTools == sequenceHeader.ForceScreenContentTools); // Guard.IsTrue(frameHeader.AllowScreenContentTools == sequenceHeader.ForceScreenContentTools);
} }
if (frameHeader.AllowScreenContentTools) if (frameHeader.AllowScreenContentTools)
@ -367,7 +367,7 @@ internal class ObuWriter
} }
else else
{ {
// Guard.IsTrue(frameInfo.ForceIntegerMotionVector == sequenceHeader.ForceIntegerMotionVector, nameof(frameInfo.ForceIntegerMotionVector), "Frame and sequence must be in sync"); // Guard.IsTrue(frameHeader.ForceIntegerMotionVector == sequenceHeader.ForceIntegerMotionVector, nameof(frameHeader.ForceIntegerMotionVector), "Frame and sequence must be in sync");
} }
} }
@ -486,10 +486,10 @@ internal class ObuWriter
private static bool IsSegmentationFeatureActive(ObuSegmentationParameters segmentationParameters, int segmentId, ObuSegmentationLevelFeature feature) private static bool IsSegmentationFeatureActive(ObuSegmentationParameters segmentationParameters, int segmentId, ObuSegmentationLevelFeature feature)
=> segmentationParameters.Enabled && segmentationParameters.FeatureEnabled[segmentId, (int)feature]; => segmentationParameters.Enabled && segmentationParameters.FeatureEnabled[segmentId, (int)feature];
private int WriteFrameHeader(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool writeTrailingBits) private int WriteFrameHeader(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, bool writeTrailingBits)
{ {
int startBitPosition = writer.BitPosition; int startBitPosition = writer.BitPosition;
this.WriteUncompressedFrameHeader(ref writer, sequenceHeader, frameInfo); this.WriteUncompressedFrameHeader(ref writer, sequenceHeader, frameHeader);
if (writeTrailingBits) if (writeTrailingBits)
{ {
WriteTrailingBits(ref writer); WriteTrailingBits(ref writer);
@ -555,32 +555,32 @@ internal class ObuWriter
return deltaQ; return deltaQ;
} }
private static void WriteFrameDeltaQParameters(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) private static void WriteFrameDeltaQParameters(ref Av1BitStreamWriter writer, ObuFrameHeader frameHeader)
{ {
if (frameInfo.QuantizationParameters.BaseQIndex > 0) if (frameHeader.QuantizationParameters.BaseQIndex > 0)
{ {
writer.WriteBoolean(frameInfo.DeltaQParameters.IsPresent); writer.WriteBoolean(frameHeader.DeltaQParameters.IsPresent);
} }
if (frameInfo.DeltaQParameters.IsPresent) if (frameHeader.DeltaQParameters.IsPresent)
{ {
writer.WriteLiteral((uint)frameInfo.DeltaQParameters.Resolution, 2); writer.WriteLiteral((uint)frameHeader.DeltaQParameters.Resolution, 2);
} }
} }
private static void WriteFrameDeltaLoopFilterParameters(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) private static void WriteFrameDeltaLoopFilterParameters(ref Av1BitStreamWriter writer, ObuFrameHeader frameHeader)
{ {
if (frameInfo.DeltaQParameters.IsPresent) if (frameHeader.DeltaQParameters.IsPresent)
{ {
if (!frameInfo.AllowIntraBlockCopy) if (!frameHeader.AllowIntraBlockCopy)
{ {
writer.WriteBoolean(frameInfo.DeltaLoopFilterParameters.IsPresent); writer.WriteBoolean(frameHeader.DeltaLoopFilterParameters.IsPresent);
} }
if (frameInfo.DeltaLoopFilterParameters.IsPresent) if (frameHeader.DeltaLoopFilterParameters.IsPresent)
{ {
writer.WriteLiteral((uint)frameInfo.DeltaLoopFilterParameters.Resolution, 2); writer.WriteLiteral((uint)frameHeader.DeltaLoopFilterParameters.Resolution, 2);
writer.WriteBoolean(frameInfo.DeltaLoopFilterParameters.IsMulti); writer.WriteBoolean(frameHeader.DeltaLoopFilterParameters.IsMulti);
} }
} }
} }
@ -621,10 +621,10 @@ internal class ObuWriter
} }
} }
private static void WriteSegmentationParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) private static void WriteSegmentationParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
_ = sequenceHeader; _ = sequenceHeader;
Guard.IsFalse(frameInfo.SegmentationParameters.Enabled, nameof(frameInfo.SegmentationParameters.Enabled), "Segmentation not supported yet."); Guard.IsFalse(frameHeader.SegmentationParameters.Enabled, nameof(frameHeader.SegmentationParameters.Enabled), "Segmentation not supported yet.");
writer.WriteBoolean(false); writer.WriteBoolean(false);
} }
@ -664,11 +664,11 @@ internal class ObuWriter
/// <summary> /// <summary>
/// 5.9.21. TX mode syntax. /// 5.9.21. TX mode syntax.
/// </summary> /// </summary>
private static void WriteTransformMode(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) private static void WriteTransformMode(ref Av1BitStreamWriter writer, ObuFrameHeader frameHeader)
{ {
if (!frameInfo.CodedLossless) if (!frameHeader.CodedLossless)
{ {
writer.WriteBoolean(frameInfo.TransformMode == Av1TransformMode.Select); writer.WriteBoolean(frameHeader.TransformMode == Av1TransformMode.Select);
} }
} }

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

@ -56,7 +56,7 @@ internal class Av1BlockModeInfo
public Av1IntraFilterModeInfo FilterIntraModeInfo { get; internal set; } public Av1IntraFilterModeInfo FilterIntraModeInfo { get; internal set; }
/// <summary> /// <summary>
/// Gets the index of the first <see cref="Av1TransformInfo"/> of this Mode Info in the <see cref="Av1FrameBuffer"/>. /// Gets the index of the first <see cref="Av1TransformInfo"/> of this Mode Info in the <see cref="Av1FrameInfo"/>.
/// </summary> /// </summary>
public int[] FirstTransformLocation { get; } public int[] FirstTransformLocation { get; }

27
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs → src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameInfo.cs

@ -5,7 +5,10 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal partial class Av1FrameBuffer /// <summary>
/// Collection of all information for a single frame.
/// </summary>
internal partial class Av1FrameInfo
{ {
// Number of Coefficients in a single ModeInfo 4x4 block of pixels (1 length + 4 x 4). // Number of Coefficients in a single ModeInfo 4x4 block of pixels (1 length + 4 x 4).
public const int CoefficientCountPerModeInfo = 1 + 16; public const int CoefficientCountPerModeInfo = 1 + 16;
@ -29,7 +32,7 @@ internal partial class Av1FrameBuffer
private readonly int deltaLoopFactorLog2 = 2; private readonly int deltaLoopFactorLog2 = 2;
private readonly int[] deltaLoopFilter; private readonly int[] deltaLoopFilter;
public Av1FrameBuffer(ObuSequenceHeader sequenceHeader) public Av1FrameInfo(ObuSequenceHeader sequenceHeader)
{ {
// init_main_frame_ctxt // init_main_frame_ctxt
int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2; int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2;
@ -102,20 +105,28 @@ internal partial class Av1FrameBuffer
return this.modeInfos[index]; return this.modeInfos[index];
} }
public Span<Av1TransformInfo> GetSuperblockTransformY(Point index) public ref Av1TransformInfo GetSuperblockTransform(int plane, Point index)
{
if (plane == 0)
{
return ref this.GetSuperblockTransformY(index);
}
return ref this.GetSuperblockTransformUv(index);
}
public ref Av1TransformInfo GetSuperblockTransformY(Point index)
{ {
Span<Av1TransformInfo> span = this.transformInfosY; Span<Av1TransformInfo> span = this.transformInfosY;
int offset = ((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock; int offset = ((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock;
int length = this.modeInfoCountPerSuperblock; return ref span[offset];
return span.Slice(offset, length);
} }
public Span<Av1TransformInfo> GetSuperblockTransformUv(Point index) public ref Av1TransformInfo GetSuperblockTransformUv(Point index)
{ {
Span<Av1TransformInfo> span = this.transformInfosUv; Span<Av1TransformInfo> span = this.transformInfosUv;
int offset = (((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock) << 1; int offset = (((index.Y * this.superblockColumnCount) + index.X) * this.modeInfoCountPerSuperblock) << 1;
int length = this.modeInfoCountPerSuperblock << 1; return ref span[offset];
return span.Slice(offset, length);
} }
public Span<int> GetCoefficients(int plane) => public Span<int> GetCoefficients(int plane) =>

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

@ -3,10 +3,10 @@
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal partial class Av1FrameBuffer internal partial class Av1FrameInfo
{ {
/// <summary> /// <summary>
/// Mapping of <see cref="Av1BlockModeInfo"/> instances, from position to index into the <see cref="Av1FrameBuffer"/>. /// Mapping of <see cref="Av1BlockModeInfo"/> instances, from position to index into the <see cref="Av1FrameInfo"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// For a visual representation of how this map looks in practice, see <seealso href="https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/v2.1.0/Docs/svt-av1-decoder-design.md?ref_type=tags#blockmodeinfo"/> /// For a visual representation of how this map looks in practice, see <seealso href="https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/v2.1.0/Docs/svt-av1-decoder-design.md?ref_type=tags#blockmodeinfo"/>

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

@ -75,7 +75,7 @@ internal class Av1PartitionInfo
public int ModeBlockToBottomEdge => this.modeBlockToBottomEdge; public int ModeBlockToBottomEdge => this.modeBlockToBottomEdge;
public void ComputeBoundaryOffsets(ObuFrameHeader frameInfo, Av1TileInfo tileInfo) public void ComputeBoundaryOffsets(ObuFrameHeader frameHeader, Av1TileInfo tileInfo)
{ {
Av1BlockSize blockSize = this.ModeInfo.BlockSize; Av1BlockSize blockSize = this.ModeInfo.BlockSize;
int bw4 = blockSize.Get4x4WideCount(); int bw4 = blockSize.Get4x4WideCount();
@ -86,9 +86,9 @@ internal class Av1PartitionInfo
this.AvailableLeftForChroma = this.AvailableLeft; this.AvailableLeftForChroma = this.AvailableLeft;
int shift = Av1Constants.ModeInfoSizeLog2 + 3; int shift = Av1Constants.ModeInfoSizeLog2 + 3;
this.modeBlockToLeftEdge = -this.ColumnIndex << shift; this.modeBlockToLeftEdge = -this.ColumnIndex << shift;
this.modeBlockToRightEdge = (frameInfo.ModeInfoColumnCount - bw4 - this.ColumnIndex) << shift; this.modeBlockToRightEdge = (frameHeader.ModeInfoColumnCount - bw4 - this.ColumnIndex) << shift;
this.modeBlockToTopEdge = -this.RowIndex << shift; this.modeBlockToTopEdge = -this.RowIndex << shift;
this.modeBlockToBottomEdge = (frameInfo.ModeInfoRowCount - bh4 - this.RowIndex) << shift; this.modeBlockToBottomEdge = (frameHeader.ModeInfoRowCount - bh4 - this.RowIndex) << shift;
} }
public int GetMaxBlockWide(Av1BlockSize blockSize, bool subX) public int GetMaxBlockWide(Av1BlockSize blockSize, bool subX)

26
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs

@ -5,12 +5,12 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1SuperblockInfo internal class Av1SuperblockInfo
{ {
private readonly Av1FrameBuffer frameBuffer; private readonly Av1FrameInfo frameInfo;
public Av1SuperblockInfo(Av1FrameBuffer frameBuffer, Point position) public Av1SuperblockInfo(Av1FrameInfo frameInfo, Point position)
{ {
this.Position = position; this.Position = position;
this.frameBuffer = frameBuffer; this.frameInfo = frameInfo;
} }
/// <summary> /// <summary>
@ -18,27 +18,29 @@ internal class Av1SuperblockInfo
/// </summary> /// </summary>
public Point Position { get; } public Point Position { get; }
public ref int SuperblockDeltaQ => ref this.frameBuffer.GetDeltaQuantizationIndex(this.Position); public ref int SuperblockDeltaQ => ref this.frameInfo.GetDeltaQuantizationIndex(this.Position);
public Av1BlockModeInfo SuperblockModeInfo => this.GetModeInfo(new Point(0, 0)); public Av1BlockModeInfo SuperblockModeInfo => this.GetModeInfo(new Point(0, 0));
public Span<int> CoefficientsY => this.frameBuffer.GetCoefficientsY(this.Position); public Span<int> CoefficientsY => this.frameInfo.GetCoefficientsY(this.Position);
public Span<int> CoefficientsU => this.frameBuffer.GetCoefficientsU(this.Position); public Span<int> CoefficientsU => this.frameInfo.GetCoefficientsU(this.Position);
public Span<int> CoefficientsV => this.frameBuffer.GetCoefficientsV(this.Position); public Span<int> CoefficientsV => this.frameInfo.GetCoefficientsV(this.Position);
public Span<int> CdefStrength => this.frameBuffer.GetCdefStrength(this.Position); public Span<int> CdefStrength => this.frameInfo.GetCdefStrength(this.Position);
public Span<int> SuperblockDeltaLoopFilter => this.frameBuffer.GetDeltaLoopFilter(this.Position); public Span<int> SuperblockDeltaLoopFilter => this.frameInfo.GetDeltaLoopFilter(this.Position);
public int TransformInfoIndexY { get; internal set; } public int TransformInfoIndexY { get; internal set; }
public int TransformInfoIndexUv { get; internal set; } public int TransformInfoIndexUv { get; internal set; }
public Span<Av1TransformInfo> GetTransformInfoY() => this.frameBuffer.GetSuperblockTransformY(this.Position); public int BlockCount { get; internal set; }
public Span<Av1TransformInfo> GetTransformInfoUv() => this.frameBuffer.GetSuperblockTransformUv(this.Position); public ref Av1TransformInfo GetTransformInfoY() => ref this.frameInfo.GetSuperblockTransformY(this.Position);
public Av1BlockModeInfo GetModeInfo(Point index) => this.frameBuffer.GetModeInfo(this.Position, index); public ref Av1TransformInfo GetTransformInfoUv() => ref this.frameInfo.GetSuperblockTransformUv(this.Position);
public Av1BlockModeInfo GetModeInfo(Point index) => this.frameInfo.GetModeInfo(this.Position, index);
} }

6
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileInfo.cs

@ -7,10 +7,10 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1TileInfo internal class Av1TileInfo
{ {
public Av1TileInfo(int row, int column, ObuFrameHeader frameInfo) public Av1TileInfo(int row, int column, ObuFrameHeader frameHeader)
{ {
this.SetTileRow(frameInfo.TilesInfo, frameInfo.ModeInfoRowCount, row); this.SetTileRow(frameHeader.TilesInfo, frameHeader.ModeInfoRowCount, row);
this.SetTileColumn(frameInfo.TilesInfo, frameInfo.ModeInfoColumnCount, column); this.SetTileColumn(frameHeader.TilesInfo, frameHeader.ModeInfoColumnCount, column);
} }
public int ModeInfoRowStart { get; private set; } public int ModeInfoRowStart { get; private set; }

172
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Heif.Av1; using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
@ -34,17 +35,17 @@ internal class Av1TileReader : IAv1TileReader
private readonly int[] firstTransformOffset = new int[2]; private readonly int[] firstTransformOffset = new int[2];
private readonly int[] coefficientIndex = []; private readonly int[] coefficientIndex = [];
public Av1TileReader(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) public Av1TileReader(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{ {
this.FrameInfo = frameInfo; this.FrameHeader = frameHeader;
this.SequenceHeader = sequenceHeader; this.SequenceHeader = sequenceHeader;
// init_main_frame_ctxt // init_main_frame_ctxt
this.FrameBuffer = new(this.SequenceHeader); this.FrameInfo = new(this.SequenceHeader);
this.segmentIds = new int[this.FrameInfo.ModeInfoRowCount][]; this.segmentIds = new int[this.FrameHeader.ModeInfoRowCount][];
for (int y = 0; y < this.FrameInfo.ModeInfoRowCount; y++) for (int y = 0; y < this.FrameHeader.ModeInfoRowCount; y++)
{ {
this.segmentIds[y] = new int[this.FrameInfo.ModeInfoColumnCount]; this.segmentIds[y] = new int[this.FrameHeader.ModeInfoColumnCount];
} }
// reallocate_parse_context_memory // reallocate_parse_context_memory
@ -57,28 +58,28 @@ internal class Av1TileReader : IAv1TileReader
this.aboveNeighborContext = new Av1ParseAboveNeighbor4x4Context(planesCount, modeInfoWideColumnCount); this.aboveNeighborContext = new Av1ParseAboveNeighbor4x4Context(planesCount, modeInfoWideColumnCount);
this.leftNeighborContext = new Av1ParseLeftNeighbor4x4Context(planesCount, sequenceHeader.SuperblockModeInfoSize); this.leftNeighborContext = new Av1ParseLeftNeighbor4x4Context(planesCount, sequenceHeader.SuperblockModeInfoSize);
this.transformUnitCount = new int[Av1Constants.MaxPlanes][]; this.transformUnitCount = new int[Av1Constants.MaxPlanes][];
this.transformUnitCount[0] = new int[this.FrameBuffer.ModeInfoCount]; this.transformUnitCount[0] = new int[this.FrameInfo.ModeInfoCount];
this.transformUnitCount[1] = new int[this.FrameBuffer.ModeInfoCount]; this.transformUnitCount[1] = new int[this.FrameInfo.ModeInfoCount];
this.transformUnitCount[2] = new int[this.FrameBuffer.ModeInfoCount]; this.transformUnitCount[2] = new int[this.FrameInfo.ModeInfoCount];
this.coefficientIndex = new int[Av1Constants.MaxPlanes]; this.coefficientIndex = new int[Av1Constants.MaxPlanes];
} }
public ObuFrameHeader FrameInfo { get; } public ObuFrameHeader FrameHeader { get; }
public ObuSequenceHeader SequenceHeader { get; } public ObuSequenceHeader SequenceHeader { get; }
public Av1FrameBuffer FrameBuffer { get; } public Av1FrameInfo FrameInfo { get; }
public void ReadTile(Span<byte> tileData, int tileNum) public void ReadTile(Span<byte> tileData, int tileNum)
{ {
Av1SymbolDecoder reader = new(tileData, this.FrameInfo.QuantizationParameters.BaseQIndex); Av1SymbolDecoder reader = new(tileData, this.FrameHeader.QuantizationParameters.BaseQIndex);
int tileColumnIndex = tileNum % this.FrameInfo.TilesInfo.TileColumnCount; int tileColumnIndex = tileNum % this.FrameHeader.TilesInfo.TileColumnCount;
int tileRowIndex = tileNum / this.FrameInfo.TilesInfo.TileColumnCount; int tileRowIndex = tileNum / this.FrameHeader.TilesInfo.TileColumnCount;
int modeInfoColumnStart = this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex]; int modeInfoColumnStart = this.FrameHeader.TilesInfo.TileColumnStartModeInfo[tileColumnIndex];
int modeInfoColumnEnd = this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1]; int modeInfoColumnEnd = this.FrameHeader.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1];
int modeInfoRowStart = this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex]; int modeInfoRowStart = this.FrameHeader.TilesInfo.TileRowStartModeInfo[tileRowIndex];
int modeInfoRowEnd = this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex + 1]; int modeInfoRowEnd = this.FrameHeader.TilesInfo.TileRowStartModeInfo[tileRowIndex + 1];
this.aboveNeighborContext.Clear(this.SequenceHeader, modeInfoColumnStart, modeInfoColumnEnd); this.aboveNeighborContext.Clear(this.SequenceHeader, modeInfoColumnStart, modeInfoColumnEnd);
this.ClearLoopFilterDelta(); this.ClearLoopFilterDelta();
int planesCount = this.SequenceHeader.ColorConfig.PlaneCount; int planesCount = this.SequenceHeader.ColorConfig.PlaneCount;
@ -98,7 +99,7 @@ internal class Av1TileReader : IAv1TileReader
} }
} }
Av1TileInfo tileInfo = new(tileRowIndex, tileColumnIndex, this.FrameInfo); Av1TileInfo tileInfo = new(tileRowIndex, tileColumnIndex, this.FrameHeader);
Av1BlockSize superBlockSize = this.SequenceHeader.SuperblockSize; Av1BlockSize superBlockSize = this.SequenceHeader.SuperblockSize;
int superBlock4x4Size = this.SequenceHeader.SuperblockSizeLog2; int superBlock4x4Size = this.SequenceHeader.SuperblockSizeLog2;
for (int row = modeInfoRowStart; row < modeInfoRowEnd; row += superBlock4x4Size) for (int row = modeInfoRowStart; row < modeInfoRowEnd; row += superBlock4x4Size)
@ -109,10 +110,10 @@ internal class Av1TileReader : IAv1TileReader
{ {
int superBlockColumn = (column << Av1Constants.ModeInfoSizeLog2) >> superBlock4x4Size; int superBlockColumn = (column << Av1Constants.ModeInfoSizeLog2) >> superBlock4x4Size;
Point superblockPosition = new(superBlockColumn, superBlockRow); Point superblockPosition = new(superBlockColumn, superBlockRow);
Av1SuperblockInfo superblockInfo = this.FrameBuffer.GetSuperblock(superblockPosition); Av1SuperblockInfo superblockInfo = this.FrameInfo.GetSuperblock(superblockPosition);
Point modeInfoPosition = new(column, row); Point modeInfoPosition = new(column, row);
this.FrameBuffer.ClearCdef(superblockPosition); this.FrameInfo.ClearCdef(superblockPosition);
this.firstTransformOffset[0] = 0; this.firstTransformOffset[0] = 0;
this.firstTransformOffset[1] = 0; this.firstTransformOffset[1] = 0;
this.ReadLoopRestoration(modeInfoPosition, superBlockSize); this.ReadLoopRestoration(modeInfoPosition, superBlockSize);
@ -122,14 +123,14 @@ internal class Av1TileReader : IAv1TileReader
} }
private void ClearLoopFilterDelta() private void ClearLoopFilterDelta()
=> this.FrameBuffer.ClearDeltaLoopFilter(); => this.FrameInfo.ClearDeltaLoopFilter();
private void ReadLoopRestoration(Point modeInfoLocation, Av1BlockSize superBlockSize) private void ReadLoopRestoration(Point modeInfoLocation, Av1BlockSize superBlockSize)
{ {
int planesCount = this.SequenceHeader.ColorConfig.PlaneCount; int planesCount = this.SequenceHeader.ColorConfig.PlaneCount;
for (int plane = 0; plane < planesCount; plane++) for (int plane = 0; plane < planesCount; plane++)
{ {
if (this.FrameInfo.LoopRestorationParameters.Items[plane].Type != ObuRestorationType.None) if (this.FrameHeader.LoopRestorationParameters.Items[plane].Type != ObuRestorationType.None)
{ {
// TODO: Implement. // TODO: Implement.
throw new NotImplementedException("No loop restoration filter support."); throw new NotImplementedException("No loop restoration filter support.");
@ -144,7 +145,7 @@ internal class Av1TileReader : IAv1TileReader
{ {
int columnIndex = modeInfoLocation.X; int columnIndex = modeInfoLocation.X;
int rowIndex = modeInfoLocation.Y; int rowIndex = modeInfoLocation.Y;
if (modeInfoLocation.Y >= this.FrameInfo.ModeInfoRowCount || modeInfoLocation.X >= this.FrameInfo.ModeInfoColumnCount) if (modeInfoLocation.Y >= this.FrameHeader.ModeInfoRowCount || modeInfoLocation.X >= this.FrameHeader.ModeInfoColumnCount)
{ {
return; return;
} }
@ -152,8 +153,8 @@ internal class Av1TileReader : IAv1TileReader
int block4x4Size = blockSize.Get4x4WideCount(); int block4x4Size = blockSize.Get4x4WideCount();
int halfBlock4x4Size = block4x4Size >> 1; int halfBlock4x4Size = block4x4Size >> 1;
int quarterBlock4x4Size = halfBlock4x4Size >> 1; int quarterBlock4x4Size = halfBlock4x4Size >> 1;
bool hasRows = (modeInfoLocation.Y + halfBlock4x4Size) < this.FrameInfo.ModeInfoRowCount; bool hasRows = (modeInfoLocation.Y + halfBlock4x4Size) < this.FrameHeader.ModeInfoRowCount;
bool hasColumns = (modeInfoLocation.X + halfBlock4x4Size) < this.FrameInfo.ModeInfoColumnCount; bool hasColumns = (modeInfoLocation.X + halfBlock4x4Size) < this.FrameHeader.ModeInfoColumnCount;
Av1PartitionType partitionType = Av1PartitionType.None; Av1PartitionType partitionType = Av1PartitionType.None;
if (blockSize >= Av1BlockSize.Block8x8) if (blockSize >= Av1BlockSize.Block8x8)
{ {
@ -245,7 +246,7 @@ internal class Av1TileReader : IAv1TileReader
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
int currentBlockRow = rowIndex + (i * quarterBlock4x4Size); int currentBlockRow = rowIndex + (i * quarterBlock4x4Size);
if (i > 0 && currentBlockRow > this.FrameInfo.ModeInfoRowCount) if (i > 0 && currentBlockRow > this.FrameHeader.ModeInfoRowCount)
{ {
break; break;
} }
@ -259,7 +260,7 @@ internal class Av1TileReader : IAv1TileReader
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
int currentBlockColumn = columnIndex + (i * quarterBlock4x4Size); int currentBlockColumn = columnIndex + (i * quarterBlock4x4Size);
if (i > 0 && currentBlockColumn > this.FrameInfo.ModeInfoColumnCount) if (i > 0 && currentBlockColumn > this.FrameHeader.ModeInfoColumnCount)
{ {
break; break;
} }
@ -289,11 +290,12 @@ internal class Av1TileReader : IAv1TileReader
blockModeInfo.PartitionType = partitionType; blockModeInfo.PartitionType = partitionType;
blockModeInfo.FirstTransformLocation[0] = this.firstTransformOffset[0]; blockModeInfo.FirstTransformLocation[0] = this.firstTransformOffset[0];
blockModeInfo.FirstTransformLocation[1] = this.firstTransformOffset[1]; blockModeInfo.FirstTransformLocation[1] = this.firstTransformOffset[1];
bool hasChroma = this.HasChroma(modeInfoLocation, blockSize); bool hasChroma = HasChroma(this.SequenceHeader, modeInfoLocation, blockSize);
Av1PartitionInfo partitionInfo = new(blockModeInfo, superblockInfo, hasChroma, partitionType); Av1PartitionInfo partitionInfo = new(blockModeInfo, superblockInfo, hasChroma, partitionType);
partitionInfo.ColumnIndex = columnIndex; partitionInfo.ColumnIndex = columnIndex;
partitionInfo.RowIndex = rowIndex; partitionInfo.RowIndex = rowIndex;
partitionInfo.ComputeBoundaryOffsets(this.FrameInfo, tileInfo); superblockInfo.BlockCount++;
partitionInfo.ComputeBoundaryOffsets(this.FrameHeader, tileInfo);
if (hasChroma) if (hasChroma)
{ {
if (this.SequenceHeader.ColorConfig.SubSamplingY && block4x4Height == 1) if (this.SequenceHeader.ColorConfig.SubSamplingY && block4x4Height == 1)
@ -328,7 +330,7 @@ internal class Av1TileReader : IAv1TileReader
this.Residual(ref reader, partitionInfo, superblockInfo, tileInfo, blockSize); this.Residual(ref reader, partitionInfo, superblockInfo, tileInfo, blockSize);
// Update the Frame buffer for this ModeInfo. // Update the Frame buffer for this ModeInfo.
this.FrameBuffer.UpdateModeInfo(blockModeInfo, superblockInfo); this.FrameInfo.UpdateModeInfo(blockModeInfo, superblockInfo);
} }
private void ResetSkipContext(Av1PartitionInfo partitionInfo) private void ResetSkipContext(Av1PartitionInfo partitionInfo)
@ -342,8 +344,8 @@ internal class Av1TileReader : IAv1TileReader
DebugGuard.IsTrue(planeBlockSize != Av1BlockSize.Invalid, nameof(planeBlockSize)); DebugGuard.IsTrue(planeBlockSize != Av1BlockSize.Invalid, nameof(planeBlockSize));
int txsWide = planeBlockSize.GetWidth() >> 2; int txsWide = planeBlockSize.GetWidth() >> 2;
int txsHigh = planeBlockSize.GetHeight() >> 2; int txsHigh = planeBlockSize.GetHeight() >> 2;
int aboveOffset = (partitionInfo.ColumnIndex - this.FrameInfo.TilesInfo.TileColumnStartModeInfo[partitionInfo.ColumnIndex]) >> subX; int aboveOffset = (partitionInfo.ColumnIndex - this.FrameHeader.TilesInfo.TileColumnStartModeInfo[partitionInfo.ColumnIndex]) >> subX;
int leftOffset = (partitionInfo.RowIndex - this.FrameInfo.TilesInfo.TileRowStartModeInfo[partitionInfo.RowIndex]) >> subY; int leftOffset = (partitionInfo.RowIndex - this.FrameHeader.TilesInfo.TileRowStartModeInfo[partitionInfo.RowIndex]) >> subY;
this.aboveNeighborContext.ClearContext(i, aboveOffset, txsWide); this.aboveNeighborContext.ClearContext(i, aboveOffset, txsWide);
this.leftNeighborContext.ClearContext(i, leftOffset, txsHigh); this.leftNeighborContext.ClearContext(i, leftOffset, txsHigh);
} }
@ -362,7 +364,7 @@ internal class Av1TileReader : IAv1TileReader
modeUnitBlocksWide = Math.Min(maxBlocksWide, modeUnitBlocksWide); modeUnitBlocksWide = Math.Min(maxBlocksWide, modeUnitBlocksWide);
modeUnitBlocksHigh = Math.Min(maxBlocksHigh, modeUnitBlocksHigh); modeUnitBlocksHigh = Math.Min(maxBlocksHigh, modeUnitBlocksHigh);
int planeCount = this.SequenceHeader.ColorConfig.PlaneCount; int planeCount = this.SequenceHeader.ColorConfig.PlaneCount;
bool isLossless = this.FrameInfo.LosslessArray[partitionInfo.ModeInfo.SegmentId]; bool isLossless = this.FrameHeader.LosslessArray[partitionInfo.ModeInfo.SegmentId];
bool isLosslessBlock = isLossless && (blockSize >= Av1BlockSize.Block64x64) && (blockSize <= Av1BlockSize.Block128x128); bool isLosslessBlock = isLossless && (blockSize >= Av1BlockSize.Block64x64) && (blockSize <= Av1BlockSize.Block128x128);
int subSampling = (this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0) + (this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0); int subSampling = (this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0) + (this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0);
int chromaTransformUnitCount = isLosslessBlock ? ((maxBlocksWide * maxBlocksHigh) >> subSampling) : partitionInfo.ModeInfo.TransformUnitsCount[(int)Av1PlaneType.Uv]; int chromaTransformUnitCount = isLosslessBlock ? ((maxBlocksWide * maxBlocksHigh) >> subSampling) : partitionInfo.ModeInfo.TransformUnitsCount[(int)Av1PlaneType.Uv];
@ -389,13 +391,13 @@ internal class Av1TileReader : IAv1TileReader
continue; continue;
} }
Span<Av1TransformInfo> transformInfos = plane == 0 ? superblockInfo.GetTransformInfoY() : superblockInfo.GetTransformInfoUv(); ref Av1TransformInfo transformInfoRef = ref (plane == 0) ? ref superblockInfo.GetTransformInfoY() : ref superblockInfo.GetTransformInfoUv();
if (isLosslessBlock) if (isLosslessBlock)
{ {
// TODO: Implement. // TODO: Implement.
int unitHeight = Av1Math.RoundPowerOf2(Math.Min(modeUnitBlocksHigh + row, maxBlocksHigh), 0); int unitHeight = Av1Math.RoundPowerOf2(Math.Min(modeUnitBlocksHigh + row, maxBlocksHigh), 0);
int unitWidth = Av1Math.RoundPowerOf2(Math.Min(modeUnitBlocksWide + column, maxBlocksWide), 0); int unitWidth = Av1Math.RoundPowerOf2(Math.Min(modeUnitBlocksWide + column, maxBlocksWide), 0);
DebugGuard.IsTrue(transformInfos[transformInfoIndices[plane]].Size == Av1TransformSize.Size4x4, "Lossless frame shall have transform units of size 4x4."); DebugGuard.IsTrue(Unsafe.Add(ref transformInfoRef, transformInfoIndices[plane]).Size == Av1TransformSize.Size4x4, "Lossless frame shall have transform units of size 4x4.");
transformUnitCount = ((unitWidth - column) * (unitHeight - row)) >> (subX + subY); transformUnitCount = ((unitWidth - column) * (unitHeight - row)) >> (subX + subY);
} }
else else
@ -415,7 +417,7 @@ internal class Av1TileReader : IAv1TileReader
DebugGuard.IsFalse(transformUnitCount == 0, nameof(transformUnitCount), string.Empty); DebugGuard.IsFalse(transformUnitCount == 0, nameof(transformUnitCount), string.Empty);
for (int tu = 0; tu < transformUnitCount; tu++) for (int tu = 0; tu < transformUnitCount; tu++)
{ {
Av1TransformInfo transformInfo = transformInfos[transformInfoIndices[plane]]; Av1TransformInfo transformInfo = Unsafe.Add(ref transformInfoRef, transformInfoIndices[plane]);
DebugGuard.MustBeLessThanOrEqualTo(transformInfo.OffsetX, maxBlocksWide, nameof(transformInfo)); DebugGuard.MustBeLessThanOrEqualTo(transformInfo.OffsetX, maxBlocksWide, nameof(transformInfo));
DebugGuard.MustBeLessThanOrEqualTo(transformInfo.OffsetY, maxBlocksHigh, nameof(transformInfo)); DebugGuard.MustBeLessThanOrEqualTo(transformInfo.OffsetY, maxBlocksHigh, nameof(transformInfo));
@ -426,8 +428,8 @@ internal class Av1TileReader : IAv1TileReader
int startX = (partitionInfo.ColumnIndex >> subX) + blockColumn; int startX = (partitionInfo.ColumnIndex >> subX) + blockColumn;
int startY = (partitionInfo.RowIndex >> subY) + blockRow; int startY = (partitionInfo.RowIndex >> subY) + blockRow;
if (startX >= (this.FrameInfo.ModeInfoColumnCount >> subX) || if (startX >= (this.FrameHeader.ModeInfoColumnCount >> subX) ||
startY >= (this.FrameInfo.ModeInfoRowCount >> subY)) startY >= (this.FrameHeader.ModeInfoRowCount >> subY))
{ {
return; return;
} }
@ -456,12 +458,12 @@ internal class Av1TileReader : IAv1TileReader
} }
} }
private bool HasChroma(Point modeInfoLocation, Av1BlockSize blockSize) public static bool HasChroma(ObuSequenceHeader sequenceHeader, Point modeInfoLocation, Av1BlockSize blockSize)
{ {
int blockWide = blockSize.Get4x4WideCount(); int blockWide = blockSize.Get4x4WideCount();
int blockHigh = blockSize.Get4x4HighCount(); int blockHigh = blockSize.Get4x4HighCount();
bool subX = this.SequenceHeader.ColorConfig.SubSamplingX; bool subX = sequenceHeader.ColorConfig.SubSamplingX;
bool subY = this.SequenceHeader.ColorConfig.SubSamplingY; bool subY = sequenceHeader.ColorConfig.SubSamplingY;
bool hasChroma = ((modeInfoLocation.Y & 0x01) != 0 || (blockHigh & 0x01) == 0 || !subY) && bool hasChroma = ((modeInfoLocation.Y & 0x01) != 0 || (blockHigh & 0x01) == 0 || !subY) &&
((modeInfoLocation.X & 0x01) != 0 || (blockWide & 0x01) == 0 || !subX); ((modeInfoLocation.X & 0x01) != 0 || (blockWide & 0x01) == 0 || !subX);
return hasChroma; return hasChroma;
@ -534,7 +536,7 @@ internal class Av1TileReader : IAv1TileReader
/// </remarks> /// </remarks>
private int ParseCoefficients(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, int blockRow, int blockColumn, int aboveOffset, int leftOffset, int plane, Av1TransformBlockContext transformBlockContext, Av1TransformSize transformSize, int coefficientIndex, Av1TransformInfo transformInfo) private int ParseCoefficients(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, int blockRow, int blockColumn, int aboveOffset, int leftOffset, int plane, Av1TransformBlockContext transformBlockContext, Av1TransformSize transformSize, int coefficientIndex, Av1TransformInfo transformInfo)
{ {
Span<int> coefficientBuffer = this.FrameBuffer.GetCoefficients(plane); Span<int> coefficientBuffer = this.FrameInfo.GetCoefficients(plane);
int width = transformSize.GetWidth(); int width = transformSize.GetWidth();
int height = transformSize.GetHeight(); int height = transformSize.GetHeight();
Av1TransformSize transformSizeContext = (Av1TransformSize)(((int)transformSize.GetSquareSize() + ((int)transformSize.GetSquareUpSize() + 1)) >> 1); Av1TransformSize transformSizeContext = (Av1TransformSize)(((int)transformSize.GetSquareSize() + ((int)transformSize.GetSquareUpSize() + 1)) >> 1);
@ -955,7 +957,7 @@ internal class Av1TileReader : IAv1TileReader
private Av1TransformType ComputeTransformType(Av1PlaneType planeType, Av1PartitionInfo partitionInfo, Av1TransformSize transformSize, Av1TransformInfo transformInfo) private Av1TransformType ComputeTransformType(Av1PlaneType planeType, Av1PartitionInfo partitionInfo, Av1TransformSize transformSize, Av1TransformInfo transformInfo)
{ {
Av1TransformType transformType = Av1TransformType.DctDct; Av1TransformType transformType = Av1TransformType.DctDct;
if (this.FrameInfo.LosslessArray[partitionInfo.ModeInfo.SegmentId] || transformSize.GetSquareUpSize() > Av1TransformSize.Size32x32) if (this.FrameHeader.LosslessArray[partitionInfo.ModeInfo.SegmentId] || transformSize.GetSquareUpSize() > Av1TransformSize.Size32x32)
{ {
transformType = Av1TransformType.DctDct; transformType = Av1TransformType.DctDct;
} }
@ -973,7 +975,7 @@ internal class Av1TileReader : IAv1TileReader
} }
} }
Av1TransformSetType transformSetType = GetExtendedTransformSetType(transformSize, this.FrameInfo.UseReducedTransformSet); Av1TransformSetType transformSetType = GetExtendedTransformSetType(transformSize, this.FrameHeader.UseReducedTransformSet);
if (!transformType.IsExtendedSetUsed(transformSetType)) if (!transformType.IsExtendedSetUsed(transformSetType))
{ {
transformType = Av1TransformType.DctDct; transformType = Av1TransformType.DctDct;
@ -1219,12 +1221,12 @@ internal class Av1TileReader : IAv1TileReader
private Av1TransformSize ReadTransformSize(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo, bool allowSelect) private Av1TransformSize ReadTransformSize(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo, bool allowSelect)
{ {
Av1BlockModeInfo modeInfo = partitionInfo.ModeInfo; Av1BlockModeInfo modeInfo = partitionInfo.ModeInfo;
if (this.FrameInfo.LosslessArray[modeInfo.SegmentId]) if (this.FrameHeader.LosslessArray[modeInfo.SegmentId])
{ {
return Av1TransformSize.Size4x4; return Av1TransformSize.Size4x4;
} }
if (modeInfo.BlockSize > Av1BlockSize.Block4x4 && allowSelect && this.FrameInfo.TransformMode == Av1TransformMode.Select) if (modeInfo.BlockSize > Av1BlockSize.Block4x4 && allowSelect && this.FrameHeader.TransformMode == Av1TransformMode.Select)
{ {
return this.ReadSelectedTransformSize(ref reader, partitionInfo, superblockInfo, tileInfo); return this.ReadSelectedTransformSize(ref reader, partitionInfo, superblockInfo, tileInfo);
} }
@ -1283,8 +1285,8 @@ internal class Av1TileReader : IAv1TileReader
{ {
int transformInfoYIndex = partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Y]; int transformInfoYIndex = partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Y];
int transformInfoUvIndex = partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv]; int transformInfoUvIndex = partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv];
Span<Av1TransformInfo> lumaTransformInfo = superblockInfo.GetTransformInfoY(); ref Av1TransformInfo lumaTransformInfo = ref superblockInfo.GetTransformInfoY();
Span<Av1TransformInfo> chromaTransformInfo = superblockInfo.GetTransformInfoUv(); ref Av1TransformInfo chromaTransformInfo = ref superblockInfo.GetTransformInfoUv();
int totalLumaTransformUnitCount = 0; int totalLumaTransformUnitCount = 0;
int totalChromaTransformUnitCount = 0; int totalChromaTransformUnitCount = 0;
int forceSplitCount = 0; int forceSplitCount = 0;
@ -1297,7 +1299,7 @@ internal class Av1TileReader : IAv1TileReader
width = Math.Min(width, maxBlockWide); width = Math.Min(width, maxBlockWide);
height = Math.Min(height, maxBlockHigh); height = Math.Min(height, maxBlockHigh);
bool isLossLess = this.FrameInfo.LosslessArray[partitionInfo.ModeInfo.SegmentId]; bool isLossLess = this.FrameHeader.LosslessArray[partitionInfo.ModeInfo.SegmentId];
Av1TransformSize transformSizeUv = isLossLess ? Av1TransformSize.Size4x4 : blockSize.GetMaxUvTransformSize(subX, subY); Av1TransformSize transformSizeUv = isLossLess ? Av1TransformSize.Size4x4 : blockSize.GetMaxUvTransformSize(subX, subY);
for (int idy = 0; idy < maxBlockHigh; idy += height) for (int idy = 0; idy < maxBlockHigh; idy += height)
@ -1317,7 +1319,7 @@ internal class Av1TileReader : IAv1TileReader
{ {
for (int blockColumn = idx; blockColumn < unitWidth; blockColumn += stepColumn) for (int blockColumn = idx; blockColumn < unitWidth; blockColumn += stepColumn)
{ {
lumaTransformInfo[transformInfoYIndex] = new Av1TransformInfo( Unsafe.Add(ref lumaTransformInfo, transformInfoYIndex) = new Av1TransformInfo(
transformSize, blockColumn, blockRow); transformSize, blockColumn, blockRow);
transformInfoYIndex++; transformInfoYIndex++;
lumaTransformUnitCount++; lumaTransformUnitCount++;
@ -1342,7 +1344,7 @@ internal class Av1TileReader : IAv1TileReader
{ {
for (int blockColumn = idx; blockColumn < unitWidth; blockColumn += stepColumn) for (int blockColumn = idx; blockColumn < unitWidth; blockColumn += stepColumn)
{ {
chromaTransformInfo[transformInfoUvIndex] = new Av1TransformInfo( Unsafe.Add(ref chromaTransformInfo, transformInfoUvIndex) = new Av1TransformInfo(
transformSizeUv, blockColumn, blockRow); transformSizeUv, blockColumn, blockRow);
transformInfoUvIndex++; transformInfoUvIndex++;
chromaTransformUnitCount++; chromaTransformUnitCount++;
@ -1363,9 +1365,13 @@ internal class Av1TileReader : IAv1TileReader
partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv], partitionInfo.ModeInfo.FirstTransformLocation[(int)Av1PlaneType.Uv],
nameof(totalChromaTransformUnitCount)); nameof(totalChromaTransformUnitCount));
int originalIndex = transformInfoUvIndex - totalChromaTransformUnitCount; int originalIndex = transformInfoUvIndex - totalChromaTransformUnitCount;
ref Av1TransformInfo originalInfo = ref Unsafe.Add(ref chromaTransformInfo, originalIndex);
ref Av1TransformInfo infoV = ref Unsafe.Add(ref chromaTransformInfo, transformInfoUvIndex);
for (int i = 0; i < totalChromaTransformUnitCount; i++) for (int i = 0; i < totalChromaTransformUnitCount; i++)
{ {
chromaTransformInfo[transformInfoUvIndex + i] = chromaTransformInfo[originalIndex + i]; infoV = originalInfo;
originalInfo = ref Unsafe.Add(ref originalInfo, 1);
infoV = ref Unsafe.Add(ref infoV, 1);
} }
} }
@ -1399,7 +1405,7 @@ internal class Av1TileReader : IAv1TileReader
/// </summary> /// </summary>
private void ReadModeInfo(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private void ReadModeInfo(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
DebugGuard.IsTrue(this.FrameInfo.FrameType is ObuFrameType.KeyFrame or ObuFrameType.IntraOnlyFrame, "Only INTRA frames supported."); DebugGuard.IsTrue(this.FrameHeader.FrameType is ObuFrameType.KeyFrame or ObuFrameType.IntraOnlyFrame, "Only INTRA frames supported.");
this.ReadIntraFrameModeInfo(ref reader, partitionInfo); this.ReadIntraFrameModeInfo(ref reader, partitionInfo);
} }
@ -1408,21 +1414,21 @@ internal class Av1TileReader : IAv1TileReader
/// </summary> /// </summary>
private void ReadIntraFrameModeInfo(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private void ReadIntraFrameModeInfo(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
if (this.FrameInfo.SegmentationParameters.SegmentIdPrecedesSkip) if (this.FrameHeader.SegmentationParameters.SegmentIdPrecedesSkip)
{ {
this.IntraSegmentId(ref reader, partitionInfo); this.IntraSegmentId(ref reader, partitionInfo);
} }
// this.skipMode = false; // this.skipMode = false;
partitionInfo.ModeInfo.Skip = this.ReadSkip(ref reader, partitionInfo); partitionInfo.ModeInfo.Skip = this.ReadSkip(ref reader, partitionInfo);
if (!this.FrameInfo.SegmentationParameters.SegmentIdPrecedesSkip) if (!this.FrameHeader.SegmentationParameters.SegmentIdPrecedesSkip)
{ {
this.IntraSegmentId(ref reader, partitionInfo); this.IntraSegmentId(ref reader, partitionInfo);
} }
this.ReadCdef(ref reader, partitionInfo); this.ReadCdef(ref reader, partitionInfo);
if (this.FrameInfo.DeltaQParameters.IsPresent) if (this.FrameHeader.DeltaQParameters.IsPresent)
{ {
this.ReadDeltaQuantizerIndex(ref reader, partitionInfo); this.ReadDeltaQuantizerIndex(ref reader, partitionInfo);
this.ReadDeltaLoopFilter(ref reader, partitionInfo); this.ReadDeltaLoopFilter(ref reader, partitionInfo);
@ -1468,7 +1474,7 @@ internal class Av1TileReader : IAv1TileReader
if (partitionInfo.ModeInfo.BlockSize >= Av1BlockSize.Block8x8 && if (partitionInfo.ModeInfo.BlockSize >= Av1BlockSize.Block8x8 &&
partitionInfo.ModeInfo.BlockSize.GetWidth() <= 64 && partitionInfo.ModeInfo.BlockSize.GetWidth() <= 64 &&
partitionInfo.ModeInfo.BlockSize.GetHeight() <= 64 && partitionInfo.ModeInfo.BlockSize.GetHeight() <= 64 &&
this.FrameInfo.AllowScreenContentTools) this.FrameHeader.AllowScreenContentTools)
{ {
this.PaletteModeInfo(ref reader, partitionInfo); this.PaletteModeInfo(ref reader, partitionInfo);
} }
@ -1478,13 +1484,13 @@ internal class Av1TileReader : IAv1TileReader
} }
private bool AllowIntraBlockCopy() private bool AllowIntraBlockCopy()
=> (this.FrameInfo.FrameType is ObuFrameType.KeyFrame or ObuFrameType.IntraOnlyFrame) && => (this.FrameHeader.FrameType is ObuFrameType.KeyFrame or ObuFrameType.IntraOnlyFrame) &&
(this.SequenceHeader.ForceScreenContentTools > 0) && (this.SequenceHeader.ForceScreenContentTools > 0) &&
this.FrameInfo.AllowIntraBlockCopy; this.FrameHeader.AllowIntraBlockCopy;
private bool IsChromaForLumaAllowed(Av1PartitionInfo partitionInfo) private bool IsChromaForLumaAllowed(Av1PartitionInfo partitionInfo)
{ {
if (this.FrameInfo.LosslessArray[partitionInfo.ModeInfo.SegmentId]) if (this.FrameHeader.LosslessArray[partitionInfo.ModeInfo.SegmentId])
{ {
// In lossless, CfL is available when the partition size is equal to the // In lossless, CfL is available when the partition size is equal to the
// transform size. // transform size.
@ -1569,15 +1575,15 @@ internal class Av1TileReader : IAv1TileReader
/// </summary> /// </summary>
private void IntraSegmentId(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private void IntraSegmentId(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
if (this.FrameInfo.SegmentationParameters.Enabled) if (this.FrameHeader.SegmentationParameters.Enabled)
{ {
this.ReadSegmentId(ref reader, partitionInfo); this.ReadSegmentId(ref reader, partitionInfo);
} }
int blockWidth4x4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount(); int blockWidth4x4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount();
int blockHeight4x4 = partitionInfo.ModeInfo.BlockSize.Get4x4HighCount(); int blockHeight4x4 = partitionInfo.ModeInfo.BlockSize.Get4x4HighCount();
int modeInfoCountX = Math.Min(this.FrameInfo.ModeInfoColumnCount - partitionInfo.ColumnIndex, blockWidth4x4); int modeInfoCountX = Math.Min(this.FrameHeader.ModeInfoColumnCount - partitionInfo.ColumnIndex, blockWidth4x4);
int modeInfoCountY = Math.Min(this.FrameInfo.ModeInfoRowCount - partitionInfo.RowIndex, blockHeight4x4); int modeInfoCountY = Math.Min(this.FrameHeader.ModeInfoRowCount - partitionInfo.RowIndex, blockHeight4x4);
int segmentId = partitionInfo.ModeInfo.SegmentId; int segmentId = partitionInfo.ModeInfo.SegmentId;
for (int y = 0; y < modeInfoCountY; y++) for (int y = 0; y < modeInfoCountY; y++)
{ {
@ -1637,18 +1643,18 @@ internal class Av1TileReader : IAv1TileReader
int ctx = prevUL < 0 ? 0 /* Edge cases */ int ctx = prevUL < 0 ? 0 /* Edge cases */
: prevUL == prevU && prevUL == prevL ? 2 : prevUL == prevU && prevUL == prevL ? 2
: prevUL == prevU || prevUL == prevL || prevU == prevL ? 1 : 0; : prevUL == prevU || prevUL == prevL || prevU == prevL ? 1 : 0;
int lastActiveSegmentId = this.FrameInfo.SegmentationParameters.LastActiveSegmentId; int lastActiveSegmentId = this.FrameHeader.SegmentationParameters.LastActiveSegmentId;
partitionInfo.ModeInfo.SegmentId = NegativeDeinterleave(reader.ReadSegmentId(ctx), predictor, lastActiveSegmentId + 1); partitionInfo.ModeInfo.SegmentId = NegativeDeinterleave(reader.ReadSegmentId(ctx), predictor, lastActiveSegmentId + 1);
} }
} }
private int GetSegmentId(Av1PartitionInfo partitionInfo, int rowIndex, int columnIndex) private int GetSegmentId(Av1PartitionInfo partitionInfo, int rowIndex, int columnIndex)
{ {
int modeInfoOffset = (rowIndex * this.FrameInfo.ModeInfoColumnCount) + columnIndex; int modeInfoOffset = (rowIndex * this.FrameHeader.ModeInfoColumnCount) + columnIndex;
int bw4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount(); int bw4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount();
int bh4 = partitionInfo.ModeInfo.BlockSize.Get4x4HighCount(); int bh4 = partitionInfo.ModeInfo.BlockSize.Get4x4HighCount();
int xMin = Math.Min(this.FrameInfo.ModeInfoColumnCount - columnIndex, bw4); int xMin = Math.Min(this.FrameHeader.ModeInfoColumnCount - columnIndex, bw4);
int yMin = Math.Min(this.FrameInfo.ModeInfoRowCount - rowIndex, bh4); int yMin = Math.Min(this.FrameHeader.ModeInfoRowCount - rowIndex, bh4);
int segmentId = Av1Constants.MaxSegments - 1; int segmentId = Av1Constants.MaxSegments - 1;
for (int y = 0; y < yMin; y++) for (int y = 0; y < yMin; y++)
{ {
@ -1712,7 +1718,7 @@ internal class Av1TileReader : IAv1TileReader
/// </summary> /// </summary>
private void ReadCdef(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private void ReadCdef(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
if (partitionInfo.ModeInfo.Skip || this.FrameInfo.CodedLossless || !this.SequenceHeader.EnableCdef || this.FrameInfo.AllowIntraBlockCopy) if (partitionInfo.ModeInfo.Skip || this.FrameHeader.CodedLossless || !this.SequenceHeader.EnableCdef || this.FrameHeader.AllowIntraBlockCopy)
{ {
return; return;
} }
@ -1723,7 +1729,7 @@ internal class Av1TileReader : IAv1TileReader
int c = partitionInfo.ColumnIndex & cdefMask4; int c = partitionInfo.ColumnIndex & cdefMask4;
if (partitionInfo.CdefStrength[r][c] == -1) if (partitionInfo.CdefStrength[r][c] == -1)
{ {
partitionInfo.CdefStrength[r][c] = reader.ReadLiteral(this.FrameInfo.CdefParameters.BitCount); partitionInfo.CdefStrength[r][c] = reader.ReadLiteral(this.FrameHeader.CdefParameters.BitCount);
if (this.SequenceHeader.SuperblockSize == Av1BlockSize.Block128x128) if (this.SequenceHeader.SuperblockSize == Av1BlockSize.Block128x128)
{ {
int w4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount(); int w4 = partitionInfo.ModeInfo.BlockSize.Get4x4WideCount();
@ -1742,16 +1748,16 @@ internal class Av1TileReader : IAv1TileReader
private void ReadDeltaLoopFilter(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private void ReadDeltaLoopFilter(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128Superblock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64; Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128Superblock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64;
if (this.FrameInfo.DeltaLoopFilterParameters.IsPresent || if (this.FrameHeader.DeltaLoopFilterParameters.IsPresent ||
(partitionInfo.ModeInfo.BlockSize == superBlockSize && partitionInfo.ModeInfo.Skip)) (partitionInfo.ModeInfo.BlockSize == superBlockSize && partitionInfo.ModeInfo.Skip))
{ {
return; return;
} }
if (this.FrameInfo.DeltaLoopFilterParameters.IsPresent) if (this.FrameHeader.DeltaLoopFilterParameters.IsPresent)
{ {
int frameLoopFilterCount = 1; int frameLoopFilterCount = 1;
if (this.FrameInfo.DeltaLoopFilterParameters.IsMulti) if (this.FrameHeader.DeltaLoopFilterParameters.IsMulti)
{ {
frameLoopFilterCount = this.SequenceHeader.ColorConfig.PlaneCount > 1 ? Av1Constants.FrameLoopFilterCount : Av1Constants.FrameLoopFilterCount - 2; frameLoopFilterCount = this.SequenceHeader.ColorConfig.PlaneCount > 1 ? Av1Constants.FrameLoopFilterCount : Av1Constants.FrameLoopFilterCount - 2;
} }
@ -1771,7 +1777,7 @@ internal class Av1TileReader : IAv1TileReader
{ {
bool deltaLoopFilterSign = reader.ReadLiteral(1) > 0; bool deltaLoopFilterSign = reader.ReadLiteral(1) > 0;
int reducedDeltaLoopFilterLevel = deltaLoopFilterSign ? -deltaLoopFilterAbsolute : deltaLoopFilterAbsolute; int reducedDeltaLoopFilterLevel = deltaLoopFilterSign ? -deltaLoopFilterAbsolute : deltaLoopFilterAbsolute;
int deltaLoopFilterResolution = this.FrameInfo.DeltaLoopFilterParameters.Resolution; int deltaLoopFilterResolution = this.FrameHeader.DeltaLoopFilterParameters.Resolution;
currentDeltaLoopFilter[i] = Av1Math.Clip3(-Av1Constants.MaxLoopFilter, Av1Constants.MaxLoopFilter, currentDeltaLoopFilter[i] + (reducedDeltaLoopFilterLevel << deltaLoopFilterResolution)); currentDeltaLoopFilter[i] = Av1Math.Clip3(-Av1Constants.MaxLoopFilter, Av1Constants.MaxLoopFilter, currentDeltaLoopFilter[i] + (reducedDeltaLoopFilterLevel << deltaLoopFilterResolution));
} }
} }
@ -1781,8 +1787,8 @@ internal class Av1TileReader : IAv1TileReader
private bool ReadSkip(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private bool ReadSkip(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
int segmentId = partitionInfo.ModeInfo.SegmentId; int segmentId = partitionInfo.ModeInfo.SegmentId;
if (this.FrameInfo.SegmentationParameters.SegmentIdPrecedesSkip && if (this.FrameHeader.SegmentationParameters.SegmentIdPrecedesSkip &&
this.FrameInfo.SegmentationParameters.IsFeatureActive(segmentId, ObuSegmentationLevelFeature.Skip)) this.FrameHeader.SegmentationParameters.IsFeatureActive(segmentId, ObuSegmentationLevelFeature.Skip))
{ {
return true; return true;
} }
@ -1797,7 +1803,7 @@ internal class Av1TileReader : IAv1TileReader
private void ReadDeltaQuantizerIndex(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) private void ReadDeltaQuantizerIndex(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo)
{ {
Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128Superblock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64; Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128Superblock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64;
if (!this.FrameInfo.DeltaQParameters.IsPresent || if (!this.FrameHeader.DeltaQParameters.IsPresent ||
(partitionInfo.ModeInfo.BlockSize == superBlockSize && partitionInfo.ModeInfo.Skip)) (partitionInfo.ModeInfo.BlockSize == superBlockSize && partitionInfo.ModeInfo.Skip))
{ {
return; return;
@ -1817,7 +1823,7 @@ internal class Av1TileReader : IAv1TileReader
{ {
bool deltaQuantizerSignBit = reader.ReadLiteral(1) > 0; bool deltaQuantizerSignBit = reader.ReadLiteral(1) > 0;
int reducedDeltaQuantizerIndex = deltaQuantizerSignBit ? -deltaQuantizerAbsolute : deltaQuantizerAbsolute; int reducedDeltaQuantizerIndex = deltaQuantizerSignBit ? -deltaQuantizerAbsolute : deltaQuantizerAbsolute;
int deltaQuantizerResolution = this.FrameInfo.DeltaQParameters.Resolution; int deltaQuantizerResolution = this.FrameHeader.DeltaQParameters.Resolution;
this.currentQuantizerIndex = Av1Math.Clip3(1, 255, this.currentQuantizerIndex + (reducedDeltaQuantizerIndex << deltaQuantizerResolution)); this.currentQuantizerIndex = Av1Math.Clip3(1, 255, this.currentQuantizerIndex + (reducedDeltaQuantizerIndex << deltaQuantizerResolution));
partitionInfo.SuperblockInfo.SuperblockDeltaQ = this.currentQuantizerIndex; partitionInfo.SuperblockInfo.SuperblockDeltaQ = this.currentQuantizerIndex;
} }
@ -1825,10 +1831,10 @@ internal class Av1TileReader : IAv1TileReader
} }
private bool IsInside(int rowIndex, int columnIndex) => private bool IsInside(int rowIndex, int columnIndex) =>
columnIndex >= this.FrameInfo.TilesInfo.TileColumnCount && columnIndex >= this.FrameHeader.TilesInfo.TileColumnCount &&
columnIndex < this.FrameInfo.TilesInfo.TileColumnCount && columnIndex < this.FrameHeader.TilesInfo.TileColumnCount &&
rowIndex >= this.FrameInfo.TilesInfo.TileRowCount && rowIndex >= this.FrameHeader.TilesInfo.TileRowCount &&
rowIndex < this.FrameInfo.TilesInfo.TileRowCount; rowIndex < this.FrameHeader.TilesInfo.TileRowCount;
/* /*
private static bool IsChroma(int rowIndex, int columnIndex, Av1BlockModeInfo blockMode, bool subSamplingX, bool subSamplingY) private static bool IsChroma(int rowIndex, int columnIndex, Av1BlockModeInfo blockMode, bool subSamplingX, bool subSamplingY)

8
src/ImageSharp/Formats/Heif/Av1/Transform/Av1FrameDecoder.cs

@ -10,20 +10,20 @@ internal class Av1FrameDecoder
{ {
private readonly ObuSequenceHeader sequenceHeader; private readonly ObuSequenceHeader sequenceHeader;
private readonly ObuFrameHeader frameHeader; private readonly ObuFrameHeader frameHeader;
private readonly Av1FrameBuffer frameBuffer; private readonly Av1FrameInfo frameInfo;
public Av1FrameDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, Av1FrameBuffer frameBuffer) public Av1FrameDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, Av1FrameInfo frameInfo)
{ {
this.sequenceHeader = sequenceHeader; this.sequenceHeader = sequenceHeader;
this.frameHeader = frameHeader; this.frameHeader = frameHeader;
this.frameBuffer = frameBuffer; this.frameInfo = frameInfo;
} }
public void DecodeFrame() public void DecodeFrame()
{ {
Guard.NotNull(this.sequenceHeader); Guard.NotNull(this.sequenceHeader);
Guard.NotNull(this.frameHeader); Guard.NotNull(this.frameHeader);
Guard.NotNull(this.frameBuffer); Guard.NotNull(this.frameInfo);
// TODO: Implement. // TODO: Implement.
} }

1
src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseQuantizer.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;

Loading…
Cancel
Save