Browse Source

Complete AV1 lossless reconstruction conformance

pull/2633/head
James Jackson-South 7 days ago
parent
commit
1dfffd11da
  1. 2
      HEIF_IMPLEMENTATION_PLAN.md
  2. 28
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolContextHelper.cs
  3. 11
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs
  4. 9
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs
  5. 32
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseWalshHadamardTransformer.cs
  6. 19
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1InverseTransformTests.cs
  7. 153
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs
  8. 9
      tests/ImageSharp.Tests/TestImages.cs
  9. 6
      tests/Images/Input/Heif/Av1/Conformance/README.md
  10. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444-libaom.yuv
  11. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444.avif
  12. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444.png
  13. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444-libaom.yuv
  14. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444.avif
  15. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444.png
  16. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444-libaom.yuv
  17. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444.avif
  18. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444.png

2
HEIF_IMPLEMENTATION_PLAN.md

@ -504,7 +504,7 @@ Implement and verify in dependency order:
- [x] Verify palette mode syntax and presented reconstruction with an independently encoded palette AVIF fixture.
- [ ] Lossless and high-bit-depth reconstruction with correct clipping and intermediate precision.
- [x] Route lossless 4x4 blocks through allocation-free reversible inverse Walsh-Hadamard reconstruction for 8/10/12-bit samples, including the DC-only specialization, `Vector128` production traversal, scalar fallback, exact clipping, and `FeatureTestRunner` parity.
- [ ] Verify lossless syntax, inverse quantization, prediction, and presented reconstruction with independently encoded 8/10/12-bit AVIF fixtures.
- [x] Verify lossless syntax, inverse quantization, prediction, and presented reconstruction with independently encoded 8/10/12-bit AVIF fixtures. The tests require coded residuals with palette and intra-block copy disabled, compare every native YUV sample with the pinned generic libaom-backed decoder, and compare every presented RGBA byte with pinned generic libavif exactly under normal hardware dispatch and the scalar fallback.
- [x] Deblocking loop filter.
- [x] Implement allocation-free SIMD-first 4-, 6-, 8-, and 14-tap filtering for vertical and horizontal edges in 8/10/12-bit storage through closed edge operators, with exact scalar fallback and `FeatureTestRunner` parity against an independent definition.
- [x] Verify deblocking syntax, filter-level derivation, and boundary traversal with independently encoded 8/10/12-bit AV1 samples and exact scalar-libaom planes; verify presented reconstruction and public precision with genuine AVIF containers at every supported bit depth.

28
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolContextHelper.cs

@ -12,6 +12,18 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Entropy;
/// </summary>
internal static class Av1SymbolContextHelper
{
/// <summary>
/// Maps clipped top and left coefficient-level classes to the transform-block skip context.
/// </summary>
private static ReadOnlySpan<byte> TransformBlockSkipContexts =>
[
1, 2, 2, 2, 3,
2, 4, 4, 4, 5,
2, 4, 4, 4, 5,
2, 4, 4, 4, 5,
3, 5, 5, 5, 6
];
/// <summary>
/// Maps each transform set and transform type to its coded symbol index.
/// </summary>
@ -93,6 +105,22 @@ internal static class Av1SymbolContextHelper
internal static Av1TransformSize GetTransformSizeContext(Av1TransformSize originalSize)
=> (Av1TransformSize)(((int)originalSize.GetSquareSize() + (int)originalSize.GetSquareUpSize() + 1) >> 1);
/// <summary>
/// Derives the luma transform-block skip context from the neighboring coefficient levels.
/// </summary>
/// <param name="top">The union of the packed coefficient contexts above the transform.</param>
/// <param name="left">The union of the packed coefficient contexts to the left of the transform.</param>
/// <returns>The transform-block skip context.</returns>
public static int GetTransformBlockSkipContext(int top, int left)
{
int topClass = Math.Min(top, 4);
int leftClass = Math.Min(left, 4);
// AV1 groups each edge into zero, low, or high coefficient-level classes. Retaining libaom's complete table
// lets the reader and writer share one compile-time mapping without an encoder-side jagged-array allocation.
return TransformBlockSkipContexts[(topClass * 5) + leftClass];
}
/// <summary>
/// Reconstructs an end-of-block coefficient position from its token and extra offset.
/// </summary>

11
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs

@ -82,12 +82,6 @@ internal sealed class Av1TileReader : IAv1TileReader, IDisposable
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2];
/// <summary>
/// Maps the minimum and union of luma neighbor levels to a transform-block skip context.
/// </summary>
private static readonly int[][] SkipContexts = [
[1, 2, 2, 2, 3], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 6]];
/// <summary>
/// Maps the weighted palette-neighbor score hash to its color-index entropy context.
/// </summary>
@ -1080,10 +1074,7 @@ internal sealed class Av1TileReader : IAv1TileReader, IDisposable
while (++k < transformBlockUnitHighCount);
left &= mask;
int max = Math.Min(top | left, 4);
int min = Math.Min(Math.Min(top, left), 4);
transformBlockContext.SkipContext = SkipContexts[min][max];
transformBlockContext.SkipContext = Av1SymbolContextHelper.GetTransformBlockSkipContext(top, left);
}
}
else

