Browse Source

Decode each parsed AV1 block once

pull/2633/head
James Jackson-South 1 week ago
parent
commit
686bb21601
  1. 4
      src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs
  2. 10
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameInfo.cs
  3. 5
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SuperblockInfo.cs
  4. 37
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs

4
src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs

@ -120,9 +120,7 @@ internal class Av1FrameDecoder : IAv1FrameDecoder
/// </summary>
private void DecodePartition(Point modeInfoPosition, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo)
{
Av1BlockModeInfo modeInfo = superblockInfo.GetModeInfo(modeInfoPosition);
for (int i = 0; i < superblockInfo.BlockCount; i++)
foreach (Av1BlockModeInfo modeInfo in superblockInfo.GetModeInfos())
{
Point subPosition = modeInfo.PositionInSuperblock;
Av1BlockSize subSize = modeInfo.BlockSize;

10
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1FrameInfo.cs

@ -119,6 +119,16 @@ internal partial class Av1FrameInfo
return this.modeInfos[index];
}
/// <summary>
/// Gets the mode information records parsed for the specified superblock in bitstream order.
/// </summary>
public Span<Av1BlockModeInfo> GetModeInfos(Point superblockIndex, int count)
{
Point location = this.GetModeInfoPosition(superblockIndex, Point.Empty);
int index = this.modeInfoMap[location];
return this.modeInfos.AsSpan(index, count);
}
public Span<Av1TransformInfo> GetSuperblockTransform(int plane, Point index)
{
if (plane == 0)

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

@ -47,6 +47,11 @@ internal class Av1SuperblockInfo
public Span<Av1TransformInfo> GetTransformInfoUv() => this.frameInfo.GetSuperblockTransformUv(this.Position);
/// <summary>
/// Gets the mode information records parsed for this superblock in bitstream order.
/// </summary>
public Span<Av1BlockModeInfo> GetModeInfos() => this.frameInfo.GetModeInfos(this.Position, this.BlockCount);
public Av1BlockModeInfo GetModeInfo(Point index) => this.frameInfo.GetModeInfo(this.Position, index);
public Span<int> GetCoefficients(Av1Plane plane) => plane switch

37
tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs

@ -112,6 +112,43 @@ public class Av1TilingTests
Assert.Equal(superblockCount, frameDecoder.SuperblockCount);
}
[Fact]
public void ParsedSuperblocksExposeEveryModeInfoInBitstreamOrder()
{
string filePath = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Heif.XnConvert);
byte[] content = File.ReadAllBytes(filePath);
const int dataOffset = 0x010E;
const int dataSize = 0x03CC;
const int tileOffset = 18;
Span<byte> headerSpan = content.AsSpan(dataOffset, dataSize);
Span<byte> tileSpan = content.AsSpan(tileOffset, dataSize - tileOffset);
Av1BitStreamReader bitStreamReader = new(headerSpan);
IAv1TileReader stub = new Av1TileDecoderStub();
ObuReader obuReader = new();
obuReader.ReadAll(ref bitStreamReader, dataSize, () => stub);
Av1TileReader tileReader = new(Configuration.Default, obuReader.SequenceHeader, obuReader.FrameHeader);
tileReader.ReadTile(tileSpan, 0);
int parsedModeInfoCount = 0;
int superblockSize = obuReader.SequenceHeader.SuperblockModeInfoSize;
for (int row = 0; row < obuReader.FrameHeader.ModeInfoRowCount; row += superblockSize)
{
for (int column = 0; column < obuReader.FrameHeader.ModeInfoColumnCount; column += superblockSize)
{
Point superblockPosition = new(column / superblockSize, row / superblockSize);
Av1SuperblockInfo superblockInfo = tileReader.FrameInfo.GetSuperblock(superblockPosition);
Span<Av1BlockModeInfo> modeInfos = superblockInfo.GetModeInfos();
Assert.Equal(superblockInfo.BlockCount, modeInfos.Length);
Assert.DoesNotContain(modeInfos.ToArray(), modeInfo => modeInfo is null);
parsedModeInfoCount += modeInfos.Length;
}
}
Assert.True(parsedModeInfoCount > 16);
}
[Theory]
[InlineData(TestImages.Heif.XnConvert, 0x010E, 0x03CC, 18, 16)]
[InlineData(TestImages.Heif.Orange4x4, 0x010E, 0x001d, 21, 1)]

Loading…
Cancel
Save