diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs b/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs index 8824c957a0..aafe086447 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs @@ -25,16 +25,15 @@ internal class Av1Decoder : IAv1TileDecoder this.frameBuffer = this.tileDecoder?.FrameBuffer; } - public void StartDecodeTiles() + public void DecodeTile(Span tileData, int tileNum) { - this.SequenceHeader = this.obuReader.SequenceHeader; - this.FrameHeader = this.obuReader.FrameHeader; - this.tileDecoder = new Av1TileDecoder(this.SequenceHeader!, this.FrameHeader!); + if (this.tileDecoder == null) + { + this.SequenceHeader = this.obuReader.SequenceHeader; + this.FrameHeader = this.obuReader.FrameHeader; + this.tileDecoder = new Av1TileDecoder(this.SequenceHeader!, this.FrameHeader!); + } + + this.tileDecoder.DecodeTile(tileData, tileNum); } - - public void DecodeTile(Span tileData, int tileNum) - => this.tileDecoder!.DecodeTile(tileData, tileNum); - - public void FinishDecodeTiles(bool doCdef, bool doLoopRestoration) - => this.tileDecoder!.FinishDecodeTiles(doCdef, doLoopRestoration); } diff --git a/src/ImageSharp/Formats/Heif/Av1/IAv1TileDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/IAv1TileDecoder.cs index daac2ef1d9..839f49619c 100644 --- a/src/ImageSharp/Formats/Heif/Av1/IAv1TileDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/IAv1TileDecoder.cs @@ -8,11 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1; /// internal interface IAv1TileDecoder { - /// - /// Start decoding all tiles of a frame. - /// - void StartDecodeTiles(); - /// /// Decode a single tile. /// @@ -21,11 +16,4 @@ internal interface IAv1TileDecoder /// /// The index of the tile that is to be decoded. void DecodeTile(Span tileData, int tileNum); - - /// - /// Finshed decoding all tiles of a frame. - /// - /// Apply the CDF filter. - /// Apply the loop filters. - void FinishDecodeTiles(bool doCdef, bool doLoopRestoration); } diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs index 95736d9dc4..df1d42c923 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs @@ -1272,7 +1272,7 @@ internal class ObuReader return; } - decoder.FinishDecodeTiles(doCdef, doLoopRestoration); + // TODO: Share doCdef and doLoopRestoration } /// diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs index 44d61813b9..eeffbac337 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs @@ -24,18 +24,17 @@ internal class Av1TileDecoder : IAv1TileDecoder private static readonly int[] EndOfBlockGroupStart = [0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513]; private static readonly int[] EndOfBlockOffsetBits = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - private bool[][][] blockDecoded = []; private int[][] referenceSgrXqd = []; private int[][][] referenceLrWiener = []; private readonly Av1ParseAboveNeighbor4x4Context aboveNeighborContext; private readonly Av1ParseLeftNeighbor4x4Context leftNeighborContext; private int currentQuantizerIndex; - private int[][] segmentIds = []; + private readonly int[][] segmentIds = []; private int deltaLoopFilterResolution = -1; - private bool readDeltas; - private int[][] tusCount; - private int[] firstTransformOffset = new int[2]; - private int[] coefficientIndex = []; + private readonly bool readDeltas; + private readonly int[][] tusCount; + private readonly int[] firstTransformOffset = new int[2]; + private readonly int[] coefficientIndex = []; public Av1TileDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) { @@ -55,9 +54,9 @@ internal class Av1TileDecoder : IAv1TileDecoder // Hard code number of threads to 1 for now. int planesCount = sequenceHeader.ColorConfig.IsMonochrome ? 1 : Av1Constants.MaxPlanes; int superblockColumnCount = - AlignPowerOfTwo(sequenceHeader.MaxFrameWidth, sequenceHeader.SuperBlockSizeLog2) >> sequenceHeader.SuperBlockSizeLog2; + Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameWidth, sequenceHeader.SuperBlockSizeLog2) >> sequenceHeader.SuperBlockSizeLog2; int modeInfoWideColumnCount = superblockColumnCount * sequenceHeader.ModeInfoSize; - modeInfoWideColumnCount = AlignPowerOfTwo(modeInfoWideColumnCount, sequenceHeader.SuperBlockSizeLog2 - 2); + modeInfoWideColumnCount = Av1Math.AlignPowerOf2(modeInfoWideColumnCount, sequenceHeader.SuperBlockSizeLog2 - 2); this.aboveNeighborContext = new Av1ParseAboveNeighbor4x4Context(planesCount, modeInfoWideColumnCount); this.leftNeighborContext = new Av1ParseLeftNeighbor4x4Context(planesCount, sequenceHeader.ModeInfoSize); this.tusCount = new int[Av1Constants.MaxPlanes][]; @@ -98,7 +97,6 @@ internal class Av1TileDecoder : IAv1TileDecoder } } - // TODO: Initialize this.blockDecoded Av1TileInfo tileInfo = new(tileRowIndex, tileColumnIndex, this.FrameInfo); Av1BlockSize superBlockSize = this.SequenceHeader.Use128x128SuperBlock ? Av1BlockSize.Block128x128 : Av1BlockSize.Block64x64; int superBlock4x4Size = superBlockSize.Get4x4WideCount(); @@ -115,54 +113,23 @@ internal class Av1TileDecoder : IAv1TileDecoder // this.ClearBlockDecodedFlags(modeInfoLocation, superBlock4x4Size); Point modeInfoLocation = new(column, row); this.FrameBuffer.ClearCdef(superblockPosition); + this.firstTransformOffset[0] = 0; + this.firstTransformOffset[1] = 0; this.ReadLoopRestoration(modeInfoLocation, superBlockSize); this.ParsePartition(ref reader, modeInfoLocation, superBlockSize, superblockInfo, tileInfo); } } } - private static int AlignPowerOfTwo(int value, int n) => (value + ((1 << n) - 1)) & ~((1 << n) - 1); - private void ClearLoopFilterDelta() => this.FrameBuffer.ClearDeltaLoopFilter(); /// /// 5.11.3. Clear block decoded flags function. /// - private void ClearBlockDecodedFlags(Point modeInfoLocation, int superBlock4x4Size) + private static void ClearBlockDecodedFlags(Point modeInfoLocation, int superBlock4x4Size) { - int planesCount = this.SequenceHeader.ColorConfig.ChannelCount; - this.blockDecoded = new bool[planesCount][][]; - for (int plane = 0; plane < planesCount; plane++) - { - int subX = plane > 0 && this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0; - int subY = plane > 0 && this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0; - int superBlock4x4Width = (this.FrameInfo.ModeInfoColumnCount - modeInfoLocation.X) >> subX; - int superBlock4x4Height = (this.FrameInfo.ModeInfoRowCount - modeInfoLocation.Y) >> subY; - this.blockDecoded[plane] = new bool[(superBlock4x4Size >> subY) + 3][]; - for (int y = -1; y <= superBlock4x4Size >> subY; y++) - { - this.blockDecoded[plane][y] = new bool[(superBlock4x4Size >> subX) + 3]; - for (int x = -1; x <= superBlock4x4Size >> subX; x++) - { - if (y < 0 && x < superBlock4x4Width) - { - this.blockDecoded[plane][y][x] = true; - } - else if (x < 0 && y < superBlock4x4Height) - { - this.blockDecoded[plane][y][x] = true; - } - else - { - this.blockDecoded[plane][y][x] = false; - } - } - } - - int lastIndex = this.blockDecoded[plane][(superBlock4x4Size >> subY) - 1].Length - 1; - this.blockDecoded[plane][(superBlock4x4Size >> subY) - 1][lastIndex] = false; - } + // Nothing to do here. } private void ReadLoopRestoration(Point modeInfoLocation, Av1BlockSize superBlockSize) @@ -178,16 +145,6 @@ internal class Av1TileDecoder : IAv1TileDecoder } } - public void StartDecodeTiles() - { - // TODO: Implement - } - - public void FinishDecodeTiles(bool doCdef, bool doLoopRestoration) - { - // TODO: Implement - } - /// /// 5.11.4. Decode partition syntax. /// @@ -200,8 +157,6 @@ internal class Av1TileDecoder : IAv1TileDecoder return; } - bool availableUp = this.IsInside(rowIndex - 1, columnIndex); - bool availableLeft = this.IsInside(rowIndex, columnIndex - 1); int block4x4Size = blockSize.Get4x4WideCount(); int halfBlock4x4Size = block4x4Size >> 1; int quarterBlock4x4Size = halfBlock4x4Size >> 1; @@ -235,9 +190,9 @@ internal class Av1TileDecoder : IAv1TileDecoder switch (partitionType) { case Av1PartitionType.Split: - 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); + Point loc1 = new(modeInfoLocation.X, modeInfoLocation.Y + halfBlock4x4Size); + Point loc2 = new(modeInfoLocation.X + halfBlock4x4Size, modeInfoLocation.Y); + Point loc3 = new(modeInfoLocation.X + halfBlock4x4Size, modeInfoLocation.Y + halfBlock4x4Size); this.ParsePartition(ref reader, modeInfoLocation, subSize, superblockInfo, tileInfo); this.ParsePartition(ref reader, loc1, subSize, superblockInfo, tileInfo); this.ParsePartition(ref reader, loc2, subSize, superblockInfo, tileInfo); @@ -257,7 +212,7 @@ internal class Av1TileDecoder : IAv1TileDecoder break; case Av1PartitionType.Vertical: this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, tileInfo, Av1PartitionType.Vertical); - if (hasRows) + if (hasColumns) { Point halfLocation = new(columnIndex + halfBlock4x4Size, rowIndex); this.ParseBlock(ref reader, halfLocation, subSize, superblockInfo, tileInfo, Av1PartitionType.Vertical); @@ -273,7 +228,7 @@ internal class Av1TileDecoder : IAv1TileDecoder break; case Av1PartitionType.HorizontalB: this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, tileInfo, Av1PartitionType.HorizontalB); - Point locHorB1 = new(columnIndex + halfBlock4x4Size, rowIndex); + Point locHorB1 = new(columnIndex, rowIndex + halfBlock4x4Size); this.ParseBlock(ref reader, locHorB1, splitSize, superblockInfo, tileInfo, Av1PartitionType.HorizontalB); Point locHorB2 = new(columnIndex + halfBlock4x4Size, rowIndex + halfBlock4x4Size); this.ParseBlock(ref reader, locHorB2, splitSize, superblockInfo, tileInfo, Av1PartitionType.HorizontalB); @@ -287,7 +242,7 @@ internal class Av1TileDecoder : IAv1TileDecoder break; case Av1PartitionType.VerticalB: this.ParseBlock(ref reader, modeInfoLocation, subSize, superblockInfo, tileInfo, Av1PartitionType.VerticalB); - Point locVertB1 = new(columnIndex + halfBlock4x4Size, rowIndex + halfBlock4x4Size); + Point locVertB1 = new(columnIndex + halfBlock4x4Size, rowIndex); this.ParseBlock(ref reader, locVertB1, splitSize, superblockInfo, tileInfo, Av1PartitionType.VerticalB); Point locVertB2 = new(columnIndex + halfBlock4x4Size, rowIndex + halfBlock4x4Size); this.ParseBlock(ref reader, locVertB2, splitSize, superblockInfo, tileInfo, Av1PartitionType.VerticalB); @@ -336,7 +291,9 @@ internal class Av1TileDecoder : IAv1TileDecoder int planesCount = this.SequenceHeader.ColorConfig.ChannelCount; Av1BlockModeInfo blockModeInfo = superblockInfo.GetModeInfo(modeInfoLocation); blockModeInfo.PartitionType = partitionType; - bool hasChroma = this.HasChroma(rowIndex, columnIndex, blockSize); + blockModeInfo.FirstTransformLocation[0] = this.firstTransformOffset[0]; + blockModeInfo.FirstTransformLocation[1] = this.firstTransformOffset[1]; + bool hasChroma = this.HasChroma(modeInfoLocation, blockSize); Av1PartitionInfo partitionInfo = new(blockModeInfo, superblockInfo, hasChroma, partitionType); partitionInfo.ColumnIndex = columnIndex; partitionInfo.RowIndex = rowIndex; @@ -490,14 +447,14 @@ internal class Av1TileDecoder : IAv1TileDecoder } } - private bool HasChroma(int rowIndex, int columnIndex, Av1BlockSize blockSize) + private bool HasChroma(Point modeInfoLocation, Av1BlockSize blockSize) { - int bw = blockSize.Get4x4WideCount(); - int bh = blockSize.Get4x4HighCount(); + int blockWide = blockSize.Get4x4WideCount(); + int blockHigh = blockSize.Get4x4HighCount(); bool subX = this.SequenceHeader.ColorConfig.SubSamplingX; bool subY = this.SequenceHeader.ColorConfig.SubSamplingY; - bool hasChroma = ((rowIndex & 0x01) != 0 || (bh & 0x01) == 0 || !subY) && - ((columnIndex & 0x01) != 0 || (bw & 0x01) == 0 || !subX); + bool hasChroma = ((modeInfoLocation.Y & 0x01) != 0 || (blockHigh & 0x01) == 0 || !subY) && + ((modeInfoLocation.X & 0x01) != 0 || (blockWide & 0x01) == 0 || !subX); return hasChroma; }