9
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs

@ -1406,10 +1406,6 @@ internal partial class Av1TileWriter
}
else
{
// Luma skip contexts depend on the minimum and union of the clipped edge levels.
byte[][] skip_contexts = [
[1, 2, 2, 2, 3], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 6]
];
int top = 0;
int left = 0;
@ -1438,10 +1434,7 @@ internal partial class Av1TileWriter
}
left &= Av1Constants.CoefficientContextMask;
int max = Math.Min(top | left, 4);
int min = Math.Min(Math.Min(top, left), 4);
blockContext.SkipContext = skip_contexts[min][max];
blockContext.SkipContext = Av1SymbolContextHelper.GetTransformBlockSkipContext(top, left);
}
}
else

32
src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseWalshHadamardTransformer.cs

@ -139,10 +139,14 @@ internal static class Av1InverseWalshHadamardTransformer
row2 = Vector128.LoadUnsafe(ref coefficientBase, 8) >> UnitQuantizationShift;
row3 = Vector128.LoadUnsafe(ref coefficientBase, 12) >> UnitQuantizationShift;
// Entropy decoding normalizes AV1's column-major coefficient positions to the row-major transform
// workspace. Restore the normative dimension order before either reversible butterfly performs its
// signed half shift; swapping the dimensions after those shifts would not preserve lossless rounding.
Av1Transform2dOperations.Transpose(ref row0, ref row1, ref row2, ref row3);
Transform(ref row0, ref row1, ref row2, ref row3);
// The first pass operates down four columns in parallel. Transposition turns those intermediate columns
// into packed rows so the same reversible butterfly implements the second dimension without scratch.
// The first pass produces four packed intermediate columns. Transposition turns those columns into rows
// so the same reversible butterfly implements the second dimension without scratch.
Av1Transform2dOperations.Transpose(ref row0, ref row1, ref row2, ref row3);
Transform(ref row0, ref row1, ref row2, ref row3);
}
@ -196,20 +200,22 @@ internal static class Av1InverseWalshHadamardTransformer
ref int coefficientBase = ref MemoryMarshal.GetReference(coefficients);
ref int intermediateBase = ref MemoryMarshal.GetReference(workspace);
// The scalar fallback retains the column-first traversal. The caller-owned transform workspace keeps the
// complete first dimension without introducing per-block stack or managed allocations.
for (int column = 0; column < 4; column++)
// Entropy decoding stores the transposed scan in row-major order, so each contiguous local row is one
// normative transform column. Writing those results down the intermediate columns preserves libaom's
// dimension order without a separate transpose or per-block allocation.
for (int row = 0; row < 4; row++)
{
int a = Unsafe.Add(ref coefficientBase, column) >> UnitQuantizationShift;
int c = Unsafe.Add(ref coefficientBase, 4 + column) >> UnitQuantizationShift;
int d = Unsafe.Add(ref coefficientBase, 8 + column) >> UnitQuantizationShift;
int b = Unsafe.Add(ref coefficientBase, 12 + column) >> UnitQuantizationShift;
int coefficientOffset = row * 4;
int a = Unsafe.Add(ref coefficientBase, coefficientOffset) >> UnitQuantizationShift;
int c = Unsafe.Add(ref coefficientBase, coefficientOffset + 1) >> UnitQuantizationShift;
int d = Unsafe.Add(ref coefficientBase, coefficientOffset + 2) >> UnitQuantizationShift;
int b = Unsafe.Add(ref coefficientBase, coefficientOffset + 3) >> UnitQuantizationShift;
Transform(ref a, ref b, ref c, ref d);
Unsafe.Add(ref intermediateBase, column) = a;
Unsafe.Add(ref intermediateBase, 4 + column) = b;
Unsafe.Add(ref intermediateBase, 8 + column) = c;
Unsafe.Add(ref intermediateBase, 12 + column) = d;
Unsafe.Add(ref intermediateBase, row) = a;
Unsafe.Add(ref intermediateBase, 4 + row) = b;
Unsafe.Add(ref intermediateBase, 8 + row) = c;
Unsafe.Add(ref intermediateBase, 12 + row) = d;
}
for (int column = 0; column < 4; column++)

