Browse Source

Complete AV1 local warped prediction checkpoint

pull/2633/head
James Jackson-South 3 days ago
parent
commit
27a522424f
  1. 44
      HEIF_IMPLEMENTATION_PLAN.md
  2. 4
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs
  3. 363
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1WarpedInterPredictorTests.cs
  4. 0
      tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifLocalWarpSequenceMatchesCurrentLibaomReferences_Rgba32_libavif-rotating-grid-local-warp.png
  5. 32
      tests/Images/Input/Heif/Av1/Conformance/README.md

44
HEIF_IMPLEMENTATION_PLAN.md

@ -30,8 +30,8 @@ Reference checkout evidence on 2026-08-31:
Reconciled with the worktree on 2026-08-31.
- [~] The bounded container reader, still-image path, sequence parser, AV1 decoder, color pipeline, presentation pipeline, and broad AV1 test suite exist locally.
- [~] The inter-frame decoder has verified checkpoints through scaled-reference prediction. Local warped
motion and global motion exist locally but remain open until their ordered checkpoints below are completed.
- [~] The inter-frame decoder has verified checkpoints through local warped prediction. Global motion exists
locally but remains open until its ordered checkpoint below is completed.
- [~] Loop filtering, CDEF, super-resolution, restoration, film grain, layered presentation, alpha composition, and color conversion exist locally. Shared-source cleanup changed the current tree, so final production-path verification is open.
- [~] AV1 writer primitives, forward transforms, symbol encoding, and tile-writing source exist locally, but they are not connected to the public encoder.
- [ ] The public AV1 encoder is not implemented. HeifEncoderCore.Encode throws NotSupportedException when AV1 is selected.
@ -184,8 +184,8 @@ The single-reference syntax, buffer, reconstruction, and ownership foundation is
- [x] Difference-weighted compound prediction.
- [x] OBMC.
- [x] Scaled-reference prediction.
- [~] Local warped prediction. Next item.
- [~] Non-translational global prediction.
- [x] Local warped prediction.
- [~] Non-translational global prediction. Next item.
- [~] Inter deblocking decisions and reference/mode deltas.
Verified equal-average compound checkpoint evidence on 2026-08-31:
@ -429,6 +429,42 @@ Verified scaled-reference checkpoint evidence on 2026-08-31:
- [x] The focused Release checkpoint set passes 10/10 on net10.0 and 10/10 on net11.0, with zero failures
or skips. Scoped analyzer and whitespace verification pass for every changed C# file. Roslynk reports
zero compiler errors, `git diff --check` passes, and `.gitattributes` is unchanged.
- [x] The completed checkpoint was committed as `658a9cd1b6e22806decbae923da8800bca03a09e`
with author and committer `James Jackson-South <james_south@hotmail.com>`.
Verified local warped-prediction checkpoint evidence on 2026-08-31:
- [x] Refreshed the clean official libaom `main` checkout and audited the observed revision
`441c439b9916474cac15d2822af47a9ad70674a8`. Motion-mode eligibility and CDF selection match
`read_motion_mode` in `av1/decoder/decodemv.c`; above, left, top-left, and top-right spatial projection
samples and threshold selection match `findSamples` and `selectSamples` in
`av1/common/mvref_common.c`; affine fitting, shear reduction, phase derivation, filters, rounding,
clipping, and invalid-model fallback match `av1/common/warped_motion.c` and
`av1/common/reconinter.c`.
- [x] Mechanically compared all 1,544 ImageSharp and independent-test warped-filter coefficients against
current libaom's `av1_warped_filter`; both comparisons have zero differences. The separate scalar test
transcription covers 8-, 10-, and 12-bit luma and subsampled-chroma coordinates, tail widths, destination
stride preservation, libaom's 12-bit round adjustment, and AVX-512, AVX, 128-bit, and scalar dispatch
through `FeatureTestRunner`.
- [x] Extracted the fixture's exact 2,310-byte AV1 `mdat` payload at AVIF offset 997. Its SHA-256 is
`644D04FE1D1A32BB7A3856AD7EB49CF1EFDE0AC845E55BEAC4170F72353F2391`. Current official
libaom decoded both 256x256 YUV444 frames with one thread, row threading disabled, and all layers enabled.
The complete Y4M SHA-256 is
`8FDC5D46014F5E5A7455A83643AB6F0DA66FC5A984E72A43F8C75BAD8271C299`; the final
frame's 196,608 native samples have SHA-256
`47B2AB39BF3B9DA15C1EC59840F964DFDF227760947F6E1295FB38A84555F75C` and match the
retained native reference with zero differences.
- [x] The real two-frame fixture exercises `Av1BlockDecoder.DecodeBlock()`, requires decoded
`WARPED_CAUSAL` state and the expected multi-sample affine model, compares final native Y, U, and V
planes exactly, compares the retained final presentation through ImageSharp's established reference-output
API, and passes through intrinsic and scalar dispatch. The 1,024-byte constrained tracked-allocator path
passes with motion-field allocations present and balanced exactly-once returns.
- [x] Renamed the stale pinned-reference test and its contract-derived PNG together without changing the PNG
bytes. Its SHA-256 remains
`4490D62FB6679378E92CACA48427359091AD2106BE49FC1A3848F78BE03BEEB1`.
- [x] The focused Release checkpoint set passes 4/4 on net10.0 and 4/4 on net11.0, with zero failures or
skips. Scoped analyzer verification passes for both changed C# files. Roslynk reports zero compiler errors,
`git diff --check` passes, and `.gitattributes` is unchanged.
For every item:

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

