Browse Source

Complete official AV1 intra-block-copy checkpoint

pull/2633/head
James Jackson-South 4 days ago
parent
commit
ea2fa48471
  1. 7
      HEIF_IMPLEMENTATION_PLAN.md
  2. 20
      src/ImageSharp/Formats/Heif/Av1/Motion/Av1IntraBlockCopy.cs
  3. 2
      src/ImageSharp/Formats/Heif/Av1/Motion/Av1ReferenceMotionVectors.cs
  4. 10
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs
  5. 93
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs
  6. 2
      tests/ImageSharp.Tests/TestImages.cs
  7. 3
      tests/Images/Input/Heif/Av1/Conformance/libaom-av1-1-b8-16-intra_only-intrabc-extreme-dv-libaom.y4m
  8. 3
      tests/Images/Input/Heif/Av1/Conformance/libaom-av1-1-b8-16-intra_only-intrabc-extreme-dv.ivf

7
HEIF_IMPLEMENTATION_PLAN.md

@ -39,7 +39,9 @@ Commit `beb2ab86ce5e4052c667df30af8a48a860814031` records the complete progressi
Commit `ef93d584511055f8e91e8d801662c44a5b0984d9` records the complete twelve-bit inverse-transform arithmetic checkpoint. ADST4 retains pinned libaom's signed 32-bit sine products and factorized sums and widens only its terminal rounding; Identity4 and Identity16 widen their fixed-point product and rounding bias only for the 20-bit twelve-bit row stage. The established 8/10-bit and twelve-bit column paths remain unchanged. Exact boundary vectors cover both 128-bit and 256-bit operators through normal, AVX-512-disabled, AVX-disabled, and scalar `FeatureTestRunner` configurations. Both source targets build with zero warnings and errors, the `net10.0` test-project analyzer build completes with zero errors and 1,014 pre-existing repository warnings, Roslynk reports zero compiler errors, 510 focused inverse-transform cases and 44 production reconstruction cases pass without failures or skips, and `git diff --check` is clean. Commit `ef93d584511055f8e91e8d801662c44a5b0984d9` records the complete twelve-bit inverse-transform arithmetic checkpoint. ADST4 retains pinned libaom's signed 32-bit sine products and factorized sums and widens only its terminal rounding; Identity4 and Identity16 widen their fixed-point product and rounding bias only for the 20-bit twelve-bit row stage. The established 8/10-bit and twelve-bit column paths remain unchanged. Exact boundary vectors cover both 128-bit and 256-bit operators through normal, AVX-512-disabled, AVX-disabled, and scalar `FeatureTestRunner` configurations. Both source targets build with zero warnings and errors, the `net10.0` test-project analyzer build completes with zero errors and 1,014 pre-existing repository warnings, Roslynk reports zero compiler errors, 510 focused inverse-transform cases and 44 production reconstruction cases pass without failures or skips, and `git diff --check` is clean.
The working tree contains a complete, verified official syntax-coverage and predictor-architecture checkpoint awaiting commit. The official all-intra, CDF-update, and temporal motion-field IVF files have SHA-1 `A9F7EA6312A533CC6426A6145EDD190D45813C37`, `AFCA5502A489692B0A3C120370B0F43B8FC572A1`, and `B48A717C7C003B8DD23C3C2CAED1AC673380FDB3`, exactly matching the pinned libaom manifest. Their SHA-256 values are `5FCD265FD9F9BDD0D3179340B4C4532F1422CA5E5D97741C7481B84CB5DC122F`, `14A3DBF537B6BF15EFC003182D9916D61438C93624A8BD26E6E3AE7EAF33EA82`, and `B59BF9586D8546DFDA81DFEC4EE4E32CEB502C9D22412AB0B63A2ABB534A1F14`; the pinned-libaom Y4M references have SHA-256 `1211EBEFBC9CCEF9ED19BE4CCE3F807D69FFFE338E95CCA1B5F4CA8023482175`, `4FBFF73FF0DE2D9084DAE557D1D4BD677B0486516525BF4D327D2D795D5A7779`, and `F7DB607694818C19E62FD9A27F53E1A3E2D00B72C39C0430C1B26399CC76777D`. Exact native-plane comparison covers all 39 all-intra frames, every intra mode, seven selected transform types, both tile-local and frame-end adaptive CDF publication, all four temporal motion-field frames under normal/scalar dispatch, and constrained tracked motion-field allocation with exactly-once returns. Every distinct AV1 predictor traversal now owns a family-named JPEG-style static operator contract and SIMD traversal instead of nesting separate predictors beneath broad intra/inter families. Compound reference convolution, equal averaging, distance weighting, alpha-mask blending, difference-weighted mask construction, and each intermediate reconstruction or mask traversal have separate family owners and matching `.Operator.cs` contracts; inter-intra mask construction has its own non-operator builder. Both Release source targets build with zero warnings and errors, Roslynk reports zero compiler errors, 179 focused prediction, reconstruction, reference, ownership, and lifecycle cases pass without failures or skips, and `git diff --check` is clean. Commit `5ba048be3667064f219ee230be7c8976927ea200` records the complete, verified official syntax-coverage and predictor-architecture checkpoint. SharedInfrastructure commit `a835a9d74e82b2d32b580a7902eb2699ebc47098` is pushed to `origin/main`; the ImageSharp gitlink and synchronized root attributes assign IVF and Y4M fixtures to Git LFS. The official all-intra, CDF-update, and temporal motion-field IVF files have SHA-1 `A9F7EA6312A533CC6426A6145EDD190D45813C37`, `AFCA5502A489692B0A3C120370B0F43B8FC572A1`, and `B48A717C7C003B8DD23C3C2CAED1AC673380FDB3`, exactly matching the pinned libaom manifest. Their SHA-256 values are `5FCD265FD9F9BDD0D3179340B4C4532F1422CA5E5D97741C7481B84CB5DC122F`, `14A3DBF537B6BF15EFC003182D9916D61438C93624A8BD26E6E3AE7EAF33EA82`, and `B59BF9586D8546DFDA81DFEC4EE4E32CEB502C9D22412AB0B63A2ABB534A1F14`; the pinned-libaom Y4M references have SHA-256 `1211EBEFBC9CCEF9ED19BE4CCE3F807D69FFFE338E95CCA1B5F4CA8023482175`, `4FBFF73FF0DE2D9084DAE557D1D4BD677B0486516525BF4D327D2D795D5A7779`, and `F7DB607694818C19E62FD9A27F53E1A3E2D00B72C39C0430C1B26399CC76777D`. Exact native-plane comparison covers all 39 all-intra frames, every intra mode, seven selected transform types, both tile-local and frame-end adaptive CDF publication, all four temporal motion-field frames under normal/scalar dispatch, and constrained tracked motion-field allocation with exactly-once returns. Every distinct AV1 predictor traversal now owns a family-named JPEG-style static operator contract and SIMD traversal instead of nesting separate predictors beneath broad intra/inter families. Compound reference convolution, equal averaging, distance weighting, alpha-mask blending, difference-weighted mask construction, and each intermediate reconstruction or mask traversal have separate family owners and matching `.Operator.cs` contracts; inter-intra mask construction has its own non-operator builder. Filtered intra-block-copy horizontal, vertical, and bilinear phases own separate family-named types, tap-exact static operator contracts, and family-owned SIMD/scalar traversals; the broad dispatcher retains only whole-sample copy and phase routing. Both Release source targets build with zero warnings and errors, Roslynk reports zero compiler errors, 102 final-tree focused predictor and reconstruction cases pass without failures or skips, and `git diff --check` is clean.
The working tree contains a complete, verified official extreme-displacement intra-block-copy checkpoint awaiting commit. The two-frame 1920x1080 YUV420 IVF has SHA-1 `C7F336958E7AF6162C20DDC84D67C7DFA9826910`, exactly matching the pinned libaom manifest, and SHA-256 `0252716FE7A7C7F1EBB1EB23920A6737F45C10DFBA942304BD339AE42B5C576C`; its pinned-libaom Y4M has SHA-256 `8CF7851E112172C62799F8BFDF895505742A3CA77E339C12E547AD2C47AF41B3`. The source corrects the spatial scan's four-mode-info-unit step threshold from 16-sample blocks to libaom's 64-sample boundary, clamps the ranked displacement stack before reference selection, and treats intra-block-copy neighbors as inter for transform-size context. Exact production native-plane comparison covers both complete official frames under normal and scalar `FeatureTestRunner` dispatch, while the existing independent 8/10/12-bit native-plane and presentation matrix remains clean. Both Release source targets build with zero warnings and errors, Roslynk reports zero compiler errors, 170 focused intra-block-copy, frame-buffer, reference-MV, inter-mode, and transform-size tests pass without failures or skips, and `git diff --check` is clean.
Status meanings: Status meanings:
@ -51,7 +53,7 @@ Status meanings:
Current development stage: **Stage 3 — complete AV1 still-image decoding.** The decoder retains reference/header/CDF/motion-field state, derives frame-level skip-mode references, consumes temporal segment prediction, decodes intra-coded blocks inside inter frames, and reconstructs translational single-reference, compound, inter-intra, OBMC, scaled-reference, local warped, and non-translational global prediction before residual traversal. Commit `1c58d855f70b024170ced9eb0a7005f0f9c955ad` adds exact official four-frame coverage through all ordinary inter modes, all three motion modes, every regular/smooth/sharp dual-filter pair, sub-8x8 chroma prediction, and no-round compound intermediates. Commit `019ac5648b4380a6ff4865072c96fde29ce09fad` adds exact selected-layer native reconstruction and scaled presentation. Neither AV1 nor HEVC production encoding is implemented. Current development stage: **Stage 3 — complete AV1 still-image decoding.** The decoder retains reference/header/CDF/motion-field state, derives frame-level skip-mode references, consumes temporal segment prediction, decodes intra-coded blocks inside inter frames, and reconstructs translational single-reference, compound, inter-intra, OBMC, scaled-reference, local warped, and non-translational global prediction before residual traversal. Commit `1c58d855f70b024170ced9eb0a7005f0f9c955ad` adds exact official four-frame coverage through all ordinary inter modes, all three motion modes, every regular/smooth/sharp dual-filter pair, sub-8x8 chroma prediction, and no-round compound intermediates. Commit `019ac5648b4380a6ff4865072c96fde29ce09fad` adds exact selected-layer native reconstruction and scaled presentation. Neither AV1 nor HEVC production encoding is implemented.
Immediate checkpoint: **inventory and remove the next remaining production-reachable unsupported valid AV1 still-image syntax path.** Trace every explicit rejection through the decoder, distinguish malformed or out-of-scope syntax from valid still-image behavior, select the first valid gap in source order, and close it with exact independent native-plane and presentation evidence before advancing. Immediate checkpoint: **finish and commit the official extreme-displacement intra-block-copy conformance correction.** Complete the focused Release matrix, documentation review, and diff validation, then record the exact evidence before advancing to the next production-reachable unsupported valid AV1 still-image syntax path.
| Order | Delivery stage | State | Delivered state | Gate that remains open | | Order | Delivery stage | State | Delivered state | Gate that remains open |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
@ -575,6 +577,7 @@ Implement and verify in dependency order:
- [x] Intra-block copy for still-image intra frames. - [x] Intra-block copy for still-image intra frames.
- [x] Decode tile-adaptive integer displacement vectors, derive and validate spatial references, apply the inter transform sets, and reconstruct luma and subsampled chroma through allocation-free `Vector512`/`Vector256`/`Vector128` operators with exact-width stores and scalar fallback. `FeatureTestRunner` verifies every transform width, bit-depth storage path, chroma phase, intrinsic tier, scalar continuation, and destination-padding boundary. - [x] Decode tile-adaptive integer displacement vectors, derive and validate spatial references, apply the inter transform sets, and reconstruct luma and subsampled chroma through allocation-free `Vector512`/`Vector256`/`Vector128` operators with exact-width stores and scalar fallback. `FeatureTestRunner` verifies every transform width, bit-depth storage path, chroma phase, intrinsic tier, scalar continuation, and destination-padding boundary.
- [x] Verify displacement-vector entropy, spatial candidate ordering, wavefront legality, native 8/10/12-bit reconstruction, and presented output against independently encoded opaque intra-block-copy AVIF fixtures from the pinned generic libaom/libavif reference. The fixtures require actual intra-block-copy block selection, compare every native plane sample from retained scalar-decoder Y4M output, and compare every presented RGBA byte exactly under normal hardware dispatch and each narrower fallback configuration without a tolerance. - [x] Verify displacement-vector entropy, spatial candidate ordering, wavefront legality, native 8/10/12-bit reconstruction, and presented output against independently encoded opaque intra-block-copy AVIF fixtures from the pinned generic libaom/libavif reference. The fixtures require actual intra-block-copy block selection, compare every native plane sample from retained scalar-decoder Y4M output, and compare every presented RGBA byte exactly under normal hardware dispatch and each narrower fallback configuration without a tolerance.
- [x] Correct libaom's 64-sample spatial-scan step threshold and ranked-reference clamping, consume intra-block-copy transform-size contexts, and compare both complete official extreme-displacement frames exactly with the pinned-libaom native YUV420 reference under normal and scalar dispatch.
- [ ] Inter-frame prediction for layered still-image items. - [ ] Inter-frame prediction for layered still-image items.
- [x] Retain completed ungrained reference planes, frame headers, frame information, and published CDF snapshots in one eight-slot owner; apply refresh flags only after successful completion; resolve full and short reference signaling against occupancy and frame-ID validity; and implement primary-reference selection and `frame_size_with_refs`. - [x] Retain completed ungrained reference planes, frame headers, frame information, and published CDF snapshots in one eight-slot owner; apply refresh flags only after successful completion; resolve full and short reference signaling against occupancy and frame-ID validity; and implement primary-reference selection and `frame_size_with_refs`.
- [x] Inherit primary-reference CDFs, segmentation features and unchanged maps, loop-filter deltas, and same-role global-motion parameters. Initialize the frame-owned per-8x8 temporal motion field and project eligible retained motion vectors in normative reference order. - [x] Inherit primary-reference CDFs, segmentation features and unchanged maps, loop-filter deltas, and same-role global-motion parameters. Initialize the frame-owned per-8x8 temporal motion field and project eligible retained motion vectors in normative reference order.