19
tests/ImageSharp.Tests/Formats/Heif/Av1/Av1InverseTransformTests.cs

@ -411,18 +411,19 @@ public class Av1InverseTransformTests
}
int[] intermediateValues = new int[16];
for (int column = 0; column < 4; column++)
for (int row = 0; row < 4; row++)
{
int a = coefficients[column] >> 2;
int c = coefficients[4 + column] >> 2;
int d = coefficients[8 + column] >> 2;
int b = coefficients[12 + column] >> 2;
int coefficientOffset = row * 4;
int a = coefficients[coefficientOffset] >> 2;
int c = coefficients[coefficientOffset + 1] >> 2;
int d = coefficients[coefficientOffset + 2] >> 2;
int b = coefficients[coefficientOffset + 3] >> 2;
ApplyWalshHadamardReference(ref a, ref b, ref c, ref d);
intermediateValues[column] = a;
intermediateValues[4 + column] = b;
intermediateValues[8 + column] = c;
intermediateValues[12 + column] = d;
intermediateValues[row] = a;
intermediateValues[4 + row] = b;
intermediateValues[8 + row] = c;
intermediateValues[12 + row] = d;
}
for (int column = 0; column < 4; column++)

153
tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs

@ -31,6 +31,11 @@ public class Av1ReconstructionConformanceTests
private const HwIntrinsics PaletteConfigurations =
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic;
/// <summary>
/// The hardware configurations covering the 128-bit and scalar lossless inverse-transform paths.
/// </summary>
private const HwIntrinsics LosslessConfigurations = HwIntrinsics.AllowAll | HwIntrinsics.DisableHWIntrinsic;
/// <summary>
/// The hardware configurations covering the 256-bit, 128-bit, and scalar loop-restoration paths.
/// </summary>
@ -62,6 +67,16 @@ public class Av1ReconstructionConformanceTests
/// </summary>
private const int RequiredPaletteCoverage = LumaPaletteCoverage | ChromaPaletteCoverage;
/// <summary>
/// The displayed width shared by the independent lossless fixtures.
/// </summary>
private const int LosslessFixtureWidth = 100;
/// <summary>
/// The displayed height shared by the independent lossless fixtures.
/// </summary>
private const int LosslessFixtureHeight = 60;
/// <summary>
/// The hardware configurations covering the available vector widths and the scalar color-conversion fallback.
/// </summary>
@ -140,6 +155,22 @@ public class Av1ReconstructionConformanceTests
public void DecodeWithPaletteMatchesPinnedLibavifPresentation()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidatePalettePresentedFixture, PresentationConfigurations);
/// <summary>
/// Verifies lossless syntax, residual reconstruction, and exact native samples against scalar libaom for
/// independently encoded eight-, ten-, and twelve-bit AVIF images.
/// </summary>
[Fact]
public void DecodeLosslessMatchesPinnedLibaomReference()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateLosslessFixtures, LosslessConfigurations);
/// <summary>
/// Verifies exact presented pixels for independently encoded lossless eight-, ten-, and twelve-bit AVIF images
/// across the available vector widths and the scalar fallback.
/// </summary>
[Fact]
public void DecodeLosslessMatchesPinnedLibavifPresentation()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateLosslessPresentedFixtures, PresentationConfigurations);
/// <summary>
/// Verifies active normative super-resolution, chroma-width rounding, replicated edges, and exact native samples
/// against scalar libaom for independently encoded eight-, ten-, and twelve-bit still-picture streams.
@ -308,6 +339,56 @@ public class Av1ReconstructionConformanceTests
requireActiveLoopFilter: false,
requirePalette: true);
/// <summary>
/// Validates every lossless native fixture under the hardware configuration selected by
/// <see cref="FeatureTestRunner"/>.
/// </summary>
private static void ValidateLosslessFixtures()
{
ValidateLosslessFixture(
TestImages.Heif.Av1Lossless8BitAvif,
TestImages.Heif.Av1Lossless8BitReference,
Av1BitDepth.EightBit);
ValidateLosslessFixture(
TestImages.Heif.Av1Lossless10BitAvif,
TestImages.Heif.Av1Lossless10BitReference,
Av1BitDepth.TenBit);
ValidateLosslessFixture(
TestImages.Heif.Av1Lossless12BitAvif,
TestImages.Heif.Av1Lossless12BitReference,
Av1BitDepth.TwelveBit);
}
/// <summary>
/// Validates every lossless presentation fixture under the hardware configuration selected by
/// <see cref="FeatureTestRunner"/>.
/// </summary>
private static void ValidateLosslessPresentedFixtures()
{
ValidatePresentedFixture(
TestImages.Heif.Av1Lossless8BitAvif,
TestImages.Heif.Av1Lossless8BitPresentationReference,
LosslessFixtureWidth,
LosslessFixtureHeight,
HeifBitDepth.Bit8);
ValidatePresentedFixture(
TestImages.Heif.Av1Lossless10BitAvif,
TestImages.Heif.Av1Lossless10BitPresentationReference,
LosslessFixtureWidth,
LosslessFixtureHeight,
HeifBitDepth.Bit10);
ValidatePresentedFixture(
TestImages.Heif.Av1Lossless12BitAvif,
TestImages.Heif.Av1Lossless12BitPresentationReference,
LosslessFixtureWidth,
LosslessFixtureHeight,
HeifBitDepth.Bit12);
}
/// <summary>
/// Validates every active super-resolution fixture under the hardware configuration selected by
/// <see cref="FeatureTestRunner"/>.
@ -701,6 +782,78 @@ public class Av1ReconstructionConformanceTests
return restorationCoverage;
}
/// <summary>
/// Validates lossless frame syntax and complete native reconstruction for one AVIF image.
/// </summary>
/// <param name="imagePath">The independently encoded AVIF container.</param>
/// <param name="referencePath">The raw planar output produced by the pinned scalar libaom decoder.</param>
/// <param name="bitDepth">The expected AV1 sample precision.</param>
private static void ValidateLosslessFixture(string imagePath, string referencePath, Av1BitDepth bitDepth)
{
byte[] imageBytes = TestFile.Create(imagePath).Bytes;
byte[] referenceBytes = TestFile.Create(referencePath).Bytes;
Span<byte> payload = GetSoleAv1ItemPayload(imageBytes);
ReadOnlySpan<byte> nativeReference = referenceBytes;
using Av1Decoder decoder = new(Configuration.Default);
using Av1FrameBuffer<byte> frameBuffer = decoder.DecodeFrameBuffer(payload, null, null, out _);
Assert.Equal(LosslessFixtureWidth, frameBuffer.Width);
Assert.Equal(LosslessFixtureHeight, frameBuffer.Height);
Assert.Equal(bitDepth, frameBuffer.BitDepth);
Assert.Equal(Av1ColorFormat.Yuv444, frameBuffer.ColorFormat);
Assert.NotNull(decoder.SequenceHeader);
Assert.NotNull(decoder.FrameHeader);
Assert.NotNull(decoder.FrameInfo);
Assert.True(decoder.FrameHeader.CodedLossless);
Assert.True(decoder.FrameHeader.AllLossless);
Assert.Equal(0, decoder.FrameHeader.QuantizationParameters.BaseQIndex);
Assert.Equal(ObuMatrixCoefficients.Identity, decoder.SequenceHeader.ColorConfig.MatrixCoefficients);
Assert.False(decoder.FrameHeader.AllowIntraBlockCopy);
Assert.Equal(0, GetPaletteCoverage(decoder));
bool hasCodedResidual = false;
int superblockSizeLog2 = decoder.SequenceHeader.SuperblockSizeLog2;
int superblockColumnCount = Av1Math.AlignPowerOf2(decoder.SequenceHeader.MaxFrameWidth, superblockSizeLog2) >> superblockSizeLog2;
int superblockRowCount = Av1Math.AlignPowerOf2(decoder.SequenceHeader.MaxFrameHeight, superblockSizeLog2) >> superblockSizeLog2;
ReadOnlySpan<Av1Plane> planes = [Av1Plane.Y, Av1Plane.U, Av1Plane.V];
for (int superblockRow = 0; superblockRow < superblockRowCount && !hasCodedResidual; superblockRow++)
{
for (int superblockColumn = 0; superblockColumn < superblockColumnCount && !hasCodedResidual; superblockColumn++)
{
Point superblock = new(superblockColumn, superblockRow);
foreach (Av1Plane plane in planes)
{
Span<int> coefficients = plane switch
{
Av1Plane.Y => decoder.FrameInfo.GetCoefficientsY(superblock),
Av1Plane.U => decoder.FrameInfo.GetCoefficientsU(superblock),
_ => decoder.FrameInfo.GetCoefficientsV(superblock)
};
// Each transform reserves an end index followed by its coefficients. Any nonzero stored value
// proves that exact output traversed coefficient decoding, inverse quantization, and lossless WHT.
foreach (int coefficient in coefficients)
{
if (coefficient != 0)
{
hasCodedResidual = true;
break;
}
}
if (hasCodedResidual)
{
break;
}
}
}
}
Assert.True(hasCodedResidual);
AssertNativePlanesEqual(frameBuffer, nativeReference);
}
/// <summary>
/// Validates one independently encoded stream that activates constrained directional enhancement filtering.
/// </summary>