@ -1079,11 +1079,11 @@ public class Av1ReconstructionConformanceTests
AverageCompoundFixtureFrameCount);
/// <summary>
/// Verifies production local warped-motion reconstruction against pinned native and presentation references.
/// Verifies production local warped-motion reconstruction against current-libaom native and retained presentation references.
/// </summary>
[Theory]
[WithFile(TestImages.Heif.Av1LocalWarpSequenceAvif, PixelTypes.Rgba32)]
public void DecodeRealLibavifLocalWarpSequenceMatchesPinnedReferences(TestImageProvider<Rgba32> provider)
public void DecodeRealLibavifLocalWarpSequenceMatchesCurrentLibaomReferences(TestImageProvider<Rgba32> provider)
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(
ValidateLocalWarpSequenceWithDefaultConfiguration,
ReconstructionConfigurations,

363
tests/ImageSharp.Tests/Formats/Heif/Av1/Av1WarpedInterPredictorTests.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Heif.Av1.Motion;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction.Inter;
using SixLabors.ImageSharp.Tests.TestUtilities;
@ -14,26 +15,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
public class Av1WarpedInterPredictorTests
{
/// <summary>
/// The hardware configurations covering the portable vector operator and scalar fallback.
/// The hardware configurations covering every descending SIMD width and the scalar fallback.
/// </summary>
private const HwIntrinsics PredictorConfigurations = HwIntrinsics.AllowAll | HwIntrinsics.DisableHWIntrinsic;
private const HwIntrinsics PredictorConfigurations =
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic;
/// <summary>
/// Verifies exact 8-bit vector/scalar parity for luma and subsampled chroma coordinates.
/// Verifies exact 8-bit prediction against the current libaom scalar equations.
/// </summary>
[Fact]
public void BytePredictionMatchesScalarAcrossIntrinsicConfigurations()
public void BytePredictionMatchesCurrentLibaomOracleAcrossIntrinsicConfigurations()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateBytePrediction, PredictorConfigurations);
/// <summary>
/// Verifies exact 8-, 10-, and 12-bit vector/scalar parity for luma and subsampled chroma coordinates.
/// Verifies exact 8-, 10-, and 12-bit prediction against the current libaom scalar equations.
/// </summary>
[Fact]
public void HighBitDepthPredictionMatchesScalarAcrossIntrinsicConfigurations()
public void HighBitDepthPredictionMatchesCurrentLibaomOracleAcrossIntrinsicConfigurations()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateHighBitDepthPrediction, PredictorConfigurations);
/// <summary>
/// Applies the pinned multi-sample affine model to deterministic byte storage.
/// Applies the current-libaom multi-sample affine model to deterministic byte storage.
/// </summary>
private static void ValidateBytePrediction()
{
@ -52,18 +54,17 @@ public class Av1WarpedInterPredictorTests
}
}
Av1GlobalMotionParameters parameters = CreatePinnedParameters();
Av1GlobalMotionParameters parameters = CreateCurrentLibaomParameters();
for (int subsampling = 0; subsampling <= 1; subsampling++)
{
byte[] expected = new byte[destinationStride * height];
byte[] actual = new byte[destinationStride * height];
Array.Fill(expected, (byte)0xD3);
Array.Fill(actual, (byte)0xD3);
short[] expectedScratch = new short[Av1WarpedInterPredictor.WarpedScratchLength];
short[] actualScratch = new short[Av1WarpedInterPredictor.WarpedScratchLength];
Point destinationPosition = subsampling == 0 ? new Point(32, 24) : new Point(16, 12);
Av1WarpedInterPredictor.PredictWarpedScalar(
PredictCurrentLibaomReference(
source,
sourceStride,
new Point(padding, padding),
@ -76,8 +77,8 @@ public class Av1WarpedInterPredictorTests
height,
subsampling,
subsampling,
parameters,
expectedScratch);
8,
parameters);
Av1WarpedInterPredictor.PredictWarped(
source,
@ -100,7 +101,7 @@ public class Av1WarpedInterPredictorTests
}
/// <summary>
/// Applies the pinned multi-sample affine model to every supported high-bit-depth precision.
/// Applies the current-libaom multi-sample affine model to every supported high-bit-depth precision.
/// </summary>
private static void ValidateHighBitDepthPrediction()
{
@ -110,7 +111,7 @@ public class Av1WarpedInterPredictorTests
const int width = 13;
const int height = 11;
const int destinationStride = width + 7;
Av1GlobalMotionParameters parameters = CreatePinnedParameters();
Av1GlobalMotionParameters parameters = CreateCurrentLibaomParameters();
foreach (int bitDepth in new[] { 8, 10, 12 })
{
int maximum = (1 << bitDepth) - 1;
@ -121,7 +122,6 @@ public class Av1WarpedInterPredictorTests
{
source[(row * sourceStride) + column] =
(ushort)(((row * 269) + (column * 443) + (row * column * 31)) & maximum);
}
}
@ -131,11 +131,10 @@ public class Av1WarpedInterPredictorTests
ushort[] actual = new ushort[destinationStride * height];
Array.Fill(expected, (ushort)0xDEAD);
Array.Fill(actual, (ushort)0xDEAD);
short[] expectedScratch = new short[Av1WarpedInterPredictor.WarpedScratchLength];
short[] actualScratch = new short[Av1WarpedInterPredictor.WarpedScratchLength];
Point destinationPosition = subsampling == 0 ? new Point(32, 24) : new Point(16, 12);
Av1WarpedInterPredictor.PredictWarpedScalar(
PredictCurrentLibaomReference(
source,
sourceStride,
new Point(padding, padding),
@ -149,8 +148,7 @@ public class Av1WarpedInterPredictorTests
subsampling,
subsampling,
bitDepth,
parameters,
expectedScratch);
parameters);
Av1WarpedInterPredictor.PredictWarped(
source,
@ -175,9 +173,332 @@ public class Av1WarpedInterPredictorTests
}
/// <summary>
/// Creates one nontrivial affine model traced from the pinned two-frame local-warp fixture.
/// Reconstructs one warped block by directly transcribing current libaom's scalar affine loops.
/// </summary>
private static void PredictCurrentLibaomReference<TPixel>(
ReadOnlySpan<TPixel> source,
int sourceStride,
Point sourceOrigin,
int sourceWidth,
int sourceHeight,
Span<TPixel> destination,
int destinationStride,
Point destinationPosition,
int width,
int height,
int subsamplingX,
int subsamplingY,
int bitDepth,
Av1GlobalMotionParameters parameters)
where TPixel : unmanaged, IBinaryInteger<TPixel>
{
const int filterBits = 7;
const int filterTaps = 8;
const int tileSize = 8;
const int modelPrecisionBits = 16;
const int phasePrecisionBits = 10;
const int pixelPrecisionShifts = 64;
Span<int> intermediate = stackalloc int[15 * tileSize];
// Current libaom raises round0 by two for 12-bit sources so the biased horizontal intermediate
// remains representable in 16 bits, then removes those two bits from the vertical rounding.
int intermediateRange = bitDepth + filterBits - 3 + 2;
int round0 = 3 + Math.Max(intermediateRange - 16, 0);
int verticalRound = (2 * filterBits) - round0;
int horizontalBias = 1 << (bitDepth + filterBits - 1);
int verticalBias = 1 << (bitDepth + (2 * filterBits) - round0);
int maximum = (1 << bitDepth) - 1;
for (int tileRow = destinationPosition.Y; tileRow < destinationPosition.Y + height; tileRow += tileSize)
{
for (int tileColumn = destinationPosition.X; tileColumn < destinationPosition.X + width; tileColumn += tileSize)
{
int centerX = (tileColumn + 4) << subsamplingX;
int centerY = (tileRow + 4) << subsamplingY;
long projectedX =
((long)parameters[2] * centerX) + ((long)parameters[3] * centerY) + parameters[0];
long projectedY =
((long)parameters[4] * centerX) + ((long)parameters[5] * centerY) + parameters[1];
long planeX = projectedX >> subsamplingX;
long planeY = projectedY >> subsamplingY;
int integerX = (int)(planeX >> modelPrecisionBits);
int integerY = (int)(planeY >> modelPrecisionBits);
int phaseX = (int)planeX & ((1 << modelPrecisionBits) - 1);
int phaseY = (int)planeY & ((1 << modelPrecisionBits) - 1);
phaseX += (-4 * parameters.Alpha) + (-4 * parameters.Beta);
phaseY += (-4 * parameters.Gamma) + (-4 * parameters.Delta);
phaseX &= -1 << 6;
phaseY &= -1 << 6;
for (int row = -7; row < 8; row++)
{
int sourceY = Math.Clamp(integerY + row, 0, sourceHeight - 1);
int phase = phaseX + (parameters.Beta * (row + 4));
for (int column = -4; column < 4; column++)
{
int sourceX = integerX + column - 3;
int filterIndex = RoundPowerOfTwo(phase, phasePrecisionBits) + pixelPrecisionShifts;
int coefficientOffset = filterIndex * filterTaps;
int sum = horizontalBias;
for (int tap = 0; tap < filterTaps; tap++)
{
int sampleX = Math.Clamp(sourceX + tap, 0, sourceWidth - 1);
int sourceIndex =
((sourceOrigin.Y + sourceY) * sourceStride) + sourceOrigin.X + sampleX;
int sample = int.CreateChecked(source[sourceIndex]);
sum += sample * CurrentLibaomWarpedFilter[coefficientOffset + tap];
}
intermediate[((row + 7) * tileSize) + column + 4] = RoundPowerOfTwo(sum, round0);
phase += parameters.Alpha;
}
}
int lastRow = Math.Min(4, destinationPosition.Y + height - tileRow - 4);
for (int row = -4; row < lastRow; row++)
{
int phase = phaseY + (parameters.Delta * (row + 4));
int lastColumn = Math.Min(4, destinationPosition.X + width - tileColumn - 4);
for (int column = -4; column < lastColumn; column++)
{
int filterIndex = RoundPowerOfTwo(phase, phasePrecisionBits) + pixelPrecisionShifts;
int coefficientOffset = filterIndex * filterTaps;
int sum = verticalBias;
for (int tap = 0; tap < filterTaps; tap++)
{
int intermediateIndex = ((row + tap + 4) * tileSize) + column + 4;
sum += intermediate[intermediateIndex] * CurrentLibaomWarpedFilter[coefficientOffset + tap];
}
int value = RoundPowerOfTwo(sum, verticalRound) - (1 << (bitDepth - 1)) - (1 << bitDepth);
int destinationIndex =
((tileRow - destinationPosition.Y + row + 4) * destinationStride) +
tileColumn -
destinationPosition.X +
column +
4;
destination[destinationIndex] = TPixel.CreateChecked(Math.Clamp(value, 0, maximum));
phase += parameters.Gamma;
}
}
}
}
}
/// <summary>
/// Gets the 193 current-libaom eight-tap warped-filter phases used by the independent scalar oracle.
/// </summary>
private static ReadOnlySpan<short> CurrentLibaomWarpedFilter =>
[
0, 0, 127, 1, 0, 0, 0, 0,
0, -1, 127, 2, 0, 0, 0, 0,
1, -3, 127, 4, -1, 0, 0, 0,
1, -4, 126, 6, -2, 1, 0, 0,
1, -5, 126, 8, -3, 1, 0, 0,
1, -6, 125, 11, -4, 1, 0, 0,
1, -7, 124, 13, -4, 1, 0, 0,
2, -8, 123, 15, -5, 1, 0, 0,
2, -9, 122, 18, -6, 1, 0, 0,
2, -10, 121, 20, -6, 1, 0, 0,
2, -11, 120, 22, -7, 2, 0, 0,
2, -12, 119, 25, -8, 2, 0, 0,
3, -13, 117, 27, -8, 2, 0, 0,
3, -13, 116, 29, -9, 2, 0, 0,
3, -14, 114, 32, -10, 3, 0, 0,
3, -15, 113, 35, -10, 2, 0, 0,
3, -15, 111, 37, -11, 3, 0, 0,
3, -16, 109, 40, -11, 3, 0, 0,
3, -16, 108, 42, -12, 3, 0, 0,
4, -17, 106, 45, -13, 3, 0, 0,
4, -17, 104, 47, -13, 3, 0, 0,
4, -17, 102, 50, -14, 3, 0, 0,
4, -17, 100, 52, -14, 3, 0, 0,
4, -18, 98, 55, -15, 4, 0, 0,
4, -18, 96, 58, -15, 3, 0, 0,
4, -18, 94, 60, -16, 4, 0, 0,
4, -18, 91, 63, -16, 4, 0, 0,
4, -18, 89, 65, -16, 4, 0, 0,
4, -18, 87, 68, -17, 4, 0, 0,
4, -18, 85, 70, -17, 4, 0, 0,
4, -18, 82, 73, -17, 4, 0, 0,
4, -18, 80, 75, -17, 4, 0, 0,
4, -18, 78, 78, -18, 4, 0, 0,
4, -17, 75, 80, -18, 4, 0, 0,
4, -17, 73, 82, -18, 4, 0, 0,
4, -17, 70, 85, -18, 4, 0, 0,
4, -17, 68, 87, -18, 4, 0, 0,
4, -16, 65, 89, -18, 4, 0, 0,
4, -16, 63, 91, -18, 4, 0, 0,
4, -16, 60, 94, -18, 4, 0, 0,
3, -15, 58, 96, -18, 4, 0, 0,
4, -15, 55, 98, -18, 4, 0, 0,
3, -14, 52, 100, -17, 4, 0, 0,
3, -14, 50, 102, -17, 4, 0, 0,
3, -13, 47, 104, -17, 4, 0, 0,
3, -13, 45, 106, -17, 4, 0, 0,
3, -12, 42, 108, -16, 3, 0, 0,
3, -11, 40, 109, -16, 3, 0, 0,
3, -11, 37, 111, -15, 3, 0, 0,
2, -10, 35, 113, -15, 3, 0, 0,
3, -10, 32, 114, -14, 3, 0, 0,
2, -9, 29, 116, -13, 3, 0, 0,
2, -8, 27, 117, -13, 3, 0, 0,
2, -8, 25, 119, -12, 2, 0, 0,
2, -7, 22, 120, -11, 2, 0, 0,
1, -6, 20, 121, -10, 2, 0, 0,
1, -6, 18, 122, -9, 2, 0, 0,
1, -5, 15, 123, -8, 2, 0, 0,
1, -4, 13, 124, -7, 1, 0, 0,
1, -4, 11, 125, -6, 1, 0, 0,
1, -3, 8, 126, -5, 1, 0, 0,
1, -2, 6, 126, -4, 1, 0, 0,
0, -1, 4, 127, -3, 1, 0, 0,
0, 0, 2, 127, -1, 0, 0, 0,
0, 0, 0, 127, 1, 0, 0, 0,
0, 0, -1, 127, 2, 0, 0, 0,
0, 1, -3, 127, 4, -2, 1, 0,
0, 1, -5, 127, 6, -2, 1, 0,
0, 2, -6, 126, 8, -3, 1, 0,
-1, 2, -7, 126, 11, -4, 2, -1,
-1, 3, -8, 125, 13, -5, 2, -1,
-1, 3, -10, 124, 16, -6, 3, -1,
-1, 4, -11, 123, 18, -7, 3, -1,
-1, 4, -12, 122, 20, -7, 3, -1,
-1, 4, -13, 121, 23, -8, 3, -1,
-2, 5, -14, 120, 25, -9, 4, -1,
-1, 5, -15, 119, 27, -10, 4, -1,
-1, 5, -16, 118, 30, -11, 4, -1,
-2, 6, -17, 116, 33, -12, 5, -1,
-2, 6, -17, 114, 35, -12, 5, -1,
-2, 6, -18, 113, 38, -13, 5, -1,
-2, 7, -19, 111, 41, -14, 6, -2,
-2, 7, -19, 110, 43, -15, 6, -2,
-2, 7, -20, 108, 46, -15, 6, -2,
-2, 7, -20, 106, 49, -16, 6, -2,
-2, 7, -21, 104, 51, -16, 7, -2,
-2, 7, -21, 102, 54, -17, 7, -2,
-2, 8, -21, 100, 56, -18, 7, -2,
-2, 8, -22, 98, 59, -18, 7, -2,
-2, 8, -22, 96, 62, -19, 7, -2,
-2, 8, -22, 94, 64, -19, 7, -2,
-2, 8, -22, 91, 67, -20, 8, -2,
-2, 8, -22, 89, 69, -20, 8, -2,
-2, 8, -22, 87, 72, -21, 8, -2,
-2, 8, -21, 84, 74, -21, 8, -2,
-2, 8, -22, 82, 77, -21, 8, -2,
-2, 8, -21, 79, 79, -21, 8, -2,
-2, 8, -21, 77, 82, -22, 8, -2,
-2, 8, -21, 74, 84, -21, 8, -2,
-2, 8, -21, 72, 87, -22, 8, -2,
-2, 8, -20, 69, 89, -22, 8, -2,
-2, 8, -20, 67, 91, -22, 8, -2,
-2, 7, -19, 64, 94, -22, 8, -2,
-2, 7, -19, 62, 96, -22, 8, -2,
-2, 7, -18, 59, 98, -22, 8, -2,
-2, 7, -18, 56, 100, -21, 8, -2,
-2, 7, -17, 54, 102, -21, 7, -2,
-2, 7, -16, 51, 104, -21, 7, -2,
-2, 6, -16, 49, 106, -20, 7, -2,
-2, 6, -15, 46, 108, -20, 7, -2,
-2, 6, -15, 43, 110, -19, 7, -2,
-2, 6, -14, 41, 111, -19, 7, -2,
-1, 5, -13, 38, 113, -18, 6, -2,
-1, 5, -12, 35, 114, -17, 6, -2,
-1, 5, -12, 33, 116, -17, 6, -2,
-1, 4, -11, 30, 118, -16, 5, -1,
-1, 4, -10, 27, 119, -15, 5, -1,
-1, 4, -9, 25, 120, -14, 5, -2,
-1, 3, -8, 23, 121, -13, 4, -1,
-1, 3, -7, 20, 122, -12, 4, -1,
-1, 3, -7, 18, 123, -11, 4, -1,
-1, 3, -6, 16, 124, -10, 3, -1,
-1, 2, -5, 13, 125, -8, 3, -1,
-1, 2, -4, 11, 126, -7, 2, -1,
0, 1, -3, 8, 126, -6, 2, 0,
0, 1, -2, 6, 127, -5, 1, 0,
0, 1, -2, 4, 127, -3, 1, 0,
0, 0, 0, 2, 127, -1, 0, 0,
0, 0, 0, 1, 127, 0, 0, 0,
0, 0, 0, -1, 127, 2, 0, 0,
0, 0, 1, -3, 127, 4, -1, 0,
0, 0, 1, -4, 126, 6, -2, 1,
0, 0, 1, -5, 126, 8, -3, 1,
0, 0, 1, -6, 125, 11, -4, 1,
0, 0, 1, -7, 124, 13, -4, 1,
0, 0, 2, -8, 123, 15, -5, 1,
0, 0, 2, -9, 122, 18, -6, 1,
0, 0, 2, -10, 121, 20, -6, 1,
0, 0, 2, -11, 120, 22, -7, 2,
0, 0, 2, -12, 119, 25, -8, 2,
0, 0, 3, -13, 117, 27, -8, 2,
0, 0, 3, -13, 116, 29, -9, 2,
0, 0, 3, -14, 114, 32, -10, 3,
0, 0, 3, -15, 113, 35, -10, 2,
0, 0, 3, -15, 111, 37, -11, 3,
0, 0, 3, -16, 109, 40, -11, 3,
0, 0, 3, -16, 108, 42, -12, 3,
0, 0, 4, -17, 106, 45, -13, 3,
0, 0, 4, -17, 104, 47, -13, 3,
0, 0, 4, -17, 102, 50, -14, 3,
0, 0, 4, -17, 100, 52, -14, 3,
0, 0, 4, -18, 98, 55, -15, 4,
0, 0, 4, -18, 96, 58, -15, 3,
0, 0, 4, -18, 94, 60, -16, 4,
0, 0, 4, -18, 91, 63, -16, 4,
0, 0, 4, -18, 89, 65, -16, 4,
0, 0, 4, -18, 87, 68, -17, 4,
0, 0, 4, -18, 85, 70, -17, 4,
0, 0, 4, -18, 82, 73, -17, 4,
0, 0, 4, -18, 80, 75, -17, 4,
0, 0, 4, -18, 78, 78, -18, 4,
0, 0, 4, -17, 75, 80, -18, 4,
0, 0, 4, -17, 73, 82, -18, 4,
0, 0, 4, -17, 70, 85, -18, 4,
0, 0, 4, -17, 68, 87, -18, 4,
0, 0, 4, -16, 65, 89, -18, 4,
0, 0, 4, -16, 63, 91, -18, 4,
0, 0, 4, -16, 60, 94, -18, 4,
0, 0, 3, -15, 58, 96, -18, 4,
0, 0, 4, -15, 55, 98, -18, 4,
0, 0, 3, -14, 52, 100, -17, 4,
0, 0, 3, -14, 50, 102, -17, 4,
0, 0, 3, -13, 47, 104, -17, 4,
0, 0, 3, -13, 45, 106, -17, 4,
0, 0, 3, -12, 42, 108, -16, 3,
0, 0, 3, -11, 40, 109, -16, 3,
0, 0, 3, -11, 37, 111, -15, 3,
0, 0, 2, -10, 35, 113, -15, 3,
0, 0, 3, -10, 32, 114, -14, 3,
0, 0, 2, -9, 29, 116, -13, 3,
0, 0, 2, -8, 27, 117, -13, 3,
0, 0, 2, -8, 25, 119, -12, 2,
0, 0, 2, -7, 22, 120, -11, 2,
0, 0, 1, -6, 20, 121, -10, 2,
0, 0, 1, -6, 18, 122, -9, 2,
0, 0, 1, -5, 15, 123, -8, 2,
0, 0, 1, -4, 13, 124, -7, 1,
0, 0, 1, -4, 11, 125, -6, 1,
0, 0, 1, -3, 8, 126, -5, 1,
0, 0, 1, -2, 6, 126, -4, 1,
0, 0, 0, -1, 4, 127, -3, 1,
0, 0, 0, 0, 2, 127, -1, 0,
0, 0, 0, 0, 2, 127, -1, 0,
];
/// <summary>
/// Divides a signed fixed-point value by a power of two with current libaom's rounding.
/// </summary>
private static int RoundPowerOfTwo(int value, int bitCount)
=> (value + (1 << (bitCount - 1))) >> bitCount;
/// <summary>
/// Creates one nontrivial affine model traced from the current-libaom-verified two-frame local-warp fixture.
/// </summary>
private static Av1GlobalMotionParameters CreatePinnedParameters()
private static Av1GlobalMotionParameters CreateCurrentLibaomParameters()
{
Av1GlobalMotionParameters parameters = Av1GlobalMotionParameters.Identity;
parameters.Type = Av1GlobalMotionType.Affine;

0
tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifLocalWarpSequenceMatchesPinnedReferences_Rgba32_libavif-rotating-grid-local-warp.png → tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifLocalWarpSequenceMatchesCurrentLibaomReferences_Rgba32_libavif-rotating-grid-local-warp.png

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

@ -229,15 +229,39 @@ bytes. Their SHA-256 values remain
## Local warped-motion fixture
The `libavif-rotating-grid-local-warp.avif` fixture was encoded from a deterministic two-frame 256x256 limited-range YUV444 source. The source combines checkerboard, ring, and chroma-gradient detail; its second frame rotates the first by 2.5 degrees with nearest-neighbor sampling and edge clamping. The two-frame source Y4M SHA-256 is `82C1468C95C996B05165590417184F59373D67896F8C7B0EB398582C29C9C7A7`. Pinned scalar libavif and libaom generated the fixture and references with:
The `libavif-rotating-grid-local-warp.avif` file is retained solely as interoperability input. It was
originally encoded from a deterministic two-frame 256x256 limited-range YUV444 source whose second frame
rotates the first by 2.5 degrees. The original packaging command records fixture provenance only; libavif
is not used as an AV1 implementation or reconstruction reference:
```text
./avifenc -j 1 -s 0 -q 60 -a color:enable-warped-motion=1 -a color:enable-global-motion=0 -a color:enable-obmc=0 rotating-grid-256-two-frame.y4m libavif-rotating-grid-local-warp.avif
./avifdec -j 1 --index 1 libavif-rotating-grid-local-warp.avif libavif-rotating-grid-local-warp-libaom.y4m
./avifdec -j 1 --index 1 libavif-rotating-grid-local-warp.avif libavif-rotating-grid-local-warp-libavif.png
```
The AVIF SHA-256 is `990BAC4AD443005C217B0DA4FCCFA9ADFB3AA147AD06C85F9A655A4433E9E8A7`. The retained frame-1 Y4M SHA-256 is `984B2815CEE0C05FDE26430F150A21B5C993141E25BA1ED4FDE09372DB64AC13`, and the frame-1 PNG SHA-256 is `4490D62FB6679378E92CACA48427359091AD2106BE49FC1A3848F78BE03BEEB1`. Pinned libaom tracing records many actual `WARPED_CAUSAL` blocks. The multi-sample model at mode-information row 6, column 8 derives matrix `[-191565, 599107, 61755, -140, -6909, 62012]` and reduced shear `[-3776, -128, -7360, -3520]` from four retained neighbor samples. The production test requires decoded warped mode state, compares every final native Y, U, and V sample and the final RGBA presentation exactly, runs normal and scalar dispatch through `FeatureTestRunner`, and repeats reconstruction with constrained tracked allocation.
On 2026-08-31 the clean official libaom `main` checkout was refreshed from its upstream remote. At the
observed revision `441c439b9916474cac15d2822af47a9ad70674a8`, the fixture's 2,310-byte AV1 `mdat`
payload at AVIF offset 997 has SHA-256
`644D04FE1D1A32BB7A3856AD7EB49CF1EFDE0AC845E55BEAC4170F72353F2391` and was decoded with:
```text
aomdec --codec=av1 --threads=1 --row-mt=0 --all-layers --output-bit-depth=8 -o local-warp-current-main.y4m local-warp-current-main.obu
```
Current libaom produced two 256x256 YUV444 frames. The complete Y4M has SHA-256
`8FDC5D46014F5E5A7455A83643AB6F0DA66FC5A984E72A43F8C75BAD8271C299`. Its final
frame's 196,608 native samples have SHA-256
`47B2AB39BF3B9DA15C1EC59840F964DFDF227760947F6E1295FB38A84555F75C` and match the
retained `libavif-rotating-grid-local-warp-libaom.y4m` reference with zero differing samples.
The multi-sample model at mode-information row 6, column 8 derives matrix
`[-191565, 599107, 61755, -140, -6909, 62012]` and reduced shear
`[-3776, -128, -7360, -3520]` from four retained spatial neighbor samples. The production test requires
decoded `WARPED_CAUSAL` state through `Av1BlockDecoder.DecodeBlock()`, compares every final native Y,
U, and V sample exactly, compares the retained final presentation through the established image-reference
API, runs intrinsic and scalar dispatch through `FeatureTestRunner`, and repeats reconstruction with a
constrained tracked allocator. Separate 8-, 10-, and 12-bit operator tests use an independent scalar
transcription of current libaom's affine loops and all 1,544 current filter coefficients across AVX-512,
AVX, 128-bit, and scalar execution.
## Global warped-motion fixture

Loading…
Cancel
Save