Browse Source

Complete inverse quantization matrix table

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
f88c583003
  1. 2
      src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
  2. 2
      src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs
  3. 18
      src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantification/Av1DeQuantizationContext.cs
  4. 53
      src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantification/Av1InverseQuantizer.cs
  5. 7262
      src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantification/Av1QuantizationConstants.cs
  6. 30
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1TilingTests.cs

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

@ -175,7 +175,7 @@ internal static class Av1Constants
/// <summary>
/// Total number of Quantification Matrices sets stored.
/// </summary>
public const int QuantificationMatrixLevelCount = 4;
public const int QuantificationMatrixLevelCount = 1 << 4;
public const int AngleStep = 3;

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

@ -25,7 +25,7 @@ internal class Av1FrameDecoder : IAv1FrameDecoder
this.frameInfo = frameInfo;
this.frameBuffer = frameBuffer;
this.inverseQuantizer = new(sequenceHeader, frameHeader);
this.deQuants = new();
this.deQuants = new(sequenceHeader, frameHeader);
this.blockDecoder = new(this.sequenceHeader, this.frameHeader, this.frameInfo, this.frameBuffer);
}

18
src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantification/Av1DeQuantizationContext.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline.Quantification;
internal class Av1DeQuantizationContext
@ -8,14 +10,28 @@ internal class Av1DeQuantizationContext
private readonly short[][] dcContent;
private readonly short[][] acContent;
public Av1DeQuantizationContext()
/// <remarks>
/// SVT: svt_aom_setup_segmentation_dequant
/// </remarks>
public Av1DeQuantizationContext(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{
Av1BitDepth bitDepth = sequenceHeader.ColorConfig.BitDepth;
this.dcContent = new short[Av1Constants.MaxSegmentCount][];
this.acContent = new short[Av1Constants.MaxSegmentCount][];
for (int segmentId = 0; segmentId < Av1Constants.MaxSegmentCount; segmentId++)
{
this.dcContent[segmentId] = new short[Av1Constants.MaxPlanes];
this.acContent[segmentId] = new short[Av1Constants.MaxPlanes];
int qindex = Av1QuantizationLookup.GetQIndex(frameHeader.SegmentationParameters, segmentId, frameHeader.QuantizationParameters.BaseQIndex);
for (int plane = 0; plane < Av1Constants.MaxPlanes; plane++)
{
int dc_delta_q = frameHeader.QuantizationParameters.DeltaQDc[plane];
int ac_delta_q = frameHeader.QuantizationParameters.DeltaQAc[plane];
this.dcContent[segmentId][plane] = Av1QuantizationLookup.GetDcQuant(qindex, dc_delta_q, bitDepth);
this.acContent[segmentId][plane] = Av1QuantizationLookup.GetAcQuant(qindex, ac_delta_q, bitDepth);
}
}
}

53
src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantification/Av1InverseQuantizer.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
@ -10,49 +9,15 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline.Quantification;
internal class Av1InverseQuantizer
{
private const int QuatizationMatrixTotalSize = 3344;
private readonly ObuSequenceHeader sequenceHeader;
private readonly ObuFrameHeader frameHeader;
private readonly int[][][] inverseQuantizationMatrix;
private Av1DeQuantizationContext? deQuantsDeltaQ;
private Av1DeQuantizationContext deQuantsDeltaQ;
public Av1InverseQuantizer(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader)
{
this.sequenceHeader = sequenceHeader;
this.frameHeader = frameHeader;
this.inverseQuantizationMatrix = new int[Av1Constants.QuantificationMatrixLevelCount][][];
for (int q = 0; q < Av1Constants.QuantificationMatrixLevelCount; ++q)
{
this.inverseQuantizationMatrix[q] = new int[Av1Constants.MaxPlanes][];
for (int c = 0; c < Av1Constants.MaxPlanes; c++)
{
int lumaOrChroma = Math.Min(1, c);
int current = 0;
this.inverseQuantizationMatrix[q][c] = new int[(int)Av1TransformSize.AllSizes];
for (Av1TransformSize t = 0; t < Av1TransformSize.AllSizes; ++t)
{
int size = t.GetSize2d();
Av1TransformSize qmTransformSize = t.GetAdjusted();
if (q == Av1Constants.QuantificationMatrixLevelCount - 1)
{
this.inverseQuantizationMatrix[q][c][(int)t] = -1;
}
else if (t != qmTransformSize)
{
// Reuse matrices for 'qm_tx_size'
this.inverseQuantizationMatrix[q][c][(int)t] = this.inverseQuantizationMatrix[q][c][(int)qmTransformSize];
}
else
{
Guard.MustBeLessThanOrEqualTo(current + size, QuatizationMatrixTotalSize, nameof(current));
this.inverseQuantizationMatrix[q][c][(int)t] = Av1QuantizationConstants.InverseWT[q][lumaOrChroma][current];
current += size;
}
}
}
}
this.deQuantsDeltaQ = new(sequenceHeader, frameHeader);
}
public void UpdateDequant(Av1DeQuantizationContext deQuants, Av1SuperblockInfo superblockInfo)
@ -94,9 +59,9 @@ internal class Av1InverseQuantizer
short dequantDc = this.deQuantsDeltaQ.GetDc(mode.SegmentId, plane);
short dequantAc = this.deQuantsDeltaQ.GetAc(mode.SegmentId, plane);
int qmLevel = lossless || !usingQuantizationMatrix ? Av1ScanOrderConstants.QuantizationMatrixLevelCount - 1 : this.frameHeader.QuantizationParameters.QMatrix[(int)plane];
ref int iqMatrix = ref (transformType.ToClass() == Av1TransformClass.Class2D) ?
ref this.inverseQuantizationMatrix[qmLevel][(int)plane][(int)qmTransformSize]
: ref this.inverseQuantizationMatrix[Av1Constants.QuantificationMatrixLevelCount - 1][0][(int)qmTransformSize];
ReadOnlySpan<int> iqMatrix = (transformType.ToClass() == Av1TransformClass.Class2D) ?
Av1QuantizationConstants.GetQuantizationMatrix(qmLevel, plane, qmTransformSize)
: Av1QuantizationConstants.GetQuantizationMatrix(Av1Constants.QuantificationMatrixLevelCount - 1, Av1Plane.Y, qmTransformSize);
int shift = transformSize.GetScale();
int coefficientCount = level[0];
@ -106,7 +71,7 @@ internal class Av1InverseQuantizer
if (lev != 0)
{
int pos = scanIndices[0];
qCoefficient = (int)(((long)Math.Abs(lev) * GetDeQuantizedValue(dequantDc, pos, ref iqMatrix)) & 0xffffff);
qCoefficient = (int)(((long)Math.Abs(lev) * GetDeQuantizedValue(dequantDc, pos, iqMatrix)) & 0xffffff);
qCoefficient >>= shift;
if (lev < 0)
@ -123,7 +88,7 @@ internal class Av1InverseQuantizer
if (lev != 0)
{
int pos = scanIndices[i];
qCoefficient = (int)(((long)Math.Abs(lev) * GetDeQuantizedValue(dequantAc, pos, ref iqMatrix)) & 0xffffff);
qCoefficient = (int)(((long)Math.Abs(lev) * GetDeQuantizedValue(dequantAc, pos, iqMatrix)) & 0xffffff);
qCoefficient >>= shift;
if (lev < 0)
@ -141,12 +106,12 @@ internal class Av1InverseQuantizer
/// <summary>
/// SVT: get_dqv
/// </summary>
private static int GetDeQuantizedValue(short dequant, int coefficientIndex, ref int iqMatrix)
private static int GetDeQuantizedValue(short dequant, int coefficientIndex, ReadOnlySpan<int> iqMatrix)
{
const int bias = 1 << (Av1ScanOrderConstants.QuantizationMatrixLevelBitCount - 1);
int deQuantifiedValue = dequant;
deQuantifiedValue = ((Unsafe.Add(ref iqMatrix, coefficientIndex) * deQuantifiedValue) + bias) >> Av1ScanOrderConstants.QuantizationMatrixLevelBitCount;
deQuantifiedValue = ((iqMatrix[coefficientIndex] * deQuantifiedValue) + bias) >> Av1ScanOrderConstants.QuantizationMatrixLevelBitCount;
return deQuantifiedValue;
}
}

7262
src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantification/Av1QuantizationConstants.cs

File diff suppressed because it is too large

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

@ -3,6 +3,7 @@
using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
@ -10,10 +11,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
[Trait("Format", "Avif")]
public class Av1TilingTests
{
[Theory]
[InlineData(TestImages.Heif.Orange4x4, 0x010E, 0x001d, 21, 1)]
public void DecodePixelsFirstTile(string filename, int dataOffset, int dataSize, int tileOffset, int superblockCount)
{
// Assign
string filePath = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, filename);
byte[] content = File.ReadAllBytes(filePath);
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);
Av1FrameBuffer<byte> frameBuffer = new(Configuration.Default, obuReader.SequenceHeader, Av1ColorFormat.Yuv444, false);
Av1FrameInfo frameInfo = new(obuReader.SequenceHeader);
Av1FrameDecoder frameDecoder = new(obuReader.SequenceHeader, obuReader.FrameHeader, frameInfo, frameBuffer);
Av1TileReader tileReader = new(Configuration.Default, obuReader.SequenceHeader, obuReader.FrameHeader, frameDecoder);
// Act
tileReader.ReadTile(tileSpan, 0);
// Assert
Assert.Equal(dataSize * 8, bitStreamReader.BitPosition);
}
[Theory]
[InlineData(TestImages.Heif.XnConvert, 0x010E, 0x03CC, 18, 16)]
[InlineData(TestImages.Heif.Orange4x4, 0x010E, 0x001d, 21, 1)]
public void ReadFirstTile(string filename, int dataOffset, int dataSize, int tileOffset, int superblockCount)
public void DecodePartitionsFirstTile(string filename, int dataOffset, int dataSize, int tileOffset, int superblockCount)
{
// Assign
string filePath = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, filename);
@ -40,7 +66,7 @@ public class Av1TilingTests
[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)
public void ParseHeaderForFirstTile(string filename, int dataOffset, int dataSize, int tileOffset, int superblockCount)
{
// Assign
string filePath = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, filename);

Loading…
Cancel
Save