9
tests/ImageSharp.Tests/TestImages.cs

@ -1369,6 +1369,15 @@ public static class TestImages
public const string Av1Palette8BitReference = "Heif/Av1/Conformance/libaom-palette-draw-points-8b-444-libaom.yuv";
public const string Av1Palette8BitAvif = "Heif/Av1/Conformance/libavif-palette-draw-points-8b.avif";
public const string Av1Palette8BitPresentationReference = "Heif/Av1/Conformance/libavif-palette-draw-points-8b.png";
public const string Av1Lossless8BitAvif = "Heif/Av1/Conformance/libavif-lossless-circle-8b-444.avif";
public const string Av1Lossless8BitReference = "Heif/Av1/Conformance/libavif-lossless-circle-8b-444-libaom.yuv";
public const string Av1Lossless8BitPresentationReference = "Heif/Av1/Conformance/libavif-lossless-circle-8b-444.png";
public const string Av1Lossless10BitAvif = "Heif/Av1/Conformance/libavif-lossless-circle-10b-444.avif";
public const string Av1Lossless10BitReference = "Heif/Av1/Conformance/libavif-lossless-circle-10b-444-libaom.yuv";
public const string Av1Lossless10BitPresentationReference = "Heif/Av1/Conformance/libavif-lossless-circle-10b-444.png";
public const string Av1Lossless12BitAvif = "Heif/Av1/Conformance/libavif-lossless-circle-12b-444.avif";
public const string Av1Lossless12BitReference = "Heif/Av1/Conformance/libavif-lossless-circle-12b-444-libaom.yuv";
public const string Av1Lossless12BitPresentationReference = "Heif/Av1/Conformance/libavif-lossless-circle-12b-444.png";
public const string Av1SuperResolution8BitPayload = "Heif/Av1/Conformance/libaom-superres-kodim23-8b.bit";
public const string Av1SuperResolution8BitReference = "Heif/Av1/Conformance/libaom-superres-kodim23-8b-libaom.yuv";
public const string Av1SuperResolution8BitAvif = "Heif/Av1/Conformance/libavif-superres-kodim23-8b.avif";

6
tests/Images/Input/Heif/Av1/Conformance/README.md

@ -51,6 +51,12 @@ The palette fixture was encoded independently from ImageSharp using `tests/data/
`libaom-palette-draw-points-8b-444.bit` is the exact sole AV1 item extracted from `libavif-palette-draw-points-8b.avif`. The matching native YUV reference was decoded from that payload by the pinned scalar `aomdec --rawvideo` build. The presented PNG was decoded from the complete AVIF container by the pinned scalar `avifdec -j 1 -d 8` build. The tests require both palette planes to be selected, compare every native YUV sample exactly, and compare every presented RGBA byte exactly across the available vector widths and scalar fallback. No tolerance is used.
## Lossless coverage
The lossless fixtures were encoded independently from ImageSharp using `tests/data/circle-trns-after-plte.png` from the pinned libavif revision. Alpha was intentionally ignored so the native references isolate color-plane reconstruction. The 8-bit input uses CICP 1/13/0; the 10- and 12-bit YUV 4:4:4 inputs use CICP 12/16/0. The material `avifenc` options were `-j 1 -s 0 -l --ignore-alpha -y 444 -a enable-palette=0 -a enable-intrabc=0`, together with the matching depth and CICP values. Disabling palette and intra-block copy ensures the exact result traverses ordinary prediction, coefficient decoding, inverse quantization, and the reversible lossless transform.
The `libavif-lossless-circle-*-444-libaom.yuv` files contain the headerless native planes decoded from the complete AVIF containers by the pinned generic `avifdec -j 1` build. Each file stores one 100x60 full-range YUV 4:4:4 frame at 8, 10, or 12 bits. The matching PNG files were decoded by the same build with `-d 8`. Tests require coded and complete losslessness, base quantizer zero, identity matrix coefficients, disabled palette and intra-block copy, and at least one coded residual. Every native Y, U, and V sample and every presented RGBA byte is compared exactly across normal hardware dispatch and the scalar fallback. No tolerance is used.
## Film-grain coverage
The film-grain pairs were generated independently from ImageSharp. Each `.bit` file is an AV1 still-picture OBU stream, and the matching `-libaom.yuv` file is the exact visible planar output from the pinned scalar libaom decoder.

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444-libaom.yuv

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da9e962783072a3b2e8c0055125df1c909276ea5483345059e22706bdeea8121
size 36000

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444.avif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dd55dd965f2023d15038a32f118c0c21d98053804f58d78d1e8f67365f1dcdf4
size 2604

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f4ef1f4a117431ac32f887af4db38d4a90a910ddc5c120f8a716a4934a766c67
size 1128

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444-libaom.yuv

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ad216d8499c02716a63d83ae8ce5f4aa0a211fb05b717dcc3b4467c649313a79
size 36000

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444.avif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f4663d229c3f4d14abf60160acdd24846ceca2334615e5bc09f0f5f4128f0d0c
size 3493

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:624d6bbc99ad1fb9a4bd658959f102c94aeeaab054d86901274832b0f8a12a95
size 1152

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444-libaom.yuv

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0daf2592a6e05243f46269f23d7cc4dcdaf24582d2b544e1dc3892d4c591f575
size 18000

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444.avif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:63c0976280061543aeb6e0ca91bfdd982dbf1fff49ffe19a3fd967a83603e100
size 1663

3
tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a9b2d70a65299c6da81c3b495c54e1eab99c1932e44add57cff2ae00c1f36072
size 834
Loading…
Cancel
Save