diff --git a/HEIF_IMPLEMENTATION_PLAN.md b/HEIF_IMPLEMENTATION_PLAN.md index 08e7cd5831..f843b3e832 100644 --- a/HEIF_IMPLEMENTATION_PLAN.md +++ b/HEIF_IMPLEMENTATION_PLAN.md @@ -29,7 +29,7 @@ Checkboxes may be marked complete only when the implementation and the verificat ## Delivery dashboard -Last reconciled with the source tree on 2026-08-27 against the worktree based on commit `cf0c81eb3`, including the completed AV1 transform, OBU-framing, and independently verified intra-block-copy checkpoints. This dashboard is the authoritative delivery order. The detailed phase checklists below provide subsystem evidence; they do not override the current-stage marker or permit work to skip ahead. +Last reconciled with the source tree on 2026-08-27 against the worktree based on commit `07cc0291e`, including the completed AV1 transform, OBU-framing, intra-block-copy, and 12-profile reconstruction checkpoints. This dashboard is the authoritative delivery order. The detailed phase checklists below provide subsystem evidence; they do not override the current-stage marker or permit work to skip ahead. Status meanings: @@ -40,13 +40,13 @@ Status meanings: Current development stage: **Stage 3 — complete AV1 still-image decoding.** The transform checkpoint is closed: forward transforms use one libaom-shaped SIMD-first operator architecture across `Vector512`, `Vector256`, and `Vector128`, with scalar fallback; inverse production traversal uses the verified `Vector256` and `Vector128` tiers with scalar fallback; and implementation-mechanic type and file suffixes have been removed. Neither AV1 nor HEVC production encoding is implemented. -Immediate checkpoint: **remove every remaining valid AV1 still-image unsupported branch and prove the complete decode matrix.** Each syntax tool must be implemented through the established SIMD-first architecture with scalar fallback and verified with independent AVIF/libaom evidence across supported bit depths, chroma layouts, filters, grain, and color signaling. +Immediate checkpoint: **inventory and remove every remaining valid AV1 still-image unsupported branch, one independently verified syntax tool at a time.** The base AV1 profile matrix is now exact across 8/10/12-bit monochrome, 4:2:0, 4:2:2, and 4:4:4 reconstruction and presentation under every available dispatch tier. That matrix is the regression gate for the remaining compression-tool fixtures; it does not by itself prove every normative still-image tool. | Order | Delivery stage | State | Delivered state | Gate that remains open | | --- | --- | --- | --- | --- | | 1 | Baseline, provenance, documentation, and public contract | In progress | Pinned codec references, a bounded image-only scope, encoder options, typed bit depth, decoder-option propagation, and extensive HEIF documentation exist. | Complete the all-file documentation audit, record a fresh Release baseline, finish distinct public HEIC/AVIF save boundaries, and close API review. | | 2 | Bounded HEIF item and image-sequence container | In progress | Still-item parsing, grids, auxiliary alpha, metadata properties, bounded image-sequence tracks, Identify, and all-sync AV1 sequence presentation are connected. | Complete adversarial boundary coverage, remaining item/property behavior, reference-dependent sequence reconstruction, and the bounded sequence writer. | -| 3 | Still-image AV1 and HEVC decoding | **Current** | HEVC reconstruction reaches exact HM/libheif fixtures across the recorded 8/10/12-bit and chroma cases. AV1 includes bounded OBU framing, reconstruction, filters, grain, color, transforms, and independently verified intra-block-copy syntax and prediction through SIMD-first static-generic operators. | Remove every other valid AV1 still-image unsupported branch with independent vectors, then complete the remaining HEVC profile and Range Extensions matrix. | +| 3 | Still-image AV1 and HEVC decoding | **Current** | HEVC reconstruction reaches exact HM/libheif fixtures across the recorded 8/10/12-bit and chroma cases. AV1 includes bounded OBU framing, reconstruction, filters, grain, color, transforms, intra-block copy, and an exact independent 12-profile bit-depth/chroma matrix through every dispatch tier. | Remove every remaining valid AV1 still-image unsupported branch with independent compression-tool vectors, then complete the remaining HEVC profile and Range Extensions matrix. | | 4 | Complete decoded presentation and animation | In progress | Shared SIMD-first AV1/HEVC color conversion, ICC application, grids, transforms, direct planar alpha composition, frame metadata, repetition, and independently decodable AV1 sequence samples exist. | Close the full color/ICC cross-product, HEVC sequence decoding, AV1/HEVC reference-dependent samples, frame-local metadata/alpha behavior, and independent animated decode vectors. | | 5 | AV1/AVIF encoding | Not started | RGB-to-planar conversion, forward transforms, OBU writer foundations, options, and container-writing infrastructure exist. | `HeifEncoderCore` still rejects AV1. Implement a real independently decodable lossy/lossless AV1 payload and the complete AVIF item/metadata matrix. | | 6 | HEVC/HEIC encoding | Not started | Shared input color conversion, options, and HEIF writer infrastructure exist. | `HeifEncoderCore` still rejects HEVC. Implement a real independently decodable lossy/lossless HEVC payload and the complete HEIC item/metadata matrix. | @@ -56,7 +56,8 @@ Immediate checkpoint: **remove every remaining valid AV1 still-image unsupported ## Immediate execution queue - [x] Finish the libaom-shaped AV1 forward-transform architecture, measured production dispatch, inverse-tier correction, suffix cleanup, `FeatureTestRunner` matrix, and focused Release verification recorded below. -- [ ] **Current:** complete AV1 still-image decoding for every valid still syntax path and independently verify the full bit-depth, chroma, compression-tool, filter, grain, and color matrix. +- [x] Close the base AV1 profile matrix with exact native-plane and presented-image comparisons for 8/10/12-bit monochrome, 4:2:0, 4:2:2, and 4:4:4 fixtures under normal, AVX2, 128-bit, and scalar dispatch. +- [ ] **Current:** inventory and remove every remaining valid AV1 still-image unsupported branch, adding exact independent compression-tool fixtures to the profile-matrix regression gate. - [ ] Complete the remaining HEVC still-image profile and Range Extensions matrix with exact independent native-plane and presentation evidence. - [ ] Close shared decoded presentation, ICC, alpha, grid, transform, metadata, and animated AV1/HEVC decode gates. - [ ] Implement and independently verify real AV1/AVIF still encoding. @@ -500,6 +501,8 @@ Implement and verify in dependency order: - [ ] One coherent decoder lifecycle that retains parsed frame and tile state and disposes all buffers deterministically. - [ ] Tile partitioning, mode information, segmentation, delta quantization, transform-size selection, coefficient token decode, inverse quantization, and inverse transforms. - [x] Match libaom's depth-first traversal and frame-edge behavior for all ten AV1 partition types. Independent 8/10/12-bit streams collectively select every terminal partition shape and contain nested block geometry that requires recursive `Split` traversal; their complete native planes remain byte-exact under normal hardware dispatch and the scalar fallback. + - [x] Verify the complete 8/10/12-bit monochrome, 4:2:0, 4:2:2, and 4:4:4 base profile matrix against pinned libaom native planes and pinned libavif presentation output. All 12 fixtures match exactly with normal dispatch, AVX-512 disabled, AVX disabled, and all hardware intrinsics disabled through `FeatureTestRunner`. + - [x] Correct monochrome plane classification, maximum-superblock-row loop-filter traversal, and identity/one-dimensional inverse-quantization-matrix selection exposed by the profile matrix. The quantization rule matches libaom's `tx_type < IDTX` boundary and is verified by the exact native-plane oracle rather than a tolerance. - [ ] Intra prediction, including every directional, smooth, Paeth, CFL, filter-intra, and palette case permitted by AV1. - [x] Implement SIMD-first chroma-from-luma storage, 4:4:4/4:2:2/4:2:0 subsampling, rounded mean subtraction, and 8/10/12-bit prediction with exact scalar fallback and `FeatureTestRunner` parity. - [x] Implement allocation-free SIMD-first palette reconstruction for palette sizes 2-8, transform widths 4-64, and 8/10/12-bit samples with exact scalar fallback and `FeatureTestRunner` parity. diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs index 62783cbde4..c3de94a038 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs @@ -90,6 +90,13 @@ internal class ObuColorConfig /// The corresponding AV1 color format. public Av1ColorFormat GetColorFormat() { + if (this.IsMonochrome) + { + // AV1 sets both subsampling flags for monochrome sequences even though no chroma planes exist. The + // mono_chrome syntax therefore owns the plane layout and must take precedence over those derived flags. + return Av1ColorFormat.Yuv400; + } + Av1ColorFormat format = Av1ColorFormat.Yuv400; if (this.SubSamplingX && this.SubSamplingY) { diff --git a/src/ImageSharp/Formats/Heif/Av1/Pipeline/LoopFilter/Av1LoopFilterDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Pipeline/LoopFilter/Av1LoopFilterDecoder.cs index 7a4e2ef946..9c8ec96a3e 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Pipeline/LoopFilter/Av1LoopFilterDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Pipeline/LoopFilter/Av1LoopFilterDecoder.cs @@ -61,7 +61,7 @@ internal class Av1LoopFilterDecoder } /// - /// Filters every enabled plane, processing all vertical boundaries before horizontal boundaries. + /// Filters every enabled plane in maximum-superblock row bands. /// public void DecodeFrame() { @@ -72,45 +72,57 @@ internal class Av1LoopFilterDecoder } ObuColorConfig colorConfig = this.sequenceHeader.ColorConfig; - for (int planeIndex = 0; planeIndex < colorConfig.PlaneCount; planeIndex++) + int modeInfoRowsPerBand = 1 << (Av1Constants.MaxSuperBlockSizeLog2 - Av1Constants.ModeInfoSizeLog2); + + // libaom's loop_filter_rows processes one MAX_MIB_SIZE band at a time so that a completed band can be + // presented before the remainder of the frame. The ordering is observable because the vertical and + // horizontal passes modify intersecting sample neighborhoods in place. + for (int rowStart = 0; rowStart < this.frameHeader.ModeInfoRowCount; rowStart += modeInfoRowsPerBand) { - Av1Plane plane = (Av1Plane)planeIndex; - int planeFilterLevel = plane switch - { - Av1Plane.U => filterParameters.FilterLevelU, - Av1Plane.V => filterParameters.FilterLevelV, - _ => Math.Max(filterParameters.FilterLevel[0], filterParameters.FilterLevel[1]) - }; + int rowEnd = Math.Min(rowStart + modeInfoRowsPerBand, this.frameHeader.ModeInfoRowCount); - if (planeFilterLevel == 0) + for (int planeIndex = 0; planeIndex < colorConfig.PlaneCount; planeIndex++) { - continue; - } + Av1Plane plane = (Av1Plane)planeIndex; + int planeFilterLevel = plane switch + { + Av1Plane.U => filterParameters.FilterLevelU, + Av1Plane.V => filterParameters.FilterLevelV, + _ => Math.Max(filterParameters.FilterLevel[0], filterParameters.FilterLevel[1]) + }; - int subX = plane != Av1Plane.Y && colorConfig.SubSamplingX ? 1 : 0; - int subY = plane != Av1Plane.Y && colorConfig.SubSamplingY ? 1 : 0; - Span lowBitDepthSamples = default; - Span highBitDepthSamples = default; - int stride; + if (planeFilterLevel == 0) + { + continue; + } - if (this.frameBuffer.BytesPerSample == 2) - { - Span signedSamples = this.frameBuffer.DeriveBlockPointer16(plane, Point.Empty, subX, subY, out stride); - highBitDepthSamples = MemoryMarshal.Cast(signedSamples); - } - else - { - lowBitDepthSamples = this.frameBuffer.DeriveBlockPointer(plane, Point.Empty, subX, subY, out stride); - } + int subX = plane != Av1Plane.Y && colorConfig.SubSamplingX ? 1 : 0; + int subY = plane != Av1Plane.Y && colorConfig.SubSamplingY ? 1 : 0; + Span lowBitDepthSamples = default; + Span highBitDepthSamples = default; + int stride; - this.FilterPlane(plane, subX, subY, stride, lowBitDepthSamples, highBitDepthSamples); + if (this.frameBuffer.BytesPerSample == 2) + { + Span signedSamples = this.frameBuffer.DeriveBlockPointer16(plane, Point.Empty, subX, subY, out stride); + highBitDepthSamples = MemoryMarshal.Cast(signedSamples); + } + else + { + lowBitDepthSamples = this.frameBuffer.DeriveBlockPointer(plane, Point.Empty, subX, subY, out stride); + } + + this.FilterPlane(plane, rowStart, rowEnd, subX, subY, stride, lowBitDepthSamples, highBitDepthSamples); + } } } /// - /// Filters one plane in the AV1 vertical-then-horizontal boundary order. + /// Filters one plane band in the AV1 vertical-then-horizontal boundary order. /// /// The color plane to filter. + /// The inclusive band origin in luma 4x4 units. + /// The exclusive band limit in luma 4x4 units. /// The horizontal chroma subsampling shift. /// The vertical chroma subsampling shift. /// The plane stride in logical samples. @@ -118,6 +130,8 @@ internal class Av1LoopFilterDecoder /// The high-bit-depth plane storage, when active. private void FilterPlane( Av1Plane plane, + int rowStart, + int rowEnd, int subX, int subY, int stride, @@ -127,25 +141,41 @@ internal class Av1LoopFilterDecoder int rowStep = 1 << subY; int columnStep = 1 << subX; - // The AV1 result is independent of ordering within a pass, but vertical filtering must finish before any - // horizontal filtering begins because the two directions modify intersecting sample neighborhoods. - for (int pass = 0; pass < 2; pass++) + // The vertical pass advances across each row because successive vertical edges do not share modified samples. + // Chroma rows retain luma-grid coordinates and therefore advance by two mode-info units when subsampled. + for (int row = rowStart; row < rowEnd; row += rowStep) { - for (int row = 0; row < this.frameHeader.ModeInfoRowCount; row += rowStep) + for (int column = 0; column < this.frameHeader.ModeInfoColumnCount; column += columnStep) { - for (int column = 0; column < this.frameHeader.ModeInfoColumnCount; column += columnStep) - { - this.FilterEdge( - plane, - pass, - row, - column, - subX, - subY, - stride, - lowBitDepthSamples, - highBitDepthSamples); - } + this.FilterEdge( + plane, + 0, + row, + column, + subX, + subY, + stride, + lowBitDepthSamples, + highBitDepthSamples); + } + } + + // Horizontal edges are visited down each column. This ordering is observable because adjacent horizontal + // filters can modify samples that a later edge reads, so it must match libaom's av1_filter_block_plane_horz. + for (int column = 0; column < this.frameHeader.ModeInfoColumnCount; column += columnStep) + { + for (int row = rowStart; row < rowEnd; row += rowStep) + { + this.FilterEdge( + plane, + 1, + row, + column, + subX, + subY, + stride, + lowBitDepthSamples, + highBitDepthSamples); } } } @@ -247,6 +277,7 @@ internal class Av1LoopFilterDecoder int boundaryLimit = (2 * (filterLevel + 2)) + limit; int highEdgeVarianceThreshold = filterLevel >> 4; int q0Offset = stride + (planeY * stride) + planeX; + if (this.frameBuffer.BytesPerSample == 2) { if (verticalBoundary) diff --git a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantizers/Av1InverseQuantizer.cs b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantizers/Av1InverseQuantizer.cs index d7a6957a24..233117e071 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantizers/Av1InverseQuantizer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Quantizers/Av1InverseQuantizer.cs @@ -95,13 +95,14 @@ internal class Av1InverseQuantizer short dequantDc = this.deQuantsDeltaQ.GetDc(mode.SegmentId, plane); short dequantAc = this.deQuantsDeltaQ.GetAc(mode.SegmentId, plane); - // The final matrix level is flat. Lossless blocks, frames without matrices, and one-dimensional transforms - // must use it so coefficient frequency does not change the signaled dequantization value. + // The final matrix level is flat. Lossless blocks and frames without matrices select it globally. AV1 also + // requires identity and one-dimensional transform types, which occupy the enum range from Identity onward, + // to bypass frequency weighting even when the frame signals quantization matrices. int qmLevel = lossless || !usingQuantizationMatrix ? Av1ScanOrderConstants.QuantizationMatrixLevelCount - 1 : this.frameHeader.SegmentationParameters.QMLevel[(int)plane][mode.SegmentId]; - ReadOnlySpan iqMatrix = (transformType.ToClass() == Av1TransformClass.Class2D) + ReadOnlySpan iqMatrix = transformType < Av1TransformType.Identity ? Av1InverseQuantizationLookup.GetQuantizationMatrix(qmLevel, plane, transformSize) : Av1InverseQuantizationLookup.GetQuantizationMatrix(Av1Constants.QuantificationMatrixLevelCount - 1, Av1Plane.Y, transformSize); diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs index a918d1126e..8241a5fa06 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs @@ -2,12 +2,15 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; +using System.Text; 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.Formats.Heif.Av1.Tiling; +using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -20,6 +23,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1; [Trait("Format", "Avif")] public class Av1ReconstructionConformanceTests { + /// + /// The width and height of one CDEF unit in 4x4 luma mode-information units. + /// + private const int CdefUnitModeInfoSize = 16; + /// /// The hardware configurations covering normal SIMD dispatch and the scalar fallback. /// @@ -37,6 +45,12 @@ public class Av1ReconstructionConformanceTests private const HwIntrinsics IntraBlockCopyConfigurations = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic; + /// + /// The hardware configurations covering the narrower vector widths and scalar fallback for the profile matrix. + /// + private const HwIntrinsics ProfileFallbackConfigurations = + HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic; + /// /// The hardware configurations covering the 128-bit and scalar lossless inverse-transform paths. /// @@ -88,6 +102,16 @@ public class Av1ReconstructionConformanceTests /// private const int LosslessFixtureHeight = 60; + /// + /// The displayed width shared by the independent AV1 profile fixtures. + /// + private const int ProfileFixtureWidth = 512; + + /// + /// The displayed height shared by the independent AV1 profile fixtures. + /// + private const int ProfileFixtureHeight = 256; + /// /// The hardware configurations covering the available vector widths and the scalar color-conversion fallback. /// @@ -150,6 +174,38 @@ public class Av1ReconstructionConformanceTests public void DecodeWithActiveCdefMatchesPinnedLibavifPresentation() => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidatePresentedFixtures, PresentationConfigurations); + /// + /// Verifies exact native reconstruction for every valid AV1 profile, bit-depth, and chroma-format combination + /// supported by AVIF across every available vector width and the scalar fallback. + /// + [Fact] + public void DecodeProfileMatrixMatchesPinnedLibaomReference() + => ValidateProfileNativeFixtures(); + + /// + /// Verifies exact native reconstruction for every valid AV1 profile, bit-depth, and chroma-format combination + /// under each narrower vector width and the scalar fallback. + /// + [Fact] + public void DecodeProfileMatrixFallbacksMatchPinnedLibaomReference() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateProfileNativeFixtures, ProfileFallbackConfigurations); + + /// + /// Verifies exact presented pixels, public bit-depth metadata, and CICP signaling for every valid AV1 profile, + /// bit-depth, and chroma-format combination supported by AVIF. + /// + [Fact] + public void DecodeProfileMatrixMatchesPinnedLibavifPresentation() + => ValidateProfilePresentedFixtures(); + + /// + /// Verifies exact presented pixels, public bit-depth metadata, and CICP signaling under each narrower vector width + /// and the scalar fallback. + /// + [Fact] + public void DecodeProfileMatrixFallbacksMatchPinnedLibavifPresentation() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateProfilePresentedFixtures, ProfileFallbackConfigurations); + /// /// Verifies decoded luma and chroma palette syntax and exact native samples against scalar libaom for an /// independently encoded AV1 still-picture stream. @@ -292,6 +348,275 @@ public class Av1ReconstructionConformanceTests Assert.Equal(RequiredPartitionCoverage, coverage & RequiredPartitionCoverage); } + /// + /// Validates every native profile fixture under the hardware configuration selected by + /// . + /// + private static void ValidateProfileNativeFixtures() + { + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile8BitMonochromeAvif, + TestImages.Heif.Av1Profile8BitMonochromeReference, + Av1BitDepth.EightBit, + Av1ColorFormat.Yuv400, + ObuSequenceProfile.Main); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile8Bit420Avif, + TestImages.Heif.Av1Profile8Bit420Reference, + Av1BitDepth.EightBit, + Av1ColorFormat.Yuv420, + ObuSequenceProfile.Main); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile8Bit422Avif, + TestImages.Heif.Av1Profile8Bit422Reference, + Av1BitDepth.EightBit, + Av1ColorFormat.Yuv422, + ObuSequenceProfile.Professional); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile8Bit444Avif, + TestImages.Heif.Av1Profile8Bit444Reference, + Av1BitDepth.EightBit, + Av1ColorFormat.Yuv444, + ObuSequenceProfile.High); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile10BitMonochromeAvif, + TestImages.Heif.Av1Profile10BitMonochromeReference, + Av1BitDepth.TenBit, + Av1ColorFormat.Yuv400, + ObuSequenceProfile.Main); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile10Bit420Avif, + TestImages.Heif.Av1Profile10Bit420Reference, + Av1BitDepth.TenBit, + Av1ColorFormat.Yuv420, + ObuSequenceProfile.Main); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile10Bit422Avif, + TestImages.Heif.Av1Profile10Bit422Reference, + Av1BitDepth.TenBit, + Av1ColorFormat.Yuv422, + ObuSequenceProfile.Professional); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile10Bit444Avif, + TestImages.Heif.Av1Profile10Bit444Reference, + Av1BitDepth.TenBit, + Av1ColorFormat.Yuv444, + ObuSequenceProfile.High); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile12BitMonochromeAvif, + TestImages.Heif.Av1Profile12BitMonochromeReference, + Av1BitDepth.TwelveBit, + Av1ColorFormat.Yuv400, + ObuSequenceProfile.Professional); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile12Bit420Avif, + TestImages.Heif.Av1Profile12Bit420Reference, + Av1BitDepth.TwelveBit, + Av1ColorFormat.Yuv420, + ObuSequenceProfile.Professional); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile12Bit422Avif, + TestImages.Heif.Av1Profile12Bit422Reference, + Av1BitDepth.TwelveBit, + Av1ColorFormat.Yuv422, + ObuSequenceProfile.Professional); + + ValidateProfileNativeFixture( + TestImages.Heif.Av1Profile12Bit444Avif, + TestImages.Heif.Av1Profile12Bit444Reference, + Av1BitDepth.TwelveBit, + Av1ColorFormat.Yuv444, + ObuSequenceProfile.Professional); + } + + /// + /// Validates every presented profile fixture under the hardware configuration selected by + /// . + /// + private static void ValidateProfilePresentedFixtures() + { + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile8BitMonochromeAvif, + TestImages.Heif.Av1Profile8BitMonochromePresentationReference, + HeifBitDepth.Bit8); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile8Bit420Avif, + TestImages.Heif.Av1Profile8Bit420PresentationReference, + HeifBitDepth.Bit8); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile8Bit422Avif, + TestImages.Heif.Av1Profile8Bit422PresentationReference, + HeifBitDepth.Bit8); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile8Bit444Avif, + TestImages.Heif.Av1Profile8Bit444PresentationReference, + HeifBitDepth.Bit8); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile10BitMonochromeAvif, + TestImages.Heif.Av1Profile10BitMonochromePresentationReference, + HeifBitDepth.Bit10); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile10Bit420Avif, + TestImages.Heif.Av1Profile10Bit420PresentationReference, + HeifBitDepth.Bit10); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile10Bit422Avif, + TestImages.Heif.Av1Profile10Bit422PresentationReference, + HeifBitDepth.Bit10); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile10Bit444Avif, + TestImages.Heif.Av1Profile10Bit444PresentationReference, + HeifBitDepth.Bit10); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile12BitMonochromeAvif, + TestImages.Heif.Av1Profile12BitMonochromePresentationReference, + HeifBitDepth.Bit12); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile12Bit420Avif, + TestImages.Heif.Av1Profile12Bit420PresentationReference, + HeifBitDepth.Bit12); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile12Bit422Avif, + TestImages.Heif.Av1Profile12Bit422PresentationReference, + HeifBitDepth.Bit12); + + ValidateProfilePresentedFixture( + TestImages.Heif.Av1Profile12Bit444Avif, + TestImages.Heif.Av1Profile12Bit444PresentationReference, + HeifBitDepth.Bit12); + } + + /// + /// Validates one independently encoded AVIF against its native Y4M reference and signaled sequence profile. + /// + /// The complete AVIF container. + /// The native Y4M output produced by the pinned scalar libaom-backed decoder. + /// The expected AV1 sample precision. + /// The expected native chroma-sampling layout. + /// The AV1 profile required by the bit-depth and chroma-format combination. + private static void ValidateProfileNativeFixture( + string imagePath, + string referencePath, + Av1BitDepth bitDepth, + Av1ColorFormat colorFormat, + ObuSequenceProfile sequenceProfile) + { + byte[] imageBytes = TestFile.Create(imagePath).Bytes; + byte[] referenceBytes = TestFile.Create(referencePath).Bytes; + (string chromaTag, string extendedChromaTag) = GetY4mColorSpace(bitDepth, colorFormat); + string expectedHeader = + $"YUV4MPEG2 W{ProfileFixtureWidth} H{ProfileFixtureHeight} F25:1 Ip A0:0 C{chromaTag} XYSCSS={extendedChromaTag} XCOLORRANGE=FULL\n"; + + int headerTerminator = referenceBytes.AsSpan().IndexOf((byte)'\n'); + Assert.NotEqual(-1, headerTerminator); + int fileHeaderLength = headerTerminator + 1; + Assert.Equal(expectedHeader, Encoding.ASCII.GetString(referenceBytes, 0, fileHeaderLength)); + + ReadOnlySpan nativeReference = referenceBytes.AsSpan(fileHeaderLength); + ReadOnlySpan frameHeader = "FRAME\n"u8; + Assert.True(nativeReference.StartsWith(frameHeader)); + nativeReference = nativeReference[frameHeader.Length..]; + + Span payload = GetSoleAv1ItemPayload(imageBytes); + using Av1Decoder decoder = new(Configuration.Default); + using Av1FrameBuffer frameBuffer = decoder.DecodeFrameBuffer(payload, null, null, out _); + + Assert.Equal(ProfileFixtureWidth, frameBuffer.Width); + Assert.Equal(ProfileFixtureHeight, frameBuffer.Height); + Assert.Equal(bitDepth, frameBuffer.BitDepth); + Assert.Equal(colorFormat, frameBuffer.ColorFormat); + + ObuSequenceHeader sequenceHeader = Assert.IsType(decoder.SequenceHeader); + ObuColorConfig colorConfig = sequenceHeader.ColorConfig; + Assert.Equal(sequenceProfile, sequenceHeader.SequenceProfile); + Assert.Equal(bitDepth, colorConfig.BitDepth); + Assert.Equal(colorFormat, colorConfig.GetColorFormat()); + Assert.Equal(colorFormat == Av1ColorFormat.Yuv400, colorConfig.IsMonochrome); + Assert.True(colorConfig.IsColorDescriptionPresent); + Assert.Equal(ObuColorPrimaries.Bt709, colorConfig.ColorPrimaries); + Assert.Equal(ObuTransferCharacteristics.Srgb, colorConfig.TransferCharacteristics); + Assert.Equal(ObuMatrixCoefficients.Bt601, colorConfig.MatrixCoefficients); + Assert.True(colorConfig.ColorRange); + AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); + } + + /// + /// Validates the exact public presentation and metadata of one independently encoded AVIF profile fixture. + /// + /// The complete AVIF container. + /// The eight-bit RGBA output produced by the pinned scalar libavif decoder. + /// The expected public HEIF sample precision. + private static void ValidateProfilePresentedFixture(string imagePath, string referencePath, HeifBitDepth metadataBitDepth) + { + DecoderOptions options = new() { MaxFrames = 1 }; + byte[] imageBytes = TestFile.Create(imagePath).Bytes; + byte[] referenceBytes = TestFile.Create(referencePath).Bytes; + using Image image = Image.Load(options, imageBytes); + using Image reference = Image.Load(referenceBytes); + + Assert.Equal(ProfileFixtureWidth, image.Width); + Assert.Equal(ProfileFixtureHeight, image.Height); + Assert.Single(image.Frames); + + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); + Assert.Equal(HeifCompressionMethod.Av1, metadata.CompressionMethod); + Assert.Equal(metadataBitDepth, metadata.BitDepth); + + CicpProfile colorProfile = Assert.IsType(image.Metadata.CicpProfile); + Assert.Equal(CicpColorPrimaries.ItuRBt709_6, colorProfile.ColorPrimaries); + Assert.Equal(CicpTransferCharacteristics.Iec61966_2_1, colorProfile.TransferCharacteristics); + Assert.Equal(CicpMatrixCoefficients.ItuRBt601_7_525, colorProfile.MatrixCoefficients); + Assert.True(colorProfile.FullRange); + ImageComparer.Exact.VerifySimilarity(reference, image); + } + + /// + /// Gets the Y4M chroma tags that encode one AV1 bit-depth and sampling-layout combination. + /// + /// The encoded AV1 sample precision. + /// The encoded AV1 chroma-sampling layout. + /// The Y4M C tag and extended XYSCSS tag. + private static (string ChromaTag, string ExtendedChromaTag) GetY4mColorSpace(Av1BitDepth bitDepth, Av1ColorFormat colorFormat) + { + // Y4M uses a legacy 420jpeg name at eight bits, lowercase p in high-depth C tags, and uppercase P in the + // corresponding XYSCSS tags. Keeping the exact spellings detects a reference generated with different layout. + return (bitDepth, colorFormat) switch + { + (Av1BitDepth.EightBit, Av1ColorFormat.Yuv400) => ("mono", "400"), + (Av1BitDepth.EightBit, Av1ColorFormat.Yuv420) => ("420jpeg", "420JPEG"), + (Av1BitDepth.EightBit, Av1ColorFormat.Yuv422) => ("422", "422"), + (Av1BitDepth.EightBit, Av1ColorFormat.Yuv444) => ("444", "444"), + (Av1BitDepth.TenBit, Av1ColorFormat.Yuv400) => ("mono10", "400"), + (Av1BitDepth.TenBit, Av1ColorFormat.Yuv420) => ("420p10", "420P10"), + (Av1BitDepth.TenBit, Av1ColorFormat.Yuv422) => ("422p10", "422P10"), + (Av1BitDepth.TenBit, Av1ColorFormat.Yuv444) => ("444p10", "444P10"), + (Av1BitDepth.TwelveBit, Av1ColorFormat.Yuv400) => ("mono12", "400"), + (Av1BitDepth.TwelveBit, Av1ColorFormat.Yuv420) => ("420p12", "420P12"), + (Av1BitDepth.TwelveBit, Av1ColorFormat.Yuv422) => ("422p12", "422P12"), + _ => ("444p12", "444P12") + }; + } + /// /// Validates every active-CDEF fixture under the hardware configuration selected by . /// @@ -439,7 +764,7 @@ public class Av1ReconstructionConformanceTests Assert.NotNull(decoder.FrameHeader); Assert.True(decoder.FrameHeader.AllowIntraBlockCopy); Assert.NotEqual(0, GetIntraBlockCopyBlockCount(decoder)); - AssertNativePlanesEqual(frameBuffer, nativeReference); + AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); } /// @@ -912,7 +1237,7 @@ public class Av1ReconstructionConformanceTests Assert.Equal(RequiredPaletteCoverage, GetPaletteCoverage(decoder)); } - AssertNativePlanesEqual(frameBuffer, reference); + AssertNativePlanesEqual(decoder, frameBuffer, reference); return restorationCoverage; } @@ -985,7 +1310,7 @@ public class Av1ReconstructionConformanceTests Assert.True(hasCodedResidual); - AssertNativePlanesEqual(frameBuffer, nativeReference); + AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); } /// @@ -1398,9 +1723,10 @@ public class Av1ReconstructionConformanceTests /// /// Compares every visible native component sample with the independent planar reference. /// + /// The decoder state used to identify the coded block containing a mismatch. /// 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) + private static void AssertNativePlanesEqual(Av1Decoder decoder, Av1FrameBuffer frameBuffer, ReadOnlySpan reference) { (int chromaSubsamplingX, int chromaSubsamplingY) = frameBuffer.ColorFormat switch { @@ -1413,6 +1739,13 @@ public class Av1ReconstructionConformanceTests ReadOnlySpan planes = frameBuffer.ColorFormat == Av1ColorFormat.Yuv400 ? [Av1Plane.Y] : [Av1Plane.Y, Av1Plane.U, Av1Plane.V]; + int mismatchCount = 0; + Av1Plane largestMismatchPlane = default; + int largestMismatchX = 0; + int largestMismatchY = 0; + ushort largestExpected = 0; + ushort largestActual = 0; + StringBuilder mismatchDescription = null; foreach (Av1Plane plane in planes) { @@ -1430,7 +1763,25 @@ public class Av1ReconstructionConformanceTests ReadOnlySpan expectedRow = reference.Slice(referenceOffset, planeWidth); for (int x = 0; x < planeWidth; x++) { - AssertSampleEqual(plane, x, y, expectedRow[x], actualRow[x]); + if (expectedRow[x] != actualRow[x]) + { + if (mismatchCount < 16) + { + mismatchDescription ??= new StringBuilder(); + mismatchDescription.Append($" {plane}({x},{y})={expectedRow[x]}/{actualRow[x]}"); + } + + if (mismatchCount == 0 || Math.Abs(expectedRow[x] - actualRow[x]) > Math.Abs(largestExpected - largestActual)) + { + largestMismatchPlane = plane; + largestMismatchX = x; + largestMismatchY = y; + largestExpected = expectedRow[x]; + largestActual = actualRow[x]; + } + + mismatchCount++; + } } referenceOffset += planeWidth; @@ -1445,7 +1796,26 @@ public class Av1ReconstructionConformanceTests for (int x = 0; x < planeWidth; x++) { ushort expected = BinaryPrimitives.ReadUInt16LittleEndian(reference.Slice(referenceOffset, sizeof(ushort))); - AssertSampleEqual(plane, x, y, expected, actualRow[x]); + if (expected != actualRow[x]) + { + if (mismatchCount < 16) + { + mismatchDescription ??= new StringBuilder(); + mismatchDescription.Append($" {plane}({x},{y})={expected}/{actualRow[x]}"); + } + + if (mismatchCount == 0 || Math.Abs(expected - actualRow[x]) > Math.Abs(largestExpected - largestActual)) + { + largestMismatchPlane = plane; + largestMismatchX = x; + largestMismatchY = y; + largestExpected = expected; + largestActual = actualRow[x]; + } + + mismatchCount++; + } + referenceOffset += sizeof(ushort); } } @@ -1453,6 +1823,15 @@ public class Av1ReconstructionConformanceTests } Assert.Equal(reference.Length, referenceOffset); + AssertSampleEqual( + decoder, + largestMismatchPlane, + largestMismatchX, + largestMismatchY, + largestExpected, + largestActual, + mismatchCount, + mismatchDescription?.ToString() ?? string.Empty); } /// @@ -1467,16 +1846,126 @@ public class Av1ReconstructionConformanceTests /// /// Reports the exact component coordinate when independently decoded samples differ. /// + /// The decoder state used to identify the coded block containing the sample. /// 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) + /// The total number of unequal native samples. + /// The first unequal samples in plane traversal order. + private static void AssertSampleEqual( + Av1Decoder decoder, + Av1Plane plane, + int x, + int y, + ushort expected, + ushort actual, + int mismatchCount, + string mismatchDescription) { if (expected != actual) { - Assert.Fail($"Plane {plane} differs at ({x}, {y}): expected {expected}, actual {actual}."); + Av1FrameInfo frameInfo = Assert.IsType(decoder.FrameInfo); + int modeInfoColumn = x >> Av1Constants.ModeInfoSizeLog2; + int modeInfoRow = y >> Av1Constants.ModeInfoSizeLog2; + Av1BlockModeInfo modeInfo = frameInfo.GetModeInfoAt(new Point(modeInfoColumn, modeInfoRow)); + int blockColumn = modeInfoColumn; + while (blockColumn > 0 && ReferenceEquals(frameInfo.GetModeInfoAt(new Point(blockColumn - 1, modeInfoRow)), modeInfo)) + { + blockColumn--; + } + + int blockRow = modeInfoRow; + while (blockRow > 0 && ReferenceEquals(frameInfo.GetModeInfoAt(new Point(modeInfoColumn, blockRow - 1)), modeInfo)) + { + blockRow--; + } + + int superblockSize = frameInfo.SuperblockModeInfoSize; + Av1SuperblockInfo superblock = frameInfo.GetSuperblock(new Point(blockColumn / superblockSize, blockRow / superblockSize)); + Span transforms = superblock.GetTransformInfoY().Slice( + modeInfo.GetFirstTransformLocation(Av1Plane.Y), + modeInfo.GetTransformUnitCount(Av1Plane.Y)); + + Av1TransformInfo containingTransform = transforms[0]; + int containingTransformIndex = 0; + int transformColumn = modeInfoColumn - blockColumn; + int transformRow = modeInfoRow - blockRow; + for (int transformIndex = 0; transformIndex < transforms.Length; transformIndex++) + { + Av1TransformInfo transform = transforms[transformIndex]; + if (transformColumn >= transform.OffsetX && transformColumn < transform.OffsetX + transform.Size.Get4x4WideCount() + && transformRow >= transform.OffsetY && transformRow < transform.OffsetY + transform.Size.Get4x4HighCount()) + { + containingTransform = transform; + containingTransformIndex = transformIndex; + break; + } + } + + int superblockTransformIndex = modeInfo.GetFirstTransformLocation(Av1Plane.Y) + containingTransformIndex; + Span superblockTransforms = superblock.GetTransformInfoY(); + Span superblockCoefficients = superblock.CoefficientsY; + int coefficientOffset = 0; + for (int transformIndex = 0; transformIndex < superblockTransformIndex; transformIndex++) + { + if (superblockTransforms[transformIndex].CodeBlockFlag) + { + coefficientOffset += superblockCoefficients[coefficientOffset] + 1; + } + } + + StringBuilder coefficientDescription = new(); + if (containingTransform.CodeBlockFlag) + { + int coefficientCount = superblockCoefficients[coefficientOffset]; + coefficientDescription.Append($", quantized-coefficients={coefficientCount}:["); + for (int coefficientIndex = 0; coefficientIndex < coefficientCount; coefficientIndex++) + { + if (coefficientIndex != 0) + { + coefficientDescription.Append(','); + } + + coefficientDescription.Append(superblockCoefficients[coefficientOffset + coefficientIndex + 1]); + } + + coefficientDescription.Append(']'); + } + + ObuFrameHeader frameHeader = Assert.IsType(decoder.FrameHeader); + int cdefUnitColumn = (modeInfoColumn % superblockSize) / CdefUnitModeInfoSize; + int cdefUnitRow = (modeInfoRow % superblockSize) / CdefUnitModeInfoSize; + int cdefStrengthIndex = frameInfo.GetCdefStrength(superblock.Position)[cdefUnitColumn + (cdefUnitRow << 1)]; + int cdefStrength = cdefStrengthIndex < 0 ? -1 : frameHeader.CdefParameters.YStrength[cdefStrengthIndex]; + int nextModeInfoRow = Math.Min(modeInfoRow + 1, frameHeader.ModeInfoRowCount - 1); + Av1BlockModeInfo nextRowModeInfo = frameInfo.GetModeInfoAt(new Point(modeInfoColumn, nextModeInfoRow)); + Av1BlockModeInfo aboveModeInfo = frameInfo.GetModeInfoAt(new Point(modeInfoColumn, Math.Max(blockRow - 1, 0))); + Av1BlockModeInfo leftModeInfo = frameInfo.GetModeInfoAt(new Point(Math.Max(blockColumn - 1, 0), modeInfoRow)); + + // Exact conformance failures need the owning syntax state. A coordinate alone does not distinguish + // prediction, residual reconstruction, and in-loop filtering failures inside a large coded frame. + Assert.Fail( + $"Plane {plane} differs at ({x}, {y}): expected {expected}, actual {actual}. " + + $"Total unequal samples={mismatchCount}:{mismatchDescription}. " + + $"Block={modeInfo.BlockSize}, mode={modeInfo.YMode}, partition={modeInfo.PartitionType}, skip={modeInfo.Skip}, " + + $"filter-intra={modeInfo.UseFilterIntra}/{modeInfo.FilterIntraMode}, angle-delta={modeInfo.GetAngleDelta(plane)}, " + + $"palette-size={modeInfo.GetPaletteSize(plane)}, transforms={modeInfo.GetTransformUnitCount(plane)}, " + + $"transform={containingTransform.Size}/{containingTransform.Type}/coded={containingTransform.CodeBlockFlag} " + + $"at ({containingTransform.OffsetX}, {containingTransform.OffsetY}), block-origin=({blockColumn}, {blockRow}). " + + $"Loop-filter={frameHeader.LoopFilterParameters.FilterLevel[0]}/{frameHeader.LoopFilterParameters.FilterLevel[1]}, " + + $"sharpness={frameHeader.LoopFilterParameters.SharpnessLevel}, delta-q={frameHeader.DeltaQParameters.IsPresent}, " + + $"superblock-q={superblock.SuperblockQuantizerIndex}{coefficientDescription}, " + + $"delta-lf={frameHeader.DeltaLoopFilterParameters.IsPresent}/{frameHeader.DeltaLoopFilterParameters.IsMulti}, " + + $"CDEF={cdefStrengthIndex}/{cdefStrength}, restoration={frameHeader.LoopRestorationParameters.Items[0].Type}, " + + $"film-grain={frameHeader.FilmGrainParameters.ApplyGrain}, " + + $"tiles={frameHeader.TilesInfo.TileColumnCount}x{frameHeader.TilesInfo.TileRowCount}, " + + $"first-tile-end=({frameHeader.TilesInfo.TileColumnStartModeInfo[1]}, {frameHeader.TilesInfo.TileRowStartModeInfo[1]}). " + + $"Neighbors: above={aboveModeInfo.BlockSize}/{aboveModeInfo.YMode}/skip={aboveModeInfo.Skip}, " + + $"left={leftModeInfo.BlockSize}/{leftModeInfo.YMode}/skip={leftModeInfo.Skip}, " + + $"next-row={nextRowModeInfo.BlockSize}/{nextRowModeInfo.YMode}/skip={nextRowModeInfo.Skip}/" + + $"angle-delta={nextRowModeInfo.GetAngleDelta(plane)}/transforms={nextRowModeInfo.GetTransformUnitCount(plane)}."); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1895b7ef15..45cdb3bc43 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1365,6 +1365,42 @@ public static class TestImages public const string Av1Cdef12BitReference = "Heif/Av1/Conformance/libaom-cdef-cosmos-12b-libaom.yuv"; public const string Av1Cdef12BitAvif = "Heif/Av1/Conformance/libavif-cdef-cosmos-12b.avif"; public const string Av1Cdef12BitPresentationReference = "Heif/Av1/Conformance/libavif-cdef-cosmos-12b.png"; + public const string Av1Profile8BitMonochromeAvif = "Heif/Av1/Conformance/libavif-profile-8b-400.avif"; + public const string Av1Profile8BitMonochromeReference = "Heif/Av1/Conformance/libavif-profile-8b-400-libaom-y4m.yuv"; + public const string Av1Profile8BitMonochromePresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-400.png"; + public const string Av1Profile8Bit420Avif = "Heif/Av1/Conformance/libavif-profile-8b-420.avif"; + public const string Av1Profile8Bit420Reference = "Heif/Av1/Conformance/libavif-profile-8b-420-libaom-y4m.yuv"; + public const string Av1Profile8Bit420PresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-420.png"; + public const string Av1Profile8Bit422Avif = "Heif/Av1/Conformance/libavif-profile-8b-422.avif"; + public const string Av1Profile8Bit422Reference = "Heif/Av1/Conformance/libavif-profile-8b-422-libaom-y4m.yuv"; + public const string Av1Profile8Bit422PresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-422.png"; + public const string Av1Profile8Bit444Avif = "Heif/Av1/Conformance/libavif-profile-8b-444.avif"; + public const string Av1Profile8Bit444Reference = "Heif/Av1/Conformance/libavif-profile-8b-444-libaom-y4m.yuv"; + public const string Av1Profile8Bit444PresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-444.png"; + public const string Av1Profile10BitMonochromeAvif = "Heif/Av1/Conformance/libavif-profile-10b-400.avif"; + public const string Av1Profile10BitMonochromeReference = "Heif/Av1/Conformance/libavif-profile-10b-400-libaom-y4m.yuv"; + public const string Av1Profile10BitMonochromePresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-400.png"; + public const string Av1Profile10Bit420Avif = "Heif/Av1/Conformance/libavif-profile-10b-420.avif"; + public const string Av1Profile10Bit420Reference = "Heif/Av1/Conformance/libavif-profile-10b-420-libaom-y4m.yuv"; + public const string Av1Profile10Bit420PresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-420.png"; + public const string Av1Profile10Bit422Avif = "Heif/Av1/Conformance/libavif-profile-10b-422.avif"; + public const string Av1Profile10Bit422Reference = "Heif/Av1/Conformance/libavif-profile-10b-422-libaom-y4m.yuv"; + public const string Av1Profile10Bit422PresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-422.png"; + public const string Av1Profile10Bit444Avif = "Heif/Av1/Conformance/libavif-profile-10b-444.avif"; + public const string Av1Profile10Bit444Reference = "Heif/Av1/Conformance/libavif-profile-10b-444-libaom-y4m.yuv"; + public const string Av1Profile10Bit444PresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-444.png"; + public const string Av1Profile12BitMonochromeAvif = "Heif/Av1/Conformance/libavif-profile-12b-400.avif"; + public const string Av1Profile12BitMonochromeReference = "Heif/Av1/Conformance/libavif-profile-12b-400-libaom-y4m.yuv"; + public const string Av1Profile12BitMonochromePresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-400.png"; + public const string Av1Profile12Bit420Avif = "Heif/Av1/Conformance/libavif-profile-12b-420.avif"; + public const string Av1Profile12Bit420Reference = "Heif/Av1/Conformance/libavif-profile-12b-420-libaom-y4m.yuv"; + public const string Av1Profile12Bit420PresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-420.png"; + public const string Av1Profile12Bit422Avif = "Heif/Av1/Conformance/libavif-profile-12b-422.avif"; + public const string Av1Profile12Bit422Reference = "Heif/Av1/Conformance/libavif-profile-12b-422-libaom-y4m.yuv"; + public const string Av1Profile12Bit422PresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-422.png"; + public const string Av1Profile12Bit444Avif = "Heif/Av1/Conformance/libavif-profile-12b-444.avif"; + public const string Av1Profile12Bit444Reference = "Heif/Av1/Conformance/libavif-profile-12b-444-libaom-y4m.yuv"; + public const string Av1Profile12Bit444PresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-444.png"; public const string Av1Palette8BitPayload = "Heif/Av1/Conformance/libaom-palette-draw-points-8b-444.bit"; 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"; diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400-libaom-y4m.yuv new file mode 100644 index 0000000000..d1c20f8290 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c71bca8da6ee62c42e1ebdcfcba89e2829f8fd9569d3bf8107c8321ed085b06 +size 262220 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.avif new file mode 100644 index 0000000000..428648e41c --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78d25037c2c41f387e74a88ed844fe9888f64e88f8155af31ccf994f5566c23d +size 1631 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.png new file mode 100644 index 0000000000..25a8163e49 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ed0fd0f21b2c5620b7b6289cf3ebdd6001e8498ce7b0daec17d5657051f9cea +size 5224 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420-libaom-y4m.yuv new file mode 100644 index 0000000000..aee84e102f --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39b2dca5c922a09a085b798fdf9cad0ce218418eb0fd33a08388ff05e6dd3114 +size 393295 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.avif new file mode 100644 index 0000000000..4aadeb766b --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5df732dc3c72684f35dfa9c69781133e6383ae8406e66e57d8cc3fa5e0dd852d +size 1682 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.png new file mode 100644 index 0000000000..30a54877bb --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:649c9fef1d87858cc6b49b7fcf51ad691ea22f0a513cd69ab61a3bf1943dd1bf +size 9635 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422-libaom-y4m.yuv new file mode 100644 index 0000000000..51aa38edc4 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79c6e4560af81fe427bc38f1fa64ee43622d1ec02a7876a533ccb6be72955a9e +size 524367 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.avif new file mode 100644 index 0000000000..1dd877072f --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3420ea3f3fb2430ffa502a85190e3aab9aafdeb24880748d023b3a5091943c6d +size 1685 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.png new file mode 100644 index 0000000000..90ecec2d0d --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c1a70c907c1040fcb7b2a6618fb0f9c84a4ddfdf441238138f9f3349fb79696 +size 9573 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444-libaom-y4m.yuv new file mode 100644 index 0000000000..3cd001634e --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad9f1b3318f9795f325a2f8d4e6dd5e5ea2c4ea51713f6aa9dab302a970b25bb +size 786511 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.avif new file mode 100644 index 0000000000..e7f3f99313 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:354e339eaf0e6e2889659c2a889d65b9bdf6022543fb9f9522d11301251e0075 +size 1682 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.png new file mode 100644 index 0000000000..30a54877bb --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:649c9fef1d87858cc6b49b7fcf51ad691ea22f0a513cd69ab61a3bf1943dd1bf +size 9635 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400-libaom-y4m.yuv new file mode 100644 index 0000000000..70b3404a26 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a020ff72013124975caae5823eaaa1abd3ed66e19cf6ccb31ff96fcd0b63a084 +size 262220 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.avif new file mode 100644 index 0000000000..d7d93a454c --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72af196f86395af9b5939598be97c45cd065ad4b62c276a0486bf76a6568020b +size 1643 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.png new file mode 100644 index 0000000000..2c50dec739 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53c0c2e538c85323fceee54d30b7ba29d2af5fd9770a617faceadb9f2a502b2c +size 5459 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420-libaom-y4m.yuv new file mode 100644 index 0000000000..c40c8ac495 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b3b67cc8fff91e5302f02f4718967b9a2871b321109defdafb85dd46b558876 +size 393295 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.avif new file mode 100644 index 0000000000..f0a41f80c0 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:063d1980df27ae7ff996c437d962ca51d4615d6f745eca6cc55a5c57a05c761d +size 1688 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.png new file mode 100644 index 0000000000..b3b82c26c1 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:589a61003f368ce59defd0e2334b5d50bfa24119e488bea19c56542bcfc4e930 +size 10122 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422-libaom-y4m.yuv new file mode 100644 index 0000000000..79d63b266f --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efbb14ce47121971afca860b811b34da9414fb961a73e2f16fd403d835cf89d1 +size 524367 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.avif new file mode 100644 index 0000000000..f87357b03a --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:80d606728693f5f890fc1ffb7a2bcff1b2128b783143445fdbed89da30b1353f +size 1686 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.png new file mode 100644 index 0000000000..d06bbba677 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c86a0e37069641c3e077428f2a0632081ef3b8fe997e10721347377ad98d14f +size 10142 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444-libaom-y4m.yuv new file mode 100644 index 0000000000..b802feb305 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43907add76f881850cfdc4ed23655dc71443c8d40ef16093b51745650dc66307 +size 786511 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.avif new file mode 100644 index 0000000000..ae98187a54 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f35443d16382c2d184adc3e518230ce4df497a429d101c92b96bb592b50c1a36 +size 1683 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.png new file mode 100644 index 0000000000..5658d5ae11 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13b3e95816e3b98016fc7b8c11e161a3204e0dcf9a38008254d1468ec7e73769 +size 9942 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400-libaom-y4m.yuv new file mode 100644 index 0000000000..33c5a69c78 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da90f960e2297224b621ff866353d89ddb0dd9ed0ffcb201d4b5e49c250c5c07 +size 131146 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.avif new file mode 100644 index 0000000000..6452bda077 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b33f3d2f20a4d1d828ee3ed44e94e0ac5a13caa3971e0279ba740581437c194 +size 1665 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.png new file mode 100644 index 0000000000..e55b20c57f --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:260a860d1f01e56c0154a31a6f4802fd27b5f507f724d55084f5278b388003c2 +size 5294 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420-libaom-y4m.yuv new file mode 100644 index 0000000000..1257f0c682 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98342115d81519b685c3c3d4077e74896b5c3ebc6eb44ccfe11dd20f43fc06df +size 196689 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.avif new file mode 100644 index 0000000000..d6934fac62 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16353df2ed0b1e5f3b5111e6f514e8ba56b81be8b20aae5b4d07ccf71f203538 +size 1718 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.png new file mode 100644 index 0000000000..fae45e031a --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b39c31c012ad7e194870fcdd074a83f225dc0dfc40731f0c72fa8847821e0fd +size 9631 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422-libaom-y4m.yuv new file mode 100644 index 0000000000..c398ab5335 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd25de31e7c3175b8854cdf63ce233d2657b07ba038158286763c19ab4ca60cc +size 262217 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.avif new file mode 100644 index 0000000000..40f000b051 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b1f8d6ae7131d2596f43ac9a67c0afce6f4cb4eacd323383a22073bcb8afc05a +size 1736 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.png new file mode 100644 index 0000000000..abdbafc004 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:253291bc0bcebde6cc0ef6729c52ec025cba4a7ed046a3231297da7c63df3f4a +size 9748 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444-libaom-y4m.yuv b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444-libaom-y4m.yuv new file mode 100644 index 0000000000..418816b6d0 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444-libaom-y4m.yuv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dae8878737e0afcc7084a252f5963bc8915e0febbf7a92284bad14bb8723e826 +size 393289 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.avif b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.avif new file mode 100644 index 0000000000..573da92774 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.avif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef6c09e4c7b3ecfcc7fef52abe3eab6afe422ec6bf9fd0fd3af00db445384a6f +size 1722 diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.png b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.png new file mode 100644 index 0000000000..3e0b2f65d6 --- /dev/null +++ b/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96423c89e68f6d4e6a349e0693b1c0b106055654681d51c822ab43fd12b86223 +size 9703