Browse Source

Bug fixes in OBU parsing

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
60869e1f47
  1. 2
      src/ImageSharp/Formats/Heif/Av1/Av1BitStreamReader.cs
  2. 5
      src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs
  3. 2
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs
  4. 2
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuDeltaLoopFilterParameters.cs
  5. 4
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopFilterParameters.cs
  6. 122
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
  7. 2
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSegmentationParameters.cs
  8. 15
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuWriter.cs
  9. 37
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
  10. 6
      tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs

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

@ -49,7 +49,7 @@ internal ref struct Av1BitStreamReader
public uint ReadLiteral(int bitCount)
{
DebugGuard.MustBeBetweenOrEqualTo(bitCount, 0, 32, nameof(bitCount));
DebugGuard.MustBeBetweenOrEqualTo(bitCount, 1, 32, nameof(bitCount));
uint bits = (this.currentWord << this.bitOffset) >> (WordSize - bitCount);
this.bitOffset += bitCount;

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

@ -18,8 +18,6 @@ internal class Av1Decoder : IAv1TileDecoder
public ObuSequenceHeader? SequenceHeader { get; private set; }
public ObuTileGroupHeader? TilesHeader { get; private set; }
public void Decode(Span<byte> buffer)
{
Av1BitStreamReader reader = new(buffer);
@ -31,8 +29,7 @@ internal class Av1Decoder : IAv1TileDecoder
{
this.SequenceHeader = this.obuReader.SequenceHeader;
this.FrameHeader = this.obuReader.FrameHeader;
this.TilesHeader = this.obuReader.TileGroupHeader;
this.tileDecoder = new Av1TileDecoder(this.SequenceHeader!, this.FrameHeader!, this.TilesHeader!);
this.tileDecoder = new Av1TileDecoder(this.SequenceHeader!, this.FrameHeader!);
}
public void DecodeTile(Span<byte> tileData, int tileNum)

2
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs

@ -29,8 +29,6 @@ internal class ObuColorConfig
public int BitDepth { get; set; }
public bool HasSeparateUvDeltaQ { get; set; }
public Av1ColorFormat GetColorFormat()
{
Av1ColorFormat format = Av1ColorFormat.Yuv400;

2
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuDeltaLoopFilterParameters.cs

@ -9,5 +9,5 @@ internal class ObuDeltaLoopFilterParameters
public int Resolution { get; internal set; }
public bool Multi { get; internal set; }
public bool IsMulti { get; internal set; }
}

4
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopFilterParameters.cs

@ -6,4 +6,8 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuLoopFilterParameters
{
public int[] FilterLevel { get; internal set; } = new int[2];
public int FilterLevelU { get; internal set; }
public int FilterLevelV { get; internal set; }
public int SharpnessLevel { get; internal set; }
public bool ReferenceDeltaModeEnabled { get; internal set; }
}

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

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
@ -11,8 +12,6 @@ internal class ObuReader
public ObuFrameHeader? FrameHeader { get; set; }
public ObuTileGroupHeader? TileGroupHeader { get; set; }
/// <summary>
/// Decode all OBU's in a frame.
/// </summary>
@ -91,7 +90,6 @@ internal class ObuReader
throw new InvalidImageContentException("Corrupt frame");
}
this.TileGroupHeader = new();
this.ReadTileGroup(ref reader, decoder, header, out frameDecodingFinished);
if (frameDecodingFinished)
{
@ -202,8 +200,9 @@ internal class ObuReader
}
}
private static void ComputeImageSize(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
private void ComputeImageSize(ObuSequenceHeader sequenceHeader)
{
ObuFrameHeader frameInfo = this.FrameHeader!;
frameInfo.ModeInfoColumnCount = 2 * ((frameInfo.FrameSize.FrameWidth + 7) >> 3);
frameInfo.ModeInfoRowCount = 2 * ((frameInfo.FrameSize.FrameHeight + 7) >> 3);
frameInfo.ModeInfoStride = Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameWidth, Av1Constants.MaxSuperBlockSizeLog2) >> Av1Constants.ModeInfoSizeLog2;
@ -366,7 +365,7 @@ internal class ObuReader
}
}
colorConfig.HasSeparateUvDeltaQ = reader.ReadBoolean();
colorConfig.HasSeparateUvDelta = reader.ReadBoolean();
return colorConfig;
}
@ -387,8 +386,10 @@ internal class ObuReader
}
}
private static void ReadSuperResolutionParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
private void ReadSuperResolutionParameters(ref Av1BitStreamReader reader)
{
ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!;
bool useSuperResolution = false;
if (sequenceHeader.EnableSuperResolution)
{
@ -417,8 +418,9 @@ internal class ObuReader
}
}
private static void ReadRenderSize(ref Av1BitStreamReader reader, ObuFrameHeader frameInfo)
private void ReadRenderSize(ref Av1BitStreamReader reader)
{
ObuFrameHeader frameInfo = this.FrameHeader!;
bool renderSizeAndFrameSizeDifferent = reader.ReadBoolean();
if (renderSizeAndFrameSizeDifferent)
{
@ -432,8 +434,10 @@ internal class ObuReader
}
}
private static void ReadFrameSizeWithReferences(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool frameSizeOverrideFlag)
private void ReadFrameSizeWithReferences(ref Av1BitStreamReader reader, bool frameSizeOverrideFlag)
{
ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!;
bool foundReference = false;
for (int i = 0; i < Av1Constants.ReferencesPerFrame; i++)
{
@ -447,18 +451,20 @@ internal class ObuReader
if (!foundReference)
{
ReadFrameSize(ref reader, sequenceHeader, frameInfo, frameSizeOverrideFlag);
ReadRenderSize(ref reader, frameInfo);
this.ReadFrameSize(ref reader, frameSizeOverrideFlag);
this.ReadRenderSize(ref reader);
}
else
{
ReadSuperResolutionParameters(ref reader, sequenceHeader, frameInfo);
ComputeImageSize(sequenceHeader, frameInfo);
this.ReadSuperResolutionParameters(ref reader);
this.ComputeImageSize(sequenceHeader);
}
}
private static void ReadFrameSize(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool frameSizeOverrideFlag)
private void ReadFrameSize(ref Av1BitStreamReader reader, bool frameSizeOverrideFlag)
{
ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!;
if (frameSizeOverrideFlag)
{
frameInfo.FrameSize.FrameWidth = (int)reader.ReadLiteral(sequenceHeader.FrameWidthBits) + 1;
@ -470,8 +476,8 @@ internal class ObuReader
frameInfo.FrameSize.FrameHeight = sequenceHeader.MaxFrameHeight;
}
ReadSuperResolutionParameters(ref reader, sequenceHeader, frameInfo);
ComputeImageSize(sequenceHeader, frameInfo);
this.ReadSuperResolutionParameters(ref reader);
this.ComputeImageSize(sequenceHeader);
}
private static ObuTileGroupHeader ReadTileInfo(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
@ -670,11 +676,8 @@ internal class ObuReader
{
frameInfo.ReferenceValid = new bool[Av1Constants.ReferenceFrameCount];
frameInfo.ReferenceOrderHint = new bool[Av1Constants.ReferenceFrameCount];
for (int i = 0; i < Av1Constants.ReferenceFrameCount; i++)
{
frameInfo.ReferenceValid[i] = false;
frameInfo.ReferenceOrderHint[i] = false;
}
Array.Fill(frameInfo.ReferenceValid, false);
Array.Fill(frameInfo.ReferenceOrderHint, false);
}
frameInfo.DisableCdfUpdate = reader.ReadBoolean();
@ -761,7 +764,14 @@ internal class ObuReader
frameSizeOverrideFlag = reader.ReadBoolean();
}
frameInfo.OrderHint = reader.ReadLiteral(sequenceHeader.OrderHintInfo.OrderHintBits);
if (sequenceHeader.OrderHintInfo.OrderHintBits > 0)
{
frameInfo.OrderHint = reader.ReadLiteral(sequenceHeader.OrderHintInfo.OrderHintBits);
}
else
{
frameInfo.OrderHint = 0;
}
if (isIntraFrame || frameInfo.ErrorResilientMode)
{
@ -807,8 +817,8 @@ internal class ObuReader
if (isIntraFrame)
{
ReadFrameSize(ref reader, sequenceHeader, frameInfo, frameSizeOverrideFlag);
ReadRenderSize(ref reader, frameInfo);
this.ReadFrameSize(ref reader, frameSizeOverrideFlag);
this.ReadRenderSize(ref reader);
if (frameInfo.AllowScreenContentTools && frameInfo.FrameSize.RenderWidth != 0)
{
if (frameInfo.FrameSize.FrameWidth == frameInfo.FrameSize.SuperResolutionUpscaledWidth)
@ -852,6 +862,9 @@ internal class ObuReader
int tilesCount = frameInfo.TilesInfo.TileColumnCount * frameInfo.TilesInfo.TileRowCount;
frameInfo.CodedLossless = true;
frameInfo.SegmentationParameters.QMLevel[0] = new int[Av1Constants.MaxSegmentCount];
frameInfo.SegmentationParameters.QMLevel[1] = new int[Av1Constants.MaxSegmentCount];
frameInfo.SegmentationParameters.QMLevel[2] = new int[Av1Constants.MaxSegmentCount];
for (int segmentId = 0; segmentId < Av1Constants.MaxSegmentCount; segmentId++)
{
int qIndex = GetQIndex(frameInfo.SegmentationParameters, segmentId, frameInfo.QuantizationParameters.BaseQIndex);
@ -871,19 +884,24 @@ internal class ObuReader
{
if (frameInfo.LosslessArray[segmentId])
{
frameInfo.SegmentationParameters.QMLevel[0, segmentId] = 15;
frameInfo.SegmentationParameters.QMLevel[1, segmentId] = 15;
frameInfo.SegmentationParameters.QMLevel[2, segmentId] = 15;
frameInfo.SegmentationParameters.QMLevel[0][segmentId] = 15;
frameInfo.SegmentationParameters.QMLevel[1][segmentId] = 15;
frameInfo.SegmentationParameters.QMLevel[2][segmentId] = 15;
}
else
{
frameInfo.SegmentationParameters.QMLevel[0, segmentId] = frameInfo.QuantizationParameters.QMatrix[(int)Av1Plane.Y];
frameInfo.SegmentationParameters.QMLevel[1, segmentId] = frameInfo.QuantizationParameters.QMatrix[(int)Av1Plane.U];
frameInfo.SegmentationParameters.QMLevel[2, segmentId] = frameInfo.QuantizationParameters.QMatrix[(int)Av1Plane.V];
frameInfo.SegmentationParameters.QMLevel[0][segmentId] = frameInfo.QuantizationParameters.QMatrix[(int)Av1Plane.Y];
frameInfo.SegmentationParameters.QMLevel[1][segmentId] = frameInfo.QuantizationParameters.QMatrix[(int)Av1Plane.U];
frameInfo.SegmentationParameters.QMLevel[2][segmentId] = frameInfo.QuantizationParameters.QMatrix[(int)Av1Plane.V];
}
}
}
if (frameInfo.CodedLossless)
{
DebugGuard.IsFalse(frameInfo.DeltaQParameters.IsPresent, nameof(frameInfo.DeltaQParameters.IsPresent), "No Delta Q parameters are allowed for lossless frame.");
}
frameInfo.AllLossless = frameInfo.CodedLossless && frameInfo.FrameSize.FrameWidth == frameInfo.FrameSize.SuperResolutionUpscaledWidth;
ReadLoopFilterParameters(ref reader, sequenceHeader, frameInfo, planesCount);
ReadCdefParameters(ref reader, sequenceHeader, frameInfo, planesCount);
@ -896,6 +914,10 @@ internal class ObuReader
{
frameInfo.AllowWarpedMotion = false;
}
else
{
frameInfo.AllowWarpedMotion = reader.ReadBoolean();
}
frameInfo.ReducedTransformSet = reader.ReadBoolean();
ReadGlobalMotionParameters(ref reader, sequenceHeader, frameInfo, isIntraFrame);
@ -945,8 +967,7 @@ internal class ObuReader
{
ObuSequenceHeader sequenceHeader = this.SequenceHeader!;
ObuFrameHeader frameInfo = this.FrameHeader!;
ObuTileGroupHeader tileInfo = this.TileGroupHeader!;
this.TileGroupHeader = tileInfo;
ObuTileGroupHeader tileInfo = this.FrameHeader!.TilesInfo;
int tileCount = tileInfo.TileColumnCount * tileInfo.TileRowCount;
int startBitPosition = reader.BitPosition;
bool tileStartAndEndPresentFlag = false;
@ -1013,7 +1034,7 @@ internal class ObuReader
int deltaQ = 0;
if (reader.ReadBoolean())
{
deltaQ = reader.ReadSignedFromUnsigned(6);
deltaQ = reader.ReadSignedFromUnsigned(7);
}
return deltaQ;
@ -1038,7 +1059,7 @@ internal class ObuReader
{
frameInfo.DeltaLoopFilterParameters.IsPresent = false;
frameInfo.DeltaLoopFilterParameters.Resolution = 0;
frameInfo.DeltaLoopFilterParameters.Multi = false;
frameInfo.DeltaLoopFilterParameters.IsMulti = false;
if (frameInfo.DeltaQParameters.IsPresent)
{
if (!frameInfo.AllowIntraBlockCopy)
@ -1049,7 +1070,7 @@ internal class ObuReader
if (frameInfo.DeltaLoopFilterParameters.IsPresent)
{
frameInfo.DeltaLoopFilterParameters.Resolution = (int)reader.ReadLiteral(2);
frameInfo.DeltaLoopFilterParameters.Multi = reader.ReadBoolean();
frameInfo.DeltaLoopFilterParameters.IsMulti = reader.ReadBoolean();
}
}
}
@ -1062,6 +1083,11 @@ internal class ObuReader
if (planesCount > 1)
{
bool areUvDeltaDifferent = false;
if (colorInfo.HasSeparateUvDelta)
{
areUvDeltaDifferent = reader.ReadBoolean();
}
quantParams.DeltaQDc[(int)Av1Plane.U] = ReadDeltaQ(ref reader);
quantParams.DeltaQAc[(int)Av1Plane.U] = ReadDeltaQ(ref reader);
if (areUvDeltaDifferent)
@ -1088,7 +1114,7 @@ internal class ObuReader
{
quantParams.QMatrix[(int)Av1Plane.Y] = (int)reader.ReadLiteral(4);
quantParams.QMatrix[(int)Av1Plane.U] = (int)reader.ReadLiteral(4);
if (!colorInfo.HasSeparateUvDeltaQ)
if (!colorInfo.HasSeparateUvDelta)
{
quantParams.QMatrix[(int)Av1Plane.V] = quantParams.QMatrix[(int)Av1Plane.U];
}
@ -1115,14 +1141,31 @@ internal class ObuReader
private static void ReadLoopFilterParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount)
{
frameInfo.LoopFilterParameters.FilterLevel = new int[2];
if (frameInfo.CodedLossless || frameInfo.AllowIntraBlockCopy)
{
frameInfo.LoopFilterParameters.FilterLevel[0] = 0;
frameInfo.LoopFilterParameters.FilterLevel[1] = 0;
return;
}
// TODO: Parse more stuff.
frameInfo.LoopFilterParameters.FilterLevel[0] = (int)reader.ReadLiteral(6);
frameInfo.LoopFilterParameters.FilterLevel[1] = (int)reader.ReadLiteral(6);
if (planesCount > 1)
{
if (frameInfo.LoopFilterParameters.FilterLevel[0] > 0 || frameInfo.LoopFilterParameters.FilterLevel[1] > 0)
{
frameInfo.LoopFilterParameters.FilterLevelU = (int)reader.ReadLiteral(6);
frameInfo.LoopFilterParameters.FilterLevelV = (int)reader.ReadLiteral(6);
}
}
frameInfo.LoopFilterParameters.SharpnessLevel = (int)reader.ReadLiteral(3);
frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled = reader.ReadBoolean();
if (frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled)
{
// TODO: Implement.
throw new NotImplementedException();
}
}
private static void ReadTransformMode(ref Av1BitStreamReader reader, ObuFrameHeader frameInfo)
@ -1238,6 +1281,7 @@ internal class ObuReader
}
// Not applicable for INTRA frames.
throw new NotImplementedException();
}
private static ObuReferenceMode ReadFrameReferenceMode(ref Av1BitStreamReader reader, bool isIntraFrame)
@ -1286,7 +1330,7 @@ internal class ObuReader
}
// TODO: Implement parsing.
return grainParams;
throw new NotImplementedException();
}
private static bool IsValidSequenceLevel(int sequenceLevelIndex)

2
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSegmentationParameters.cs

@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuSegmentationParameters
{
public int[,] QMLevel { get; internal set; } = new int[3, Av1Constants.MaxSegmentCount];
public int[][] QMLevel { get; internal set; } = new int[3][];
public bool[,] FeatureEnabled { get; internal set; } = new bool[Av1Constants.MaxSegmentCount, Av1Constants.SegmentationLevelMax];

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

@ -10,7 +10,7 @@ internal class ObuWriter
/// <summary>
/// Encode a single frame into OBU's.
/// </summary>
public static void Write(Stream stream, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, ObuTileGroupHeader tileInfo)
public static void Write(Stream stream, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
{
MemoryStream bufferStream = new(100);
Av1BitStreamWriter writer = new(bufferStream);
@ -26,7 +26,7 @@ internal class ObuWriter
WriteObuHeaderAndSize(stream, ObuType.FrameHeader, bufferStream.GetBuffer(), (int)bufferStream.Position);
bufferStream.Position = 0;
WriteTileGroup(ref writer, tileInfo);
WriteTileGroup(ref writer, frameInfo.TilesInfo);
writer.Flush();
WriteObuHeaderAndSize(stream, ObuType.TileGroup, bufferStream.GetBuffer(), (int)bufferStream.Position);
}
@ -145,7 +145,7 @@ internal class ObuWriter
}
}
writer.WriteBoolean(colorConfig.HasSeparateUvDeltaQ);
writer.WriteBoolean(colorConfig.HasSeparateUvDelta);
}
private static void WriteBitDepth(ref Av1BitStreamWriter writer, ObuColorConfig colorConfig, ObuSequenceHeader sequenceHeader)
@ -520,7 +520,7 @@ internal class ObuWriter
if (frameInfo.DeltaLoopFilterParameters.IsPresent)
{
writer.WriteLiteral((uint)frameInfo.DeltaLoopFilterParameters.Resolution, 2);
writer.WriteBoolean(frameInfo.DeltaLoopFilterParameters.Multi);
writer.WriteBoolean(frameInfo.DeltaLoopFilterParameters.IsMulti);
}
}
}
@ -535,6 +535,11 @@ internal class ObuWriter
if (planesCount > 1)
{
bool areUvDeltaDifferent = false;
if (colorInfo.HasSeparateUvDelta)
{
writer.WriteBoolean(colorInfo.HasSeparateUvDelta);
}
WriteDeltaQ(ref writer, quantParams.DeltaQDc[(int)Av1Plane.U]);
WriteDeltaQ(ref writer, quantParams.DeltaQAc[(int)Av1Plane.U]);
if (areUvDeltaDifferent)
@ -549,7 +554,7 @@ internal class ObuWriter
{
writer.WriteLiteral((uint)quantParams.QMatrix[(int)Av1Plane.Y], 4);
writer.WriteLiteral((uint)quantParams.QMatrix[(int)Av1Plane.U], 4);
if (colorInfo.HasSeparateUvDeltaQ)
if (colorInfo.HasSeparateUvDelta)
{
writer.WriteLiteral((uint)quantParams.QMatrix[(int)Av1Plane.V], 4);
}

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

@ -30,11 +30,10 @@ internal class Av1TileDecoder : IAv1TileDecoder
private int deltaLoopFilterResolution = -1;
private int deltaQuantizerResolution = -1;
public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, ObuTileGroupHeader tileInfo)
public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo)
{
this.FrameInfo = frameInfo;
this.SequenceHeader = sequenceHeader;
this.TileInfo = tileInfo;
// init_main_frame_ctxt
this.FrameBuffer = new(this.SequenceHeader);
@ -50,17 +49,15 @@ internal class Av1TileDecoder : IAv1TileDecoder
public ObuSequenceHeader SequenceHeader { get; }
public ObuTileGroupHeader TileInfo { get; }
public Av1FrameBuffer FrameBuffer { get; }
public void DecodeTile(Span<byte> tileData, int tileNum)
{
Av1SymbolDecoder reader = new(tileData);
int tileColumnIndex = tileNum % this.TileInfo.TileColumnCount;
int tileRowIndex = tileNum / this.TileInfo.TileColumnCount;
int tileColumnIndex = tileNum % this.FrameInfo.TilesInfo.TileColumnCount;
int tileRowIndex = tileNum / this.FrameInfo.TilesInfo.TileColumnCount;
this.aboveContext.Clear(this.TileInfo.TileColumnStartModeInfo[tileColumnIndex], this.TileInfo.TileColumnStartModeInfo[tileColumnIndex - 1]);
this.aboveContext.Clear(this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex], this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex - 1]);
this.ClearLoopFilterDelta();
int planesCount = this.SequenceHeader.ColorConfig.IsMonochrome ? 1 : 3;
this.referenceSgrXqd = new int[planesCount][];
@ -79,11 +76,11 @@ internal class Av1TileDecoder : IAv1TileDecoder
Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128SuperBlock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64;
int superBlock4x4Size = superBlockSize.Get4x4WideCount();
for (int row = this.TileInfo.TileRowStartModeInfo[tileRowIndex]; row < this.TileInfo.TileRowStartModeInfo[tileRowIndex + 1]; row += this.SequenceHeader.ModeInfoSize)
for (int row = this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex]; row < this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex + 1]; row += this.SequenceHeader.ModeInfoSize)
{
int superBlockRow = row << Av1Constants.ModeInfoSizeLog2 >> this.SequenceHeader.SuperBlockSizeLog2;
this.leftContext.Clear();
for (int column = this.TileInfo.TileColumnStartModeInfo[tileColumnIndex]; column < this.TileInfo.TileColumnStartModeInfo[tileColumnIndex + 1]; column += this.SequenceHeader.ModeInfoSize)
for (int column = this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex]; column < this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1]; column += this.SequenceHeader.ModeInfoSize)
{
int superBlockColumn = column << Av1Constants.ModeInfoSizeLog2 >> this.SequenceHeader.SuperBlockSizeLog2;
bool subSamplingX = this.SequenceHeader.ColorConfig.SubSamplingX;
@ -165,8 +162,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
private void ParsePartition(ref Av1SymbolDecoder reader, int rowIndex, int columnIndex, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo)
{
if (rowIndex >= this.TileInfo.TileRowStartModeInfo[rowIndex] ||
columnIndex >= this.TileInfo.TileColumnStartModeInfo[columnIndex])
if (rowIndex >= this.FrameInfo.TilesInfo.TileRowStartModeInfo[rowIndex] ||
columnIndex >= this.FrameInfo.TilesInfo.TileColumnStartModeInfo[columnIndex])
{
return;
}
@ -339,8 +336,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
Av1BlockSize planeBlockSize = partitionInfo.ModeInfo.BlockSize.GetSubsampled(subX, subY);
int txsWide = planeBlockSize.GetWidth() >> 2;
int txsHigh = planeBlockSize.GetHeight() >> 2;
int aboveOffset = (partitionInfo.ColumnIndex - this.TileInfo.TileColumnStartModeInfo[partitionInfo.ColumnIndex]) >> (subX ? 1 : 0);
int leftOffset = (partitionInfo.RowIndex - this.TileInfo.TileRowStartModeInfo[partitionInfo.RowIndex]) >> (subY ? 1 : 0);
int aboveOffset = (partitionInfo.ColumnIndex - this.FrameInfo.TilesInfo.TileColumnStartModeInfo[partitionInfo.ColumnIndex]) >> (subX ? 1 : 0);
int leftOffset = (partitionInfo.RowIndex - this.FrameInfo.TilesInfo.TileRowStartModeInfo[partitionInfo.RowIndex]) >> (subY ? 1 : 0);
int[] aboveContext = this.aboveContext.AboveContext[i + aboveOffset];
int[] leftContext = this.leftContext.LeftContext[i + leftOffset];
Array.Fill(aboveContext, 0);
@ -870,7 +867,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
if (this.FrameInfo.DeltaLoopFilterParameters.IsPresent)
{
int frameLoopFilterCount = 1;
if (this.FrameInfo.DeltaLoopFilterParameters.Multi)
if (this.FrameInfo.DeltaLoopFilterParameters.IsMulti)
{
frameLoopFilterCount = this.SequenceHeader.ColorConfig.ChannelCount > 1 ? Av1Constants.FrameLoopFilterCount : Av1Constants.FrameLoopFilterCount - 2;
}
@ -942,10 +939,10 @@ internal class Av1TileDecoder : IAv1TileDecoder
}
private bool IsInside(int rowIndex, int columnIndex) =>
columnIndex >= this.TileInfo.TileColumnCount &&
columnIndex < this.TileInfo.TileColumnCount &&
rowIndex >= this.TileInfo.TileRowCount &&
rowIndex < this.TileInfo.TileRowCount;
columnIndex >= this.FrameInfo.TilesInfo.TileColumnCount &&
columnIndex < this.FrameInfo.TilesInfo.TileColumnCount &&
rowIndex >= this.FrameInfo.TilesInfo.TileRowCount &&
rowIndex < this.FrameInfo.TilesInfo.TileRowCount;
/*
private static bool IsChroma(int rowIndex, int columnIndex, Av1BlockModeInfo blockMode, bool subSamplingX, bool subSamplingY)
@ -961,8 +958,8 @@ internal class Av1TileDecoder : IAv1TileDecoder
{
// Maximum partition point is 8x8. Offset the log value occordingly.
int blockSizeLog = blockSize.Get4x4WidthLog2() - Av1BlockSize.Block8x8.Get4x4WidthLog2();
int aboveCtx = this.aboveContext.PartitionWidth + columnIndex - this.TileInfo.TileColumnStartModeInfo[columnIndex];
int leftCtx = this.leftContext.PartitionHeight + rowIndex - this.TileInfo.TileRowStartModeInfo[rowIndex];
int aboveCtx = this.aboveContext.PartitionWidth + columnIndex - this.FrameInfo.TilesInfo.TileColumnStartModeInfo[columnIndex];
int leftCtx = this.leftContext.PartitionHeight + rowIndex - this.FrameInfo.TilesInfo.TileRowStartModeInfo[rowIndex];
int above = (aboveCtx >> blockSizeLog) & 0x1;
int left = (leftCtx >> blockSizeLog) & 0x1;
return (left * 2) + above + (blockSizeLog * PartitionProbabilitySet);

6
tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs

@ -31,7 +31,7 @@ public class ObuFrameHeaderTests
// Assert
Assert.NotNull(obuReader.SequenceHeader);
Assert.NotNull(obuReader.FrameHeader);
Assert.NotNull(obuReader.TileGroupHeader);
Assert.NotNull(obuReader.FrameHeader.TilesInfo);
}
/* [Theory]
@ -78,7 +78,7 @@ public class ObuFrameHeaderTests
MemoryStream encoded = new();
// Act 2
ObuWriter.Write(encoded, obuReader1.SequenceHeader, obuReader1.FrameHeader, obuReader1.TileGroupHeader);
ObuWriter.Write(encoded, obuReader1.SequenceHeader, obuReader1.FrameHeader);
// Assign 2
Span<byte> encodedBuffer = encoded.ToArray();
@ -93,7 +93,7 @@ public class ObuFrameHeaderTests
Assert.Equal(PrettyPrintProperties(obuReader1.SequenceHeader.ColorConfig), PrettyPrintProperties(obuReader2.SequenceHeader.ColorConfig));
Assert.Equal(PrettyPrintProperties(obuReader1.SequenceHeader), PrettyPrintProperties(obuReader2.SequenceHeader));
Assert.Equal(PrettyPrintProperties(obuReader1.FrameHeader), PrettyPrintProperties(obuReader2.FrameHeader));
Assert.Equal(PrettyPrintProperties(obuReader1.TileGroupHeader), PrettyPrintProperties(obuReader2.TileGroupHeader));
Assert.Equal(PrettyPrintProperties(obuReader1.FrameHeader.TilesInfo), PrettyPrintProperties(obuReader2.FrameHeader.TilesInfo));
}
private static string PrettyPrintProperties(object obj)

Loading…
Cancel
Save