// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Buffers.Binary; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Heif; using SixLabors.ImageSharp.Formats.Heif.Av1; using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1; /// /// Validates complete AV1 reconstruction against independently decoded native component planes. /// [Trait("Format", "Avif")] public class Av1DeblockingConformanceTests { /// /// Verifies deblocking syntax, filter activation, component traversal, and presentation for real eight-, ten-, /// and twelve-bit AV1 and AVIF content. /// [Fact] public void DecodeMatchesPinnedLibaomReference() { ValidateFixture( TestImages.Heif.Av1Deblocking8BitAvif, TestImages.Heif.Av1Deblocking8BitPayload, TestImages.Heif.Av1Deblocking8BitReference, 768, 512, Av1BitDepth.EightBit, Av1ColorFormat.Yuv420, HeifBitDepth.Bit8); ValidateFixture( TestImages.Heif.Av1Deblocking10BitAvif, TestImages.Heif.Av1Deblocking10BitPayload, TestImages.Heif.Av1Deblocking10BitReference, 1024, 428, Av1BitDepth.TenBit, Av1ColorFormat.Yuv444, HeifBitDepth.Bit10); ValidateNativeFixture( TestImages.Heif.Av1Deblocking12BitPayload, TestImages.Heif.Av1Deblocking12BitReference, 1024, 428, Av1BitDepth.TwelveBit, Av1ColorFormat.Yuv444); ValidatePresentedImage(TestImages.Heif.Av1Deblocking12BitAvif, 64, 64, HeifBitDepth.Bit12); } /// /// Validates one elementary-stream sample and its containing AVIF image. /// /// The complete AVIF container. /// The AV1 elementary-stream sample extracted from the container. /// The native planar output produced by the pinned libaom decoder. /// The expected displayed width. /// The expected displayed height. /// The expected AV1 sample precision. /// The expected native chroma-sampling layout. /// The expected public HEIF sample precision. private static void ValidateFixture( string imagePath, string payloadPath, string referencePath, int width, int height, Av1BitDepth bitDepth, Av1ColorFormat colorFormat, HeifBitDepth metadataBitDepth) { ValidateNativeFixture(payloadPath, referencePath, width, height, bitDepth, colorFormat); ValidatePresentedImage(imagePath, width, height, metadataBitDepth); } /// /// Validates complete native-plane reconstruction for one AV1 elementary-stream sample. /// /// The AV1 elementary-stream sample. /// The native planar output produced by the pinned libaom decoder. /// The expected reconstructed width. /// The expected reconstructed height. /// The expected AV1 sample precision. /// The expected native chroma-sampling layout. private static void ValidateNativeFixture( string payloadPath, string referencePath, int width, int height, Av1BitDepth bitDepth, Av1ColorFormat colorFormat) { byte[] payload = TestFile.Create(payloadPath).Bytes; byte[] reference = TestFile.Create(referencePath).Bytes; using Av1Decoder decoder = new(Configuration.Default); using Av1FrameBuffer frameBuffer = decoder.DecodeFrameBuffer(payload, null, null, out _); Assert.Equal(width, frameBuffer.Width); Assert.Equal(height, frameBuffer.Height); Assert.Equal(bitDepth, frameBuffer.BitDepth); Assert.Equal(colorFormat, frameBuffer.ColorFormat); Assert.NotNull(decoder.FrameHeader); ObuLoopFilterParameters filterParameters = decoder.FrameHeader.LoopFilterParameters; Assert.True( filterParameters.FilterLevel[0] != 0 || filterParameters.FilterLevel[1] != 0 || filterParameters.FilterLevelU != 0 || filterParameters.FilterLevelV != 0); AssertNativePlanesEqual(frameBuffer, reference); } /// /// Validates the public presentation and metadata produced from one complete AVIF container. /// /// The complete AVIF container. /// The expected displayed width. /// The expected displayed height. /// The expected public HEIF sample precision. private static void ValidatePresentedImage(string imagePath, int width, int height, HeifBitDepth metadataBitDepth) { DecoderOptions options = new() { MaxFrames = 1 }; byte[] imageBytes = TestFile.Create(imagePath).Bytes; using Image image = Image.Load(options, imageBytes); Assert.Equal(width, image.Width); Assert.Equal(height, image.Height); Assert.Single(image.Frames); HeifMetadata metadata = image.Metadata.GetHeifMetadata(); Assert.Equal(HeifCompressionMethod.Av1, metadata.CompressionMethod); Assert.Equal(metadataBitDepth, metadata.BitDepth); } /// /// Compares every visible native component sample with the independent planar reference. /// /// The reconstructed AV1 component planes. /// The planar Y, U, and V samples produced by the pinned libaom decoder. private static void AssertNativePlanesEqual(Av1FrameBuffer frameBuffer, ReadOnlySpan reference) { (int chromaSubsamplingX, int chromaSubsamplingY) = frameBuffer.ColorFormat switch { Av1ColorFormat.Yuv420 => (1, 1), Av1ColorFormat.Yuv422 => (1, 0), _ => (0, 0) }; int referenceOffset = 0; foreach (Av1Plane plane in new[] { Av1Plane.Y, Av1Plane.U, Av1Plane.V }) { int subsamplingX = plane == Av1Plane.Y ? 0 : chromaSubsamplingX; int subsamplingY = plane == Av1Plane.Y ? 0 : chromaSubsamplingY; int planeWidth = GetSubsampledSize(frameBuffer.Width, subsamplingX); int planeHeight = GetSubsampledSize(frameBuffer.Height, subsamplingY); if (frameBuffer.BitDepth == Av1BitDepth.EightBit) { Buffer2DRegion actualPlane = frameBuffer.DeriveBlockPointer(plane, subsamplingX, subsamplingY); for (int y = 0; y < planeHeight; y++) { Span actualRow = actualPlane.DangerousGetRowSpan(y)[..planeWidth]; ReadOnlySpan expectedRow = reference.Slice(referenceOffset, planeWidth); for (int x = 0; x < planeWidth; x++) { AssertSampleEqual(plane, x, y, expectedRow[x], actualRow[x]); } referenceOffset += planeWidth; } } else { // aomdec writes high-bit-depth YUV as little-endian 16-bit values, independently of host endianness. for (int y = 0; y < planeHeight; y++) { Span actualRow = frameBuffer.GetHighBitDepthRowSpan(plane, y, subsamplingX, subsamplingY); for (int x = 0; x < planeWidth; x++) { ushort expected = BinaryPrimitives.ReadUInt16LittleEndian(reference.Slice(referenceOffset, sizeof(ushort))); AssertSampleEqual(plane, x, y, expected, actualRow[x]); referenceOffset += sizeof(ushort); } } } } Assert.Equal(reference.Length, referenceOffset); } /// /// Calculates a component dimension after chroma subsampling with the AV1 rounding rule. /// /// The luma dimension. /// The component subsampling shift. /// The subsampled component dimension. private static int GetSubsampledSize(int size, int subsampling) => (size + (1 << subsampling) - 1) >> subsampling; /// /// Reports the exact component coordinate when independently decoded samples differ. /// /// The compared component plane. /// The sample X coordinate. /// The sample Y coordinate. /// The reference sample. /// The reconstructed sample. private static void AssertSampleEqual(Av1Plane plane, int x, int y, ushort expected, ushort actual) { if (expected != actual) { Assert.Fail($"Plane {plane} differs at ({x}, {y}): expected {expected}, actual {actual}."); } } }