20
src/ImageSharp/Formats/Heif/Av1/Motion/Av1IntraBlockCopy.cs

@ -109,6 +109,20 @@ internal static class Av1IntraBlockCopy
SortByWeight(candidates, weights, 0, nearestCandidateCount); SortByWeight(candidates, weights, 0, nearestCandidateCount);
SortByWeight(candidates, weights, nearestCandidateCount, candidateCount); SortByWeight(candidates, weights, nearestCandidateCount, candidateCount);
// Libaom clamps the ranked stack before selecting nearest and near. The displacement entropy syntax is
// differential, so using an unclamped spatial candidate changes every following component even though the
// final decoded displacement is validated separately against the stricter intra-block-copy source limits.
for (int index = 0; index < candidateCount; index++)
{
candidates[index] = candidates[index].ClampReference(
blockSize.GetWidth(),
blockSize.GetHeight(),
partitionInfo.ModeBlockToLeftEdge,
partitionInfo.ModeBlockToRightEdge,
partitionInfo.ModeBlockToTopEdge,
partitionInfo.ModeBlockToBottomEdge);
}
Av1MotionVector reference = candidateCount > 0 ? candidates[0] : default; Av1MotionVector reference = candidateCount > 0 ? candidates[0] : default;
if (reference.IsZero && candidateCount > 1) if (reference.IsZero && candidateCount > 1)
{ {
@ -227,7 +241,8 @@ internal static class Av1IntraBlockCopy
} }
} }
bool useFourUnitStep = width >= 4; // Libaom uses the four-mode-info-unit step only once the active block reaches 64 samples.
bool useFourUnitStep = width >= 16;
for (int index = 0; index < end;) for (int index = 0; index < end;)
{ {
Av1BlockModeInfo candidate = partitionInfo.SuperblockInfo.GetModeInfoAt( Av1BlockModeInfo candidate = partitionInfo.SuperblockInfo.GetModeInfoAt(
@ -281,7 +296,8 @@ internal static class Av1IntraBlockCopy
} }
} }
bool useFourUnitStep = height >= 4; // Libaom uses the four-mode-info-unit step only once the active block reaches 64 samples.
bool useFourUnitStep = height >= 16;
for (int index = 0; index < end;) for (int index = 0; index < end;)
{ {
Av1BlockModeInfo candidate = partitionInfo.SuperblockInfo.GetModeInfoAt( Av1BlockModeInfo candidate = partitionInfo.SuperblockInfo.GetModeInfoAt(

2
src/ImageSharp/Formats/Heif/Av1/Motion/Av1ReferenceMotionVectors.cs

@ -338,7 +338,7 @@ internal sealed class Av1ReferenceMotionVectors
else else
{ {
// When the direct single-reference stack has fewer than two entries, AV1 extends it from every inter // When the direct single-reference stack has fewer than two entries, AV1 extends it from every inter
// reference on the immediate above and left blocks. Opposite temporal directions are sign-reversed. // reference in the immediate above and left spatial blocks. Differing reference sign biases are reversed.
for (int index = 0; Math.Abs(maximumRowOffset) >= 1 && index < extensionLength && this.Count < 2;) for (int index = 0; Math.Abs(maximumRowOffset) >= 1 && index < extensionLength && this.Count < 2;)
{ {
Av1BlockModeInfo candidate = partitionInfo.SuperblockInfo.GetModeInfoAt(new Point(column + index, row - 1)); Av1BlockModeInfo candidate = partitionInfo.SuperblockInfo.GetModeInfoAt(new Point(column + index, row - 1));

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

@ -1361,7 +1361,7 @@ internal sealed class Av1TileReader : IAv1TileReader, IDisposable
Av1BlockModeInfo aboveModeInfo = superblockInfo.GetModeInfoAt( Av1BlockModeInfo aboveModeInfo = superblockInfo.GetModeInfoAt(
new Point(partitionInfo.ColumnIndex, partitionInfo.RowIndex - 1)); new Point(partitionInfo.ColumnIndex, partitionInfo.RowIndex - 1));
if (aboveModeInfo.ReferenceFrames[0] > Av1ReferenceFrameType.Intra) if (aboveModeInfo.UseIntraBlockCopy || aboveModeInfo.ReferenceFrames[0] > Av1ReferenceFrameType.Intra)
{ {
above = aboveModeInfo.BlockSize.GetWidth() >= maxTransformSize.GetWidth() ? 1 : 0; above = aboveModeInfo.BlockSize.GetWidth() >= maxTransformSize.GetWidth() ? 1 : 0;
} }
@ -1372,7 +1372,7 @@ internal sealed class Av1TileReader : IAv1TileReader, IDisposable
Av1BlockModeInfo leftModeInfo = superblockInfo.GetModeInfoAt( Av1BlockModeInfo leftModeInfo = superblockInfo.GetModeInfoAt(
new Point(partitionInfo.ColumnIndex - 1, partitionInfo.RowIndex)); new Point(partitionInfo.ColumnIndex - 1, partitionInfo.RowIndex));
if (leftModeInfo.ReferenceFrames[0] > Av1ReferenceFrameType.Intra) if (leftModeInfo.UseIntraBlockCopy || leftModeInfo.ReferenceFrames[0] > Av1ReferenceFrameType.Intra)
{ {
left = leftModeInfo.BlockSize.GetHeight() >= maxTransformSize.GetHeight() ? 1 : 0; left = leftModeInfo.BlockSize.GetHeight() >= maxTransformSize.GetHeight() ? 1 : 0;
} }
@ -2263,9 +2263,13 @@ internal sealed class Av1TileReader : IAv1TileReader, IDisposable
this.displacementVectorWeights); this.displacementVectorWeights);
Av1MotionVector displacement = reader.ReadDisplacementVector(reference); Av1MotionVector displacement = reader.ReadDisplacementVector(reference);
if (!Av1IntraBlockCopy.IsValid(displacement, ref partitionInfo, tileInfo, this.SequenceHeader)) if (!Av1IntraBlockCopy.IsValid(displacement, ref partitionInfo, tileInfo, this.SequenceHeader))
{ {
throw new InvalidImageContentException("Invalid AV1 intra-block-copy displacement vector."); throw new InvalidImageContentException(
$"Invalid AV1 intra-block-copy displacement vector at ({partitionInfo.ColumnIndex}, {partitionInfo.RowIndex}) " +
$"for {partitionInfo.ModeInfo.BlockSize}: reference ({reference.Row}, {reference.Column}), " +
$"decoded ({displacement.Row}, {displacement.Column}).");
} }
partitionInfo.ModeInfo.DisplacementVector = displacement; partitionInfo.ModeInfo.DisplacementVector = displacement;

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

@ -171,6 +171,21 @@ public class Av1ReconstructionConformanceTests
/// </summary> /// </summary>
private const int OfficialMotionFieldFixtureFrameCount = 4; private const int OfficialMotionFieldFixtureFrameCount = 4;
/// <summary>
/// The displayed width of the official libaom extreme-displacement intra-block-copy sequence.
/// </summary>
private const int OfficialIntraBlockCopyFixtureWidth = 1920;
/// <summary>
/// The displayed height of the official libaom extreme-displacement intra-block-copy sequence.
/// </summary>
private const int OfficialIntraBlockCopyFixtureHeight = 1080;
/// <summary>
/// The number of shown frames in the official libaom extreme-displacement intra-block-copy sequence.
/// </summary>
private const int OfficialIntraBlockCopyFixtureFrameCount = 2;
/// <summary> /// <summary>
/// The coverage bit representing tile-local adaptive CDF updates. /// The coverage bit representing tile-local adaptive CDF updates.
/// </summary> /// </summary>
@ -1069,6 +1084,84 @@ public class Av1ReconstructionConformanceTests
ValidateOfficialMotionFieldFixture, ValidateOfficialMotionFieldFixture,
ReconstructionConfigurations); ReconstructionConfigurations);
/// <summary>
/// Verifies extreme intra-block-copy displacement vectors against the official pinned-libaom sequence and exact
/// native output under normal and scalar dispatch.
/// </summary>
[Fact]
public void DecodeOfficialIntraBlockCopySequenceMatchesPinnedLibaomReference()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(
ValidateOfficialIntraBlockCopyFixture,
ReconstructionConfigurations);
/// <summary>
/// Decodes the official intra-block-copy sequence and proves that the active copied blocks reconstruct exactly.
/// </summary>
private static void ValidateOfficialIntraBlockCopyFixture()
{
byte[] ivf = TestFile.Create(TestImages.Heif.Av1OfficialIntraBlockCopySequence).Bytes;
byte[] nativeReference = TestFile.Create(TestImages.Heif.Av1OfficialIntraBlockCopySequenceNativeReference).Bytes;
ReadOnlySpan<byte> y4mFileHeader = "YUV4MPEG2 W1920 H1080 F30:1 Ip C420jpeg\n"u8;
ReadOnlySpan<byte> y4mFrameHeader = "FRAME\n"u8;
Assert.True(ivf.AsSpan(0, 4).SequenceEqual("DKIF"u8));
Assert.Equal(0, BinaryPrimitives.ReadUInt16LittleEndian(ivf.AsSpan(4, 2)));
Assert.Equal(32, BinaryPrimitives.ReadUInt16LittleEndian(ivf.AsSpan(6, 2)));
Assert.True(ivf.AsSpan(8, 4).SequenceEqual("AV01"u8));
Assert.Equal(OfficialIntraBlockCopyFixtureWidth, BinaryPrimitives.ReadUInt16LittleEndian(ivf.AsSpan(12, 2)));
Assert.Equal(OfficialIntraBlockCopyFixtureHeight, BinaryPrimitives.ReadUInt16LittleEndian(ivf.AsSpan(14, 2)));
Assert.Equal(
OfficialIntraBlockCopyFixtureFrameCount,
checked((int)BinaryPrimitives.ReadUInt32LittleEndian(ivf.AsSpan(24, 4))));
Assert.True(nativeReference.AsSpan().StartsWith(y4mFileHeader));
int ivfOffset = 32;
int nativeOffset = y4mFileHeader.Length;
int nativeFrameLength =
(OfficialIntraBlockCopyFixtureWidth * OfficialIntraBlockCopyFixtureHeight) +
(2 * (OfficialIntraBlockCopyFixtureWidth >> 1) * (OfficialIntraBlockCopyFixtureHeight >> 1));
int intraBlockCopyBlockCount = 0;
bool allowIntraBlockCopy = false;
using Av1Decoder decoder = new(Configuration.Default);
for (int frameIndex = 0; frameIndex < OfficialIntraBlockCopyFixtureFrameCount; frameIndex++)
{
int payloadLength = checked((int)BinaryPrimitives.ReadUInt32LittleEndian(ivf.AsSpan(ivfOffset, 4)));
ivfOffset += 12;
using ImageFrame<Rgba32> frame = decoder.DecodeSequenceFrame<Rgba32>(
ivf.AsSpan(ivfOffset, payloadLength),
null,
null);
ivfOffset += payloadLength;
Assert.Equal(OfficialIntraBlockCopyFixtureWidth, frame.Width);
Assert.Equal(OfficialIntraBlockCopyFixtureHeight, frame.Height);
Assert.True(nativeReference.AsSpan(nativeOffset).StartsWith(y4mFrameHeader));
nativeOffset += y4mFrameHeader.Length;
Av1FrameBuffer<byte> frameBuffer = Assert.IsType<Av1FrameBuffer<byte>>(decoder.FrameBuffer);
Assert.Equal(OfficialIntraBlockCopyFixtureWidth, frameBuffer.Width);
Assert.Equal(OfficialIntraBlockCopyFixtureHeight, frameBuffer.Height);
Assert.Equal(Av1BitDepth.EightBit, frameBuffer.BitDepth);
Assert.Equal(Av1ColorFormat.Yuv420, frameBuffer.ColorFormat);
AssertNativePlanesEqual(
decoder,
frameBuffer,
nativeReference.AsSpan(nativeOffset, nativeFrameLength));
nativeOffset += nativeFrameLength;
ObuFrameHeader frameHeader = Assert.IsType<ObuFrameHeader>(decoder.FrameHeader);
allowIntraBlockCopy |= frameHeader.AllowIntraBlockCopy;
intraBlockCopyBlockCount += GetIntraBlockCopyBlockCount(decoder);
}
Assert.Equal(ivf.Length, ivfOffset);
Assert.Equal(nativeReference.Length, nativeOffset);
Assert.True(allowIntraBlockCopy);
Assert.NotEqual(0, intraBlockCopyBlockCount);
}
/// <summary> /// <summary>
/// Verifies exact temporal motion-field reconstruction and balanced ownership with a constrained allocator. /// Verifies exact temporal motion-field reconstruction and balanced ownership with a constrained allocator.
/// </summary> /// </summary>

2
tests/ImageSharp.Tests/TestImages.cs

@ -1396,6 +1396,8 @@ public static class TestImages
public const string Av1OfficialMotionVectorSequenceNativeReference = "Heif/Av1/Conformance/libaom-av1-1-b8-05-mv-libaom.y4m"; public const string Av1OfficialMotionVectorSequenceNativeReference = "Heif/Av1/Conformance/libaom-av1-1-b8-05-mv-libaom.y4m";
public const string Av1OfficialMotionFieldSequence = "Heif/Av1/Conformance/libaom-av1-1-b8-06-mfmv.ivf"; public const string Av1OfficialMotionFieldSequence = "Heif/Av1/Conformance/libaom-av1-1-b8-06-mfmv.ivf";
public const string Av1OfficialMotionFieldSequenceNativeReference = "Heif/Av1/Conformance/libaom-av1-1-b8-06-mfmv-libaom.y4m"; public const string Av1OfficialMotionFieldSequenceNativeReference = "Heif/Av1/Conformance/libaom-av1-1-b8-06-mfmv-libaom.y4m";
public const string Av1OfficialIntraBlockCopySequence = "Heif/Av1/Conformance/libaom-av1-1-b8-16-intra_only-intrabc-extreme-dv.ivf";
public const string Av1OfficialIntraBlockCopySequenceNativeReference = "Heif/Av1/Conformance/libaom-av1-1-b8-16-intra_only-intrabc-extreme-dv-libaom.y4m";
public const string Av1Cdef8BitPayload = "Heif/Av1/Conformance/libaom-cdef-kodim23-8b.bit"; public const string Av1Cdef8BitPayload = "Heif/Av1/Conformance/libaom-cdef-kodim23-8b.bit";
public const string Av1Cdef8BitReference = "Heif/Av1/Conformance/libaom-cdef-kodim23-8b-libaom.yuv"; public const string Av1Cdef8BitReference = "Heif/Av1/Conformance/libaom-cdef-kodim23-8b-libaom.yuv";
public const string Av1Cdef8BitAvif = "Heif/Av1/Conformance/libavif-cdef-kodim23-8b.avif"; public const string Av1Cdef8BitAvif = "Heif/Av1/Conformance/libavif-cdef-kodim23-8b.avif";

3
tests/Images/Input/Heif/Av1/Conformance/libaom-av1-1-b8-16-intra_only-intrabc-extreme-dv-libaom.y4m

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

3
tests/Images/Input/Heif/Av1/Conformance/libaom-av1-1-b8-16-intra_only-intrabc-extreme-dv.ivf

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