diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockModeInfo.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockModeInfo.cs index 27ba271ab3..b8b8f8bb47 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockModeInfo.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockModeInfo.cs @@ -9,9 +9,10 @@ internal class Av1BlockModeInfo { private int[] paletteSize; - public Av1BlockModeInfo(int numPlanes, Av1BlockSize blockSize) + public Av1BlockModeInfo(int numPlanes, Av1BlockSize blockSize, Point position) { this.BlockSize = blockSize; + this.PositionInSuperblock = position; this.AngleDelta = new int[numPlanes]; this.paletteSize = new int[numPlanes - 1]; this.FilterIntraModeInfo = new(); @@ -39,7 +40,7 @@ internal class Av1BlockModeInfo public int[] AngleDelta { get; set; } - public Size IndexInSuperblock { get; set; } + public Point PositionInSuperblock { get; set; } public Av1IntraFilterModeInfo FilterIntraModeInfo { get; internal set; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs index 8ae1eec8e1..db8b6ba18f 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameBuffer.cs @@ -39,17 +39,43 @@ internal class Av1FrameBuffer int superblockCount = this.superblockColumnCount * this.superblockRowCount; this.modeInfoSizePerSuperblock = 1 << (superblockSizeLog2 - Av1Constants.ModeInfoSizeLog2); this.modeInfoCountPerSuperblock = this.modeInfoSizePerSuperblock * this.modeInfoSizePerSuperblock; + int numPlanes = sequenceHeader.ColorConfig.IsMonochrome ? 1 : Av1Constants.MaxPlanes; + + // Allocate the arrays. this.superblockInfos = new Av1SuperblockInfo[superblockCount]; this.modeInfos = new Av1BlockModeInfo[superblockCount * this.modeInfoCountPerSuperblock]; this.transformInfosY = new Av1TransformInfo[superblockCount * this.modeInfoCountPerSuperblock]; this.transformInfosUv = new Av1TransformInfo[2 * superblockCount * this.modeInfoCountPerSuperblock]; - this.coefficientsY = new int[superblockCount * this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo]; + + // Initialize the arrays. + int i = 0; + int j = 0; + for (int y = 0; y < this.superblockRowCount; y++) + { + for (int x = 0; x < this.superblockColumnCount; x++) + { + Point point = new(x, y); + this.superblockInfos[i] = new(this, point); + for (int u = 0; u < this.modeInfoSizePerSuperblock; u++) + { + for (int v = 0; v < this.modeInfoSizePerSuperblock; v++) + { + this.modeInfos[j] = new Av1BlockModeInfo(numPlanes, Av1BlockSize.Block4x4, new Point(u, v)); + j++; + } + } + + i++; + } + } + bool subX = sequenceHeader.ColorConfig.SubSamplingX; bool subY = sequenceHeader.ColorConfig.SubSamplingY; // Factor: 444 => 0, 422 => 1, 420 => 2. this.subsamplingFactor = (subX && subY) ? 2 : (subX && !subY) ? 1 : (!subX && !subY) ? 0 : -1; Guard.IsFalse(this.subsamplingFactor == -1, nameof(this.subsamplingFactor), "Invalid combination of subsampling."); + this.coefficientsY = new int[superblockCount * this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo]; this.coefficientsU = new int[(this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo) >> this.subsamplingFactor]; this.coefficientsV = new int[(this.modeInfoCountPerSuperblock * CoefficientCountPerModeInfo) >> this.subsamplingFactor]; this.deltaQ = new int[superblockCount]; @@ -68,12 +94,19 @@ internal class Av1FrameBuffer return span[i]; } + public Av1BlockModeInfo GetModeInfo(Point superblockIndex) + { + Span span = this.modeInfos; + int superblock = (superblockIndex.Y * this.superblockColumnCount) + superblockIndex.X; + return span[superblock * this.modeInfoCountPerSuperblock]; + } + public Av1BlockModeInfo GetModeInfo(Point superblockIndex, Point modeInfoIndex) { Span span = this.modeInfos; - int baseIndex = ((superblockIndex.Y * this.superblockColumnCount) + superblockIndex.X) * this.modeInfoCountPerSuperblock; - int offset = (modeInfoIndex.Y * this.modeInfoSizePerSuperblock) + modeInfoIndex.X; - return span[baseIndex + offset]; + int superblock = (superblockIndex.Y * this.superblockColumnCount) + superblockIndex.X; + int modeInfo = (modeInfoIndex.Y * this.modeInfoSizePerSuperblock) + modeInfoIndex.X; + return span[(superblock * this.modeInfoCountPerSuperblock) + modeInfo]; } public Av1TransformInfo GetTransformY(Point index) @@ -126,6 +159,15 @@ internal class Av1FrameBuffer return span.Slice(i, 1 << this.cdefStrengthFactorLog2); } + internal void ClearCdef(Point index) + { + Span cdefs = this.GetCdefStrength(index); + for (int i = 0; i < cdefs.Length; i++) + { + cdefs[i] = -1; + } + } + public Span GetDeltaLoopFilter(Point index) { Span span = this.deltaLoopFilter; diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveContext.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveContext.cs deleted file mode 100644 index e213005dff..0000000000 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveContext.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol; - -internal class Av1ParseAboveContext -{ - public int PartitionWidth { get; set; } - - public int[][] AboveContext { get; set; } = []; - - internal void Clear(int startColumnIndex, int endColumnIndex) - { - this.PartitionWidth = -1; - this.AboveContext = []; - } -} diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs index bc1f669a83..c883d618bf 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseAboveNeighbor4x4Context.cs @@ -59,7 +59,7 @@ internal class Av1ParseAboveNeighbor4x4Context Array.Fill(this.aboveCompGroupIndex, 0); } - public void UpdatePartition(Point modeInfoLocation, Av1TileLocation tileLoc, Av1BlockSize subSize, Av1BlockSize blockSize) + public void UpdatePartition(Point modeInfoLocation, Av1TileInfo tileLoc, Av1BlockSize subSize, Av1BlockSize blockSize) { int startIndex = modeInfoLocation.X - tileLoc.ModeInfoColumnStart; int bw = blockSize.Get4x4WideCount(); diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftContext.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftContext.cs deleted file mode 100644 index 01219dcfcb..0000000000 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftContext.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol; - -internal class Av1ParseLeftContext -{ - public int PartitionHeight { get; set; } - - public int[][] LeftContext { get; set; } = []; - - internal void Clear() => throw new NotImplementedException(); -} diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs index 6797f433f4..685d1d6b8d 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs @@ -1,10 +1,12 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Data.Common; using SixLabors.ImageSharp.Formats.Heif.Av1; using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; using SixLabors.ImageSharp.Formats.Heif.Av1.Quantization; +using static SixLabors.ImageSharp.PixelFormats.Utils.Vector4Converters; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol; @@ -17,8 +19,6 @@ internal class Av1TileDecoder : IAv1TileDecoder private bool[][][] blockDecoded = []; private int[][] referenceSgrXqd = []; private int[][][] referenceLrWiener = []; - private Av1ParseAboveContext aboveContext = new(); - private Av1ParseLeftContext leftContext = new(); private Av1ParseAboveNeighbor4x4Context aboveNeighborContext; private Av1ParseLeftNeighbor4x4Context leftNeighborContext; private int currentQuantizerIndex; @@ -30,12 +30,13 @@ internal class Av1TileDecoder : IAv1TileDecoder private int maxLumaWidth; private int maxLumaHeight; private int deltaLoopFilterResolution = -1; - private int deltaQuantizerResolution = -1; + private bool readDeltas; public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) { this.FrameInfo = frameInfo; this.SequenceHeader = sequenceHeader; + this.readDeltas = frameInfo.DeltaQParameters.IsPresent; // init_main_frame_ctxt this.FrameBuffer = new(this.SequenceHeader); @@ -68,9 +69,11 @@ internal class Av1TileDecoder : IAv1TileDecoder int tileColumnIndex = tileNum % this.FrameInfo.TilesInfo.TileColumnCount; int tileRowIndex = tileNum / this.FrameInfo.TilesInfo.TileColumnCount; - this.aboveContext.Clear(this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex], this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1]); + this.aboveNeighborContext.Clear(this.SequenceHeader); this.ClearLoopFilterDelta(); int planesCount = this.SequenceHeader.ColorConfig.IsMonochrome ? 1 : 3; + + // Default initialization of Wiener and SGR Filter. this.referenceSgrXqd = new int[planesCount][]; this.referenceLrWiener = new int[planesCount][][]; for (int plane = 0; plane < planesCount; plane++) @@ -85,30 +88,25 @@ internal class Av1TileDecoder : IAv1TileDecoder } } - // TODO: Initialize this.blockDecoded and this.segmentIds + // TODO: Initialize this.blockDecoded + Av1TileInfo tileInfo = new(tileRowIndex, tileColumnIndex, this.FrameInfo); Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128SuperBlock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64; int superBlock4x4Size = superBlockSize.Get4x4WideCount(); for (int row = this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex]; row < this.FrameInfo.TilesInfo.TileRowStartModeInfo[tileRowIndex + 1]; row += this.SequenceHeader.ModeInfoSize) { int superBlockRow = row << Av1Constants.ModeInfoSizeLog2 >> this.SequenceHeader.SuperBlockSizeLog2; - this.leftContext.Clear(); + this.leftNeighborContext.Clear(this.SequenceHeader); for (int column = this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex]; column < this.FrameInfo.TilesInfo.TileColumnStartModeInfo[tileColumnIndex + 1]; column += this.SequenceHeader.ModeInfoSize) { int superBlockColumn = column << Av1Constants.ModeInfoSizeLog2 >> this.SequenceHeader.SuperBlockSizeLog2; - - // bool subSamplingX = this.SequenceHeader.ColorConfig.SubSamplingX; - // bool subSamplingY = this.SequenceHeader.ColorConfig.SubSamplingY; - bool readDeltas = this.FrameInfo.DeltaQParameters.IsPresent; - Av1TileLocation tileLoc = new(row, column, this.FrameInfo); - - // this.ClearBlockDecodedFlags(row, column, superBlock4x4Size); Point superblockPosition = new(superBlockColumn, superBlockRow); - Av1SuperblockInfo superblockInfo = new(this.FrameBuffer, superblockPosition); + Av1SuperblockInfo superblockInfo = this.FrameBuffer.GetSuperblock(superblockPosition); - // Nothing to do for CDEF - // this.ClearCdef(row, column); - // this.ReadLoopRestoration(row, column, superBlockSize); - this.ParsePartition(ref reader, new Point(column, row), superBlockSize, superblockInfo, tileLoc); + // this.ClearBlockDecodedFlags(row, column, superBlock4x4Size); + this.FrameBuffer.ClearCdef(superblockPosition); + Point modeInfoLocation = new(column, row); + this.ReadLoopRestoration(modeInfoLocation, superBlockSize); + this.ParsePartition(ref reader, modeInfoLocation, superBlockSize, superblockInfo, tileInfo); } } } @@ -154,7 +152,7 @@ internal class Av1TileDecoder : IAv1TileDecoder } } - private void ReadLoopRestoration(int row, int column, Av1BlockSize superBlockSize) + private void ReadLoopRestoration(Point modeInfoLocation, Av1BlockSize superBlockSize) { int planesCount = this.SequenceHeader.ColorConfig.ChannelCount; for (int plane = 0; plane < planesCount; plane++) @@ -177,7 +175,7 @@ internal class Av1TileDecoder : IAv1TileDecoder // TODO: Implement } - private void ParsePartition(ref Av1SymbolDecoder reader, Point modeInfoLocation, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1TileLocation tileLoc) + private void ParsePartition(ref Av1SymbolDecoder reader, Point modeInfoLocation, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo) { int columnIndex = modeInfoLocation.X; int rowIndex = modeInfoLocation.Y; @@ -200,18 +198,18 @@ internal class Av1TileDecoder : IAv1TileDecoder } else if (hasRows && hasColumns) { - int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileLoc, this.FrameInfo.ModeInfoRowCount); + int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileInfo, this.FrameInfo.ModeInfoRowCount); partitionType = reader.ReadPartitionType(ctx); } else if (hasColumns) { - int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileLoc, this.FrameInfo.ModeInfoRowCount); + int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileInfo, this.FrameInfo.ModeInfoRowCount); bool splitOrHorizontal = reader.ReadSplitOrHorizontal(blockSize, ctx); partitionType = splitOrHorizontal ? Av1PartitionType.Split : Av1PartitionType.Horizontal; } else if (hasRows) { - int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileLoc, this.FrameInfo.ModeInfoRowCount); + int ctx = this.GetPartitionContext(modeInfoLocation, blockSize, tileInfo, this.FrameInfo.ModeInfoRowCount); bool splitOrVertical = reader.ReadSplitOrVertical(blockSize, ctx); partitionType = splitOrVertical ? Av1PartitionType.Split : Av1PartitionType.Vertical; } @@ -224,49 +222,59 @@ internal class Av1TileDecoder : IAv1TileDecoder Point loc1 = new Point(modeInfoLocation.X, modeInfoLocation.Y + halfBlock4x4Size); Point loc2 = new Point(modeInfoLocation.X + halfBlock4x4Size, modeInfoLocation.Y); Point loc3 = new Point(modeInfoLocation.X + halfBlock4x4Size, modeInfoLocation.Y + halfBlock4x4Size); - this.ParsePartition(ref reader, modeInfoLocation, subSize, superblockInfo, tileLoc); - this.ParsePartition(ref reader, loc1, subSize, superblockInfo, tileLoc); - this.ParsePartition(ref reader, loc2, subSize, superblockInfo, tileLoc); - this.ParsePartition(ref reader, loc3, subSize, superblockInfo, tileLoc); + this.ParsePartition(ref reader, modeInfoLocation, subSize, superblockInfo, tileInfo); + this.ParsePartition(ref reader, loc1, subSize, superblockInfo, tileInfo); + this.ParsePartition(ref reader, loc2, subSize, superblockInfo, tileInfo); + this.ParsePartition(ref reader, loc3, subSize, superblockInfo, tileInfo); break; case Av1PartitionType.None: - this.ParseBlock(ref reader, rowIndex, columnIndex, subSize, superblockInfo, Av1PartitionType.None); + this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, Av1PartitionType.None); break; case Av1PartitionType.Horizontal: - this.ParseBlock(ref reader, rowIndex, columnIndex, subSize, superblockInfo, Av1PartitionType.Horizontal); + this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, Av1PartitionType.Horizontal); if (hasRows) { - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex, subSize, superblockInfo, Av1PartitionType.Horizontal); + Point halfLocation = new(columnIndex, rowIndex + halfBlock4x4Size); + this.ParseBlock(ref reader, halfLocation, subSize, superblockInfo, Av1PartitionType.Horizontal); } break; case Av1PartitionType.Vertical: - this.ParseBlock(ref reader, rowIndex, columnIndex, subSize, superblockInfo, Av1PartitionType.Vertical); + this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, Av1PartitionType.Vertical); if (hasRows) { - this.ParseBlock(ref reader, rowIndex, columnIndex + halfBlock4x4Size, subSize, superblockInfo, Av1PartitionType.Vertical); + Point halfLocation = new(columnIndex + halfBlock4x4Size, rowIndex); + this.ParseBlock(ref reader, halfLocation, subSize, superblockInfo, Av1PartitionType.Vertical); } break; case Av1PartitionType.HorizontalA: - this.ParseBlock(ref reader, rowIndex, columnIndex, splitSize, superblockInfo, Av1PartitionType.HorizontalA); - this.ParseBlock(ref reader, rowIndex, columnIndex + halfBlock4x4Size, splitSize, superblockInfo, Av1PartitionType.HorizontalA); - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex + halfBlock4x4Size, subSize, superblockInfo, Av1PartitionType.HorizontalA); + this.ParseBlock(ref reader, modeInfoLocation, splitSize, superblockInfo, Av1PartitionType.HorizontalA); + Point locHorA1 = new(columnIndex + halfBlock4x4Size, rowIndex); + this.ParseBlock(ref reader, locHorA1, splitSize, superblockInfo, Av1PartitionType.HorizontalA); + Point locHorA2 = new(columnIndex, rowIndex + halfBlock4x4Size); + this.ParseBlock(ref reader, locHorA2, subSize, superblockInfo, Av1PartitionType.HorizontalA); break; case Av1PartitionType.HorizontalB: - this.ParseBlock(ref reader, rowIndex, columnIndex, subSize, superblockInfo, Av1PartitionType.HorizontalB); - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex, splitSize, superblockInfo, Av1PartitionType.HorizontalB); - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex + halfBlock4x4Size, splitSize, superblockInfo, Av1PartitionType.HorizontalB); + this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, Av1PartitionType.HorizontalB); + Point locHorB1 = new(columnIndex + halfBlock4x4Size, rowIndex); + this.ParseBlock(ref reader, locHorB1, splitSize, superblockInfo, Av1PartitionType.HorizontalB); + Point locHorB2 = new(columnIndex + halfBlock4x4Size, rowIndex + halfBlock4x4Size); + this.ParseBlock(ref reader, locHorB2, splitSize, superblockInfo, Av1PartitionType.HorizontalB); break; case Av1PartitionType.VerticalA: - this.ParseBlock(ref reader, rowIndex, columnIndex, splitSize, superblockInfo, Av1PartitionType.VerticalA); - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex, splitSize, superblockInfo, Av1PartitionType.VerticalA); - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex + halfBlock4x4Size, subSize, superblockInfo, Av1PartitionType.VerticalA); + this.ParseBlock(ref reader, modeInfoLocation, splitSize, superblockInfo, Av1PartitionType.VerticalA); + Point locVertA1 = new(columnIndex, rowIndex + halfBlock4x4Size); + this.ParseBlock(ref reader, locVertA1, splitSize, superblockInfo, Av1PartitionType.VerticalA); + Point locVertA2 = new(columnIndex + halfBlock4x4Size, rowIndex); + this.ParseBlock(ref reader, locVertA2, subSize, superblockInfo, Av1PartitionType.VerticalA); break; case Av1PartitionType.VerticalB: - this.ParseBlock(ref reader, rowIndex, columnIndex, subSize, superblockInfo, Av1PartitionType.VerticalB); - this.ParseBlock(ref reader, rowIndex, columnIndex + halfBlock4x4Size, splitSize, superblockInfo, Av1PartitionType.VerticalB); - this.ParseBlock(ref reader, rowIndex + halfBlock4x4Size, columnIndex + halfBlock4x4Size, splitSize, superblockInfo, Av1PartitionType.VerticalB); + this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, Av1PartitionType.VerticalB); + Point locVertB1 = new(columnIndex + halfBlock4x4Size, rowIndex + halfBlock4x4Size); + this.ParseBlock(ref reader, locVertB1, splitSize, superblockInfo, Av1PartitionType.VerticalB); + Point locVertB2 = new(columnIndex + halfBlock4x4Size, rowIndex + halfBlock4x4Size); + this.ParseBlock(ref reader, locVertB2, splitSize, superblockInfo, Av1PartitionType.VerticalB); break; case Av1PartitionType.Horizontal4: for (int i = 0; i < 4; i++) @@ -277,7 +285,8 @@ internal class Av1TileDecoder : IAv1TileDecoder break; } - this.ParseBlock(ref reader, currentBlockRow, columnIndex, subSize, superblockInfo, Av1PartitionType.Horizontal4); + Point currentLocation = new(modeInfoLocation.X, currentBlockRow); + this.ParseBlock(ref reader, currentLocation, subSize, superblockInfo, Av1PartitionType.Horizontal4); } break; @@ -290,7 +299,8 @@ internal class Av1TileDecoder : IAv1TileDecoder break; } - this.ParseBlock(ref reader, rowIndex, currentBlockColumn, subSize, superblockInfo, Av1PartitionType.Vertical4); + Point currentLocation = new(currentBlockColumn, modeInfoLocation.Y); + this.ParseBlock(ref reader, currentLocation, subSize, superblockInfo, Av1PartitionType.Vertical4); } break; @@ -298,15 +308,17 @@ internal class Av1TileDecoder : IAv1TileDecoder throw new NotImplementedException($"Partition type: {partitionType} is not supported."); } - this.UpdatePartitionContext(new Point(columnIndex, rowIndex), tileLoc, superblockInfo, subSize, blockSize, partitionType); + this.UpdatePartitionContext(new Point(columnIndex, rowIndex), tileInfo, superblockInfo, subSize, blockSize, partitionType); } - private void ParseBlock(ref Av1SymbolDecoder reader, int rowIndex, int columnIndex, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1PartitionType partitionType) + private void ParseBlock(ref Av1SymbolDecoder reader, Point modeInfoLocation, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1PartitionType partitionType) { + int rowIndex = modeInfoLocation.Y; + int columnIndex = modeInfoLocation.X; int block4x4Width = blockSize.Get4x4WideCount(); int block4x4Height = blockSize.Get4x4HighCount(); int planesCount = this.SequenceHeader.ColorConfig.ChannelCount; - Av1BlockModeInfo blockModeInfo = new(planesCount, blockSize); + Av1BlockModeInfo blockModeInfo = superblockInfo.GetModeInfo(modeInfoLocation); bool hasChroma = this.HasChroma(rowIndex, columnIndex, blockSize); Av1PartitionInfo partitionInfo = new(blockModeInfo, superblockInfo, hasChroma, partitionType); partitionInfo.ColumnIndex = columnIndex; @@ -383,7 +395,8 @@ internal class Av1TileDecoder : IAv1TileDecoder int columnChunk = columnIndex + (chunkX << 4); int subBlockRow = rowChunk & superBlockMask; int subBlockColumn = columnChunk & superBlockMask; - for (int plane = 0; plane < 1 + (this.HasChroma(rowIndex, columnIndex, blockSize) ? 2 : 0); plane++) + int endPlane = 1 + (this.HasChroma(rowIndex, columnIndex, blockSize) ? 2 : 0); + for (int plane = 0; plane < endPlane; plane++) { Av1TransformSize transformSize = this.FrameInfo.CodedLossless ? Av1TransformSize.Size4x4 : this.GetSize(plane, -1); int stepX = transformSize.GetWidth() >> 2; @@ -426,7 +439,7 @@ internal class Av1TileDecoder : IAv1TileDecoder private void TransformBlock(int plane, int baseX, int baseY, Av1TransformSize transformSize, int x, int y) { - Av1PartitionInfo partitionInfo = new(new(1, Av1BlockSize.Invalid), new(this.FrameBuffer, default), false, Av1PartitionType.None); + Av1PartitionInfo partitionInfo = new(new(1, Av1BlockSize.Invalid, new Point(0, 0)), new(this.FrameBuffer, default), false, Av1PartitionType.None); int startX = (baseX + 4) * x; int startY = (baseY + 4) * y; bool subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX; @@ -954,7 +967,8 @@ internal class Av1TileDecoder : IAv1TileDecoder { bool deltaQuantizerSignBit = reader.ReadLiteral(1) > 0; int reducedDeltaQuantizerIndex = deltaQuantizerSignBit ? -deltaQuantizerAbsolute : deltaQuantizerAbsolute; - this.currentQuantizerIndex = Av1Math.Clip3(1, 255, this.currentQuantizerIndex + (reducedDeltaQuantizerIndex << this.deltaQuantizerResolution)); + int deltaQuantizerResolution = this.FrameInfo.DeltaQParameters.Resolution; + this.currentQuantizerIndex = Av1Math.Clip3(1, 255, this.currentQuantizerIndex + (reducedDeltaQuantizerIndex << deltaQuantizerResolution)); partitionInfo.SuperblockInfo.SuperblockDeltaQ = this.currentQuantizerIndex; } } @@ -976,7 +990,7 @@ internal class Av1TileDecoder : IAv1TileDecoder return xPos && yPos; }*/ - private int GetPartitionContext(Point location, Av1BlockSize blockSize, Av1TileLocation tileLoc, int superblockModeInfoRowCount) + private int GetPartitionContext(Point location, Av1BlockSize blockSize, Av1TileInfo tileLoc, int superblockModeInfoRowCount) { // Maximum partition point is 8x8. Offset the log value occordingly. int aboveCtx = this.aboveNeighborContext.AbovePartitionWidth[location.X - tileLoc.ModeInfoColumnStart]; @@ -987,7 +1001,7 @@ internal class Av1TileDecoder : IAv1TileDecoder return (left * 2) + above + (blockSizeLog * PartitionProbabilitySet); } - private void UpdatePartitionContext(Point modeInfoLocation, Av1TileLocation tileLoc, Av1SuperblockInfo superblockInfo, Av1BlockSize subSize, Av1BlockSize blockSize, Av1PartitionType partition) + private void UpdatePartitionContext(Point modeInfoLocation, Av1TileInfo tileLoc, Av1SuperblockInfo superblockInfo, Av1BlockSize subSize, Av1BlockSize blockSize, Av1PartitionType partition) { if (blockSize >= Av1BlockSize.Block8x8) { diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileLocation.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileInfo.cs similarity index 93% rename from src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileLocation.cs rename to src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileInfo.cs index f0821c8c8a..56d5801333 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileLocation.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileInfo.cs @@ -5,9 +5,9 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol; -internal class Av1TileLocation +internal class Av1TileInfo { - public Av1TileLocation(int row, int column, ObuFrameHeader frameInfo) + public Av1TileInfo(int row, int column, ObuFrameHeader frameInfo) { this.SetTileRow(frameInfo.TilesInfo, frameInfo.ModeInfoRowCount, row); this.SetTileColumn(frameInfo.TilesInfo, frameInfo.ModeInfoColumnCount, column);