diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs b/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs index 5ad394dc06..fbaca19a65 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs @@ -31,7 +31,7 @@ internal class Av1Decoder : IAv1TileReader public void Decode(Span buffer) { Av1BitStreamReader reader = new(buffer); - this.obuReader.ReadAll(ref reader, buffer.Length, this, false); + this.obuReader.ReadAll(ref reader, buffer.Length, () => this, false); Guard.NotNull(this.tileReader, nameof(this.tileReader)); Guard.NotNull(this.SequenceHeader, nameof(this.SequenceHeader)); Guard.NotNull(this.FrameHeader, nameof(this.FrameHeader)); diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs index b4054bfcf4..4cf648f0da 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs @@ -39,6 +39,8 @@ internal class ObuReader private static readonly int[] SegmentationFeatureMax = [255, MaxLoopFilter, MaxLoopFilter, MaxLoopFilter, MaxLoopFilter, 7, 0, 0]; + private IAv1TileReader? decoder; + public ObuSequenceHeader? SequenceHeader { get; set; } public ObuFrameHeader? FrameHeader { get; set; } @@ -46,7 +48,7 @@ internal class ObuReader /// /// Decode all OBU's in a frame. /// - public void ReadAll(ref Av1BitStreamReader reader, int dataSize, IAv1TileReader decoder, bool isAnnexB = false) + public void ReadAll(ref Av1BitStreamReader reader, int dataSize, Func creator, bool isAnnexB = false) { bool seenFrameHeader = false; bool frameDecodingFinished = false; @@ -121,7 +123,8 @@ internal class ObuReader throw new InvalidImageContentException("Corrupt frame"); } - this.ReadTileGroup(ref reader, decoder, header, out frameDecodingFinished); + this.decoder ??= creator(); + this.ReadTileGroup(ref reader, this.decoder, header, out frameDecodingFinished); if (frameDecodingFinished) { seenFrameHeader = false; diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs index fabeb629ed..70f846d856 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ParseLeftNeighbor4x4Context.cs @@ -69,7 +69,7 @@ internal class Av1ParseLeftNeighbor4x4Context int startIndex = (modeInfoLocation.Y - superblockInfo.ModeInfoPosition.Y) & Av1PartitionContext.Mask; int bh = blockSize.Get4x4HighCount(); int value = Av1PartitionContext.GetLeftContext(subSize); - DebugGuard.MustBeLessThanOrEqualTo(startIndex, this.LeftTransformHeight.Length - bh, nameof(startIndex)); + DebugGuard.MustBeLessThanOrEqualTo(startIndex, this.LeftPartitionHeight.Length - bh, nameof(startIndex)); Array.Fill(this.LeftPartitionHeight, value, startIndex, bh); } diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs index 815c667bbe..46c39e50d6 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs @@ -23,7 +23,7 @@ public class Av1TilingTests Av1BitStreamReader bitStreamReader = new(headerSpan); IAv1TileReader stub = new Av1TileDecoderStub(); ObuReader obuReader = new(); - obuReader.ReadAll(ref bitStreamReader, dataSize, stub); + obuReader.ReadAll(ref bitStreamReader, dataSize, () => stub); Av1FrameBuffer frameBuffer = new(Configuration.Default, obuReader.SequenceHeader, Av1ColorFormat.Yuv444, false); Av1FrameInfo frameInfo = new(obuReader.SequenceHeader); Av1FrameDecoderStub frameDecoder = new(); @@ -36,4 +36,26 @@ public class Av1TilingTests Assert.Equal(dataSize * 8, bitStreamReader.BitPosition); Assert.Equal(superblockCount, frameDecoder.SuperblockCount); } + + [Theory] + // [InlineData(TestImages.Heif.XnConvert, 0x010E, 0x03CC, 18, 16)] + [InlineData(TestImages.Heif.Orange4x4, 0x010E, 0x001d, 21, 1)] + public void DecodeFirstTile(string filename, int dataOffset, int dataSize, int tileOffset, int superblockCount) + { + // Assign + string filePath = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, filename); + byte[] content = File.ReadAllBytes(filePath); + Span headerSpan = content.AsSpan(dataOffset, dataSize); + Span tileSpan = content.AsSpan(tileOffset, dataSize - tileOffset); + Av1BitStreamReader bitStreamReader = new(headerSpan); + ObuReader obuReader = new(); + Av1FrameDecoderStub frameDecoder = new(); + + // Act + obuReader.ReadAll(ref bitStreamReader, dataSize, () => new Av1TileReader(Configuration.Default, obuReader.SequenceHeader, obuReader.FrameHeader, frameDecoder)); + + // Assert + Assert.Equal(dataSize * 8, bitStreamReader.BitPosition); + Assert.Equal(superblockCount, frameDecoder.SuperblockCount); + } } diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs index 44a9fdc97e..29d3f36d77 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs @@ -39,7 +39,7 @@ public class ObuFrameHeaderTests ObuReader obuReader = new(); // Act - obuReader.ReadAll(ref reader, blockSize, decoder); + obuReader.ReadAll(ref reader, blockSize, () => decoder); // Assert Assert.NotNull(obuReader.SequenceHeader); @@ -63,7 +63,7 @@ public class ObuFrameHeaderTests ObuReader obuReader = new(); // Act 1 - obuReader.ReadAll(ref reader, blockSize, tileStub); + obuReader.ReadAll(ref reader, blockSize, () => tileStub); // Assign 2 MemoryStream encoded = new(); @@ -91,7 +91,7 @@ public class ObuFrameHeaderTests ObuReader obuReader1 = new(); // Act 1 - obuReader1.ReadAll(ref reader, blockSize, tileStub); + obuReader1.ReadAll(ref reader, blockSize, () => tileStub); // Assign 2 MemoryStream encoded = new(); @@ -107,7 +107,7 @@ public class ObuFrameHeaderTests ObuReader obuReader2 = new(); // Act 2 - obuReader2.ReadAll(ref reader2, encodedBuffer.Length, tileDecoder2); + obuReader2.ReadAll(ref reader2, encodedBuffer.Length, () => tileDecoder2); // Assert Assert.Equal(ObuPrettyPrint.PrettyPrintProperties(obuReader1.SequenceHeader.ColorConfig), ObuPrettyPrint.PrettyPrintProperties(obuReader2.SequenceHeader.ColorConfig)); @@ -125,7 +125,7 @@ public class ObuFrameHeaderTests IAv1TileReader tileDecoder = new Av1TileDecoderStub(); // Act - obuReader.ReadAll(ref reader, DefaultTemporalDelimiterBitStream.Length, tileDecoder); + obuReader.ReadAll(ref reader, DefaultTemporalDelimiterBitStream.Length, () => tileDecoder); // Assert Assert.Null(obuReader.SequenceHeader); @@ -142,7 +142,7 @@ public class ObuFrameHeaderTests IAv1TileReader tileDecoder = new Av1TileDecoderStub(); // Act - obuReader.ReadAll(ref reader, bitStream.Length, tileDecoder); + obuReader.ReadAll(ref reader, bitStream.Length, () => tileDecoder); // Assert Assert.Null(obuReader.SequenceHeader); @@ -160,7 +160,7 @@ public class ObuFrameHeaderTests ObuSequenceHeader expected = GetDefaultSequenceHeader(); // Act - obuReader.ReadAll(ref reader, bitStream.Length, tileDecoder); + obuReader.ReadAll(ref reader, bitStream.Length, () => tileDecoder); // Assert Assert.NotNull(obuReader.SequenceHeader);