Browse Source

Complete AV1 global warped-motion decoding

pull/2633/head
James Jackson-South 5 days ago
parent
commit
c5637ea018
  1. 29
      HEIF_IMPLEMENTATION_PLAN.md
  2. 84
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs
  3. 247
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1CompoundBlockDecoderTests.cs
  4. 75
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs
  5. 3
      tests/ImageSharp.Tests/TestImages.cs
  6. 13
      tests/Images/Input/Heif/Av1/Conformance/README.md
  7. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libaom.y4m
  8. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libavif.png
  9. 3
      tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp.avif

29
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-29 against committed production checkpoint `8f57c29b250b4291f034b31c1ea3de3fa3345467` plus the locally complete local-warp checkpoint awaiting commit. Committed checkpoints include the AV1 transform architecture, OBU framing, intra-block copy, 12-profile reconstruction matrix, layered-item properties, layered reference/header/CDF/motion-field state, inter-frame intra blocks, SIMD-first translational prediction, complete single-reference inter reconstruction, compound reference trees and modes, paired reference-MV derivation, reference-dependent bounded sequence decoding, allocation-free SIMD-first equal averaging, selected inter-intra prediction, selectable compound blending, OBMC, and scaled-reference reconstruction. The local checkpoint adds pinned integer least-squares projection, reduced-shear validation, allocation-free 8x8-tiled affine filtering, and production local warped reconstruction across byte and high-bit-depth planes. Its genuine two-frame 256x256 bounded AVIF selects many traced `WARPED_CAUSAL` blocks, including multi-sample nonzero-shear models, and passes exact final pinned-libaom YUV444 planes, exact pinned-libavif RGBA presentation, normal and scalar `FeatureTestRunner` execution, constrained allocation, and balanced ownership tracking. Both source targets build with zero warnings and errors; the `net10.0` test project builds with zero errors and pre-existing warnings; 86 focused `net10.0` cases pass without failures or skips; and the documentation and diff checks are complete. 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-29 against committed production checkpoint `0b2db86809e26757460e719a6b59c0fe58bb0586` plus the locally complete global-warp checkpoint awaiting commit. Committed checkpoints include the AV1 transform architecture, OBU framing, intra-block copy, 12-profile reconstruction matrix, layered-item properties, layered reference/header/CDF/motion-field state, inter-frame intra blocks, SIMD-first translational prediction, complete single-reference inter reconstruction, compound reference trees and modes, paired reference-MV derivation, reference-dependent bounded sequence decoding, allocation-free SIMD-first equal averaging, selected inter-intra prediction, selectable compound blending, OBMC, scaled-reference reconstruction, and local warped prediction. The global-warp checkpoint reuses the committed affine filter for valid rotation/zoom and affine `GLOBALMV` models while preserving translational fallback for identity, translation, invalid shear, scaled references, integer-only frames, OBMC, and sub-8x8 plane predictions. Its genuine two-frame 256x256 bounded AVIF contains seven pinned-libaom-traced rotation/zoom `GLOBALMV` blocks and passes exact final pinned-libaom YUV444 planes, exact pinned-libavif RGBA presentation, normal and scalar `FeatureTestRunner` execution, constrained allocation, and balanced ownership tracking. A direct production-branch test drives both matrices of `GLOBAL_GLOBALMV` through compound averaging at 8, 10, and 12 bits. Both source targets build with zero warnings and errors; the `net10.0` test project builds with zero errors and pre-existing warnings; 84 focused `net10.0` cases pass without failures or skips; and the documentation and diff checks are complete. 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:
@ -39,15 +39,15 @@ Status meanings:
- **Not started:** supporting primitives may exist, but the production format path is absent.
- **Current:** the only work item that should be advanced before taking the next queued item.
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, and local warped prediction before residual traversal. The local-warp implementation and independent evidence are complete locally; its checkpoint commit is the only remaining gate before non-translational global prediction becomes current. 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. The global-warp implementation and independent evidence are complete locally; its checkpoint commit is the only remaining gate before the next recorded AV1 decoding item becomes current. Neither AV1 nor HEVC production encoding is implemented.
Immediate checkpoint: **commit the complete local warped-motion implementation and its verified evidence before advancing to non-translational global motion.** The production branch, pinned multi-sample projection, independent native and presentation comparisons, constrained allocator coverage, Release builds, focused tests, documentation review, and diff validation are complete. This work remains inside the existing image-item and bounded image-sequence surfaces and does not expand into a general ISO BMFF/video model.
Immediate checkpoint: **commit the complete non-translational global-motion implementation and its verified evidence before advancing to another AV1 decoding item.** The production branch, single and compound matrix reconstruction, independent native and presentation comparisons, constrained allocator coverage, Release builds, focused tests, documentation review, and diff validation are complete.
| 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 work includes bounded OBU framing, reconstruction, filters, grain, color, transforms, intra-block copy, an exact independent 12-profile bit-depth/chroma matrix through every dispatch tier, retained layered reference/header/CDF/motion-field state, temporal segment prediction, inter-frame intra blocks, SIMD-first translational prediction, exact single-reference inter reconstruction, exact equal-average and selectable compound reconstruction, inter-intra prediction, committed OBMC and scaled-reference reconstruction, and locally complete independently verified local warped prediction. | Commit local warped prediction, then implement non-translational global prediction; 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 work includes bounded OBU framing, reconstruction, filters, grain, color, transforms, intra-block copy, an exact independent 12-profile bit-depth/chroma matrix through every dispatch tier, retained layered reference/header/CDF/motion-field state, temporal segment prediction, inter-frame intra blocks, SIMD-first translational prediction, exact single-reference inter reconstruction, exact equal-average and selectable compound reconstruction, inter-intra prediction, committed OBMC, scaled-reference reconstruction, local warped prediction, and locally complete independently verified non-translational global prediction. | Commit global prediction; remove every other valid AV1 still-image unsupported branch with independent 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. |
@ -92,9 +92,9 @@ Immediate checkpoint: **commit the complete local warped-motion implementation a
- [x] Decode selected inter-intra prediction and selectable distance-weighted, wedge, and difference-weighted compound blending. Normative-order syntax, direct 8/10/12-bit production reconstruction, SIMD/scalar arithmetic, four pinned bounded sequences, exact final native planes and presentation, constrained contiguous planes, and balanced allocator returns pass. Both source targets build with zero warnings and errors; the test project builds with zero errors and pre-existing repository warnings; 25 direct focused cases and six `FeatureTestRunner` cases pass without failures or skips; and `git diff --check` is clean.
- [x] Decode and reconstruct above and left OBMC through allocator-owned prediction workspaces, exact pinned masks, and the existing SIMD-first masked blender. Commit `59a4fbad5ed3bc7c34331c4bdc65acc7acde3f04` records direct 8/10/12-bit production reconstruction, 4:2:0 and 4:2:2 overlap geometry, a real 19-frame YUV444 sequence containing more than one hundred traced OBMC blocks, exact final pinned-libaom native planes, exact pinned-libavif presentation through normal and scalar `FeatureTestRunner` configurations, constrained tracked allocation, zero-warning `net10.0` and `net11.0` source builds, a zero-error analyzer build with 1,013 pre-existing warnings, 14 direct focused cases plus the feature-isolated comparison, and clean staged `git diff --check`.
- [x] Decode and independently verify scaled-reference prediction through exact Q14/Q10 arithmetic, allocation-free SIMD/scalar convolution, 8/10/12-bit production reconstruction, scaled OBMC, active inter deblocking, constrained allocation, and a genuine size-changing bounded AVIF.
- [x] Decode local warped motion through pinned integer projection and allocation-free SIMD-first affine filtering. A genuine two-frame bounded AVIF selects traced multi-sample warped blocks and passes exact final native-plane and presentation comparisons, constrained allocation, and normal/scalar dispatch. The checkpoint is complete locally and awaiting commit.
- [ ] **Queued until the local-warp commit:** decode non-translational global-motion prediction.
- [ ] Verify every remaining connected mode and filter with independently encoded bounded AV1 content and exact native-plane comparisons.
- [x] Decode local warped motion through pinned integer projection and allocation-free SIMD-first affine filtering. A genuine two-frame bounded AVIF selects traced multi-sample warped blocks and passes exact final native-plane and presentation comparisons, constrained allocation, and normal/scalar dispatch. Commit `0b2db86809e26757460e719a6b59c0fe58bb0586` records the checkpoint.
- [x] Decode non-translational global motion through the committed affine filter. A genuine two-frame bounded AVIF selects seven traced rotation/zoom `GLOBALMV` blocks and passes exact final native-plane and presentation comparisons, constrained allocation, and normal/scalar dispatch. Direct 8/10/12-bit production reconstruction covers both matrices of compound `GLOBAL_GLOBALMV`. The checkpoint is complete locally and awaiting commit.
- [ ] **Queued until the global-warp commit:** verify every remaining connected mode and filter with independently encoded bounded AV1 content and exact native-plane comparisons.
- [ ] Return the explicitly selected spatial layer or the final displayed layer, keeping reference reconstruction separate from display-only film grain.
- [ ] Verify color and auxiliary-alpha output exactly against both pinned libavif progressive fixtures under normal SIMD dispatch and all required `FeatureTestRunner` fallbacks.
- [ ] Correct the audited 12-bit inverse ADST4, Identity4, and Identity16 SIMD arithmetic by widening only the libaom-widened multiply/accumulate operations, with exact conformant-range vectors and `FeatureTestRunner` coverage.
@ -398,7 +398,8 @@ This assessment was reconciled with the source tree on 2026-08-29, including pro
- Commit `e1a764b8f2e8a8db98a003fb3b913213f40084db` owns every compound reference-selection and inter-mode distribution through the retained CDF lifecycle, derives primary and secondary candidate vectors as inseparable pairs, reconstructs both retained references through the existing translational predictor, and combines them through one SIMD-first byte/ushort averaging operator with scalar parity. The pinned 19-frame libavif sequence exercises the complete production block branch and matches pinned libaom native planes and pinned libavif presentation exactly after decoding all preceding reference samples.
- Commit `59a4fbad5ed3bc7c34331c4bdc65acc7acde3f04` reconstructs eligible above and left OBMC neighbors through the retained primary reference, exact libaom masks, and the existing SIMD-first masked blender without per-block allocation. Direct production tests cover 8/10/12-bit storage plus 4:2:0 and 4:2:2 plane geometry. A pinned 19-frame sequence contains more than one hundred traced OBMC blocks and passes exact final native-plane, final-presentation, constrained-allocation, normal-dispatch, and scalar-dispatch comparison.
- Commit `8f57c29b250b4291f034b31c1ea3de3fa3345467` maps current-frame Q4 positions into retained-frame Q10 coordinates with pinned-libaom Q14 scale factors and signed rounding, then applies allocation-free variable-phase two-pass convolution across byte and high-bit-depth storage. The production block path selects scaling from actual retained/current dimensions, covers both primary and secondary workspaces plus scaled OBMC neighbors, and retains libaom's 288-sample prediction border. The real layered fixture also exposed and now verifies per-block inter loop-filter reference/mode deltas and skipped-transform edge decisions that the earlier intra-only deblocking integration did not model.
- The locally complete local-warp checkpoint derives AV1's affine matrix from fixed-capacity spatial samples with pinned integer least squares, reciprocal lookup, coefficient clamping, and shear validation. Production reconstruction applies the pinned 193-phase Q7 warped filter in allocation-free 8x8 tiles through `Vector128` convolution with scalar fallback for 8/10/12-bit planes; an invalid selected model falls back to translational prediction as libaom does.
- Commit `0b2db86809e26757460e719a6b59c0fe58bb0586` derives AV1's local affine matrix from fixed-capacity spatial samples with pinned integer least squares, reciprocal lookup, coefficient clamping, and shear validation. Production reconstruction applies the pinned 193-phase Q7 warped filter in allocation-free 8x8 tiles through `Vector128` convolution with scalar fallback for 8/10/12-bit planes; an invalid selected model falls back to translational prediction as libaom does.
- The locally complete global-warp checkpoint selects the full frame-header rotation/zoom or affine matrix independently for each `GLOBAL_GLOBALMV` reference, while identity, translation, invalid shear, scaled references, integer-only frames, OBMC, and sub-8x8 plane predictions retain their normative translational path. A pinned bounded sequence proves seven actual single-reference `GLOBALMV` blocks through exact native and presentation output, and a direct `FeatureTestRunner` production test proves both compound matrices at 8, 10, and 12 bits.
- Source inspection against pinned libaom `03087864cf4bea6abb0d28f95cf7843511413d8f` resolves two disputed audit claims in favor of the current predicates. The interpolation call path uses `is_nontrans_global_motion()`, which returns false only for `TRANSLATION`, so an identity `GLOBALMV` block omits filter symbols. The single-reference spatial extension loops use `MAX_MV_REF_CANDIDATES`, which is two, while the full reference-MV stack capacity is eight. These loops are spatial extension, not temporal extension.
- Every padded AV1 frame plane requests ImageSharp's contiguous allocation contract, and constrained-allocator reconstruction passes without copying. Motion fields use allocator-owned storage and counted leases; allocation tracking passes for initialization, retained aliases, failure unwinding, presentation ownership, decoder-result ownership, and exactly-once disposal. The corrected logical progressive color payload reaches the production inter branch and its final native planes match pinned libaom exactly.
- Transform coefficient entropy derivation and updates now address the above contexts relative to the tile column and the left contexts relative to the current superblock row, preserve luma coordinates independently of chroma subsampling, and test every packed context entry for the libaom any-nonzero rule. Extended vertical partition updates advance the mode-information column rather than the row. The existing multi-superblock 4:4:4 AVIF fixture now completes tile parsing; independent coefficient-context vectors across tile boundaries, chroma layouts, bit depths, and edge-clipped transforms remain required.
@ -581,9 +582,9 @@ Implement and verify in dependency order:
- [x] Decode and reconstruct selected inter-intra prediction and selectable distance-weighted, wedge, and difference-weighted compound blending through reconstructed reference planes. Direct syntax and 8/10/12-bit production tests, SIMD/scalar mask and blend tests, exact four-sequence native/presentation comparisons, constrained contiguous allocation, and exactly-once tracked returns pass. Both source targets build with zero warnings and errors; the test project builds with zero errors and pre-existing repository warnings; 25 direct focused cases and six `FeatureTestRunner` cases pass without failures or skips; and `git diff --check` is clean. Commit `864b11ad9791d3254a38691246270c569001b5a1` records the checkpoint.
- [x] Decode and reconstruct OBMC through above and left neighboring prediction, exact libaom masks, allocator-owned workspaces, and the existing SIMD-first masked blender. Commit `59a4fbad5ed3bc7c34331c4bdc65acc7acde3f04` records exact pinned native/presentation evidence, direct 8/10/12-bit and subsampled reconstruction, constrained allocation, both Release source builds, and normal/scalar dispatch.
- [x] Decode scaled references through exact Q14 scale factors, signed Q4-to-Q10 coordinate rounding, variable per-output phases and steps, regular/smooth/sharp/bilinear reduced and full filters, bit-depth-dependent two-pass rounding, scaled OBMC neighbors, and the normative 288-sample retained border without per-block allocation. The independently generated 40x40-to-80x80 layered fixture proves the base reference before retention and in the production retained session, then matches the final pinned-libaom Y/U/V planes and pinned-libavif RGBA presentation exactly. Active inter deblocking additionally verifies per-block reference/mode deltas and skipped inter/intra boundary decisions. Normal and scalar `FeatureTestRunner` runs, constrained contiguous planes, unique allocation identities, 8/10/12-bit production-block coverage, zero-warning `net10.0` and `net11.0` source builds, the zero-error test-project build with 1,013 pre-existing warnings, 87 focused cases, documentation review, and `git diff --check` pass.
- [x] Decode local warped motion through pinned integer projection and allocation-free 8x8-tiled affine filtering across byte and high-bit-depth planes. Exact traced native/presentation evidence, constrained allocation, and normal/scalar dispatch pass locally; the checkpoint awaits commit.
- [ ] **Queued until the local-warp commit:** decode non-translational global motion through reconstructed reference planes.
- [ ] Verify every remaining connected inter mode and filter with independently encoded bounded AV1 content and exact native-plane comparisons.
- [x] Decode local warped motion through pinned integer projection and allocation-free 8x8-tiled affine filtering across byte and high-bit-depth planes. Commit `0b2db86809e26757460e719a6b59c0fe58bb0586` records exact traced native/presentation evidence, constrained allocation, and normal/scalar dispatch.
- [x] Decode non-translational global motion through reconstructed reference planes. The complete local checkpoint covers pinned single-reference rotation/zoom syntax and reconstruction, both compound reference workspaces, 8/10/12-bit storage, exact native and presentation output, constrained allocation, balanced ownership, and normal/scalar dispatch; it awaits commit.
- [ ] **Queued until the global-warp commit:** verify every remaining connected inter mode and filter with independently encoded bounded AV1 content and exact native-plane comparisons.
- [ ] Lossless and high-bit-depth reconstruction with correct clipping and intermediate precision.
- [x] Route lossless 4x4 blocks through allocation-free reversible inverse Walsh-Hadamard reconstruction for 8/10/12-bit samples, including the DC-only specialization, `Vector128` production traversal, scalar fallback, exact clipping, and `FeatureTestRunner` parity.
- [x] Verify lossless syntax, inverse quantization, prediction, and presented reconstruction with independently encoded 8/10/12-bit AVIF fixtures. The tests require coded residuals with palette and intra-block copy disabled, compare every native YUV sample with the pinned generic libaom-backed decoder, and compare every presented RGBA byte with pinned generic libavif exactly under normal hardware dispatch and the scalar fallback.
@ -824,9 +825,9 @@ The dashboard and immediate execution queue define the remaining critical path.
- [x] Implement and independently verify selected inter-intra prediction and selectable distance-weighted, wedge, and difference-weighted compound blending through exact pinned native-plane and presentation comparisons, direct 8/10/12-bit production coverage, constrained allocation, and SIMD/scalar parity.
- [x] Implement and independently verify OBMC through exact traced native-plane and presentation evidence, direct 8/10/12-bit and subsampled production coverage, constrained allocation, and normal/scalar dispatch. Commit `59a4fbad5ed3bc7c34331c4bdc65acc7acde3f04` records the checkpoint.
- [x] Implement and independently verify scaled references through pinned fixed-point oracles, direct 8/10/12-bit production reconstruction, a genuine 40x40-to-80x80 bounded AVIF, exact retained-base/final-native/final-presentation comparisons, active inter deblocking, constrained allocation, and normal/scalar dispatch. Commit `8f57c29b250b4291f034b31c1ea3de3fa3345467` records the checkpoint.
- [x] Implement and independently verify local warped motion through pinned projection, direct 8/10/12-bit predictor coverage, a genuine traced two-frame bounded AVIF, exact final native and presentation comparisons, constrained allocation, and normal/scalar dispatch. The checkpoint is complete locally and awaiting commit.
- [ ] **Queued until that commit:** implement non-translational global prediction with its own independent exact evidence.
- [ ] Remove every other unsupported valid AV1 still-image syntax path, correct the audited 12-bit inverse-transform arithmetic, and prove the complete AVIF decode matrix with independent inputs and scalar/SIMD parity.
- [x] Implement and independently verify local warped motion through pinned projection, direct 8/10/12-bit predictor coverage, a genuine traced two-frame bounded AVIF, exact final native and presentation comparisons, constrained allocation, and normal/scalar dispatch. Commit `0b2db86809e26757460e719a6b59c0fe58bb0586` records the checkpoint.
- [x] Implement and independently verify non-translational global prediction with a genuine traced bounded sequence, exact native and presentation comparisons, constrained allocation, normal/scalar dispatch, and direct 8/10/12-bit compound production coverage. The checkpoint is complete locally and awaiting commit.
- [ ] **Queued until the global-warp commit:** remove every other unsupported valid AV1 still-image syntax path, correct the audited 12-bit inverse-transform arithmetic, and prove the complete AVIF decode matrix with independent inputs and scalar/SIMD parity.
- [ ] Close Phase 4 by completing the remaining HEVC profile and Range Extensions matrix with exact native-plane and presented-image evidence.
- [ ] Close Phase 5 and the decode portion of the bounded sequence ledger: color, ICC, alpha, grids, presentation transforms, reference-dependent samples, and complete animated AVIF/HEIC decode.
- [ ] Close the still-image portions of Phases 0, 1, and 2 that remain as release gates: documentation, provenance, public format boundaries, API review, parser hardening, and malformed-input coverage.

84
src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs

@ -251,33 +251,9 @@ internal sealed class Av1BlockDecoder : IDisposable
int secondCompoundWeight = 8;
if (isInterBlock)
{
int canonicalReferenceIndex = (int)modeInfo.ReferenceFrames[0] - (int)Av1ReferenceFrameType.Last;
Av1GlobalMotionParameters globalMotion = this.frameHeader.GetGlobalMotionParameters()[canonicalReferenceIndex];
bool usesPrimaryGlobalMotion = modeInfo.YMode is
Av1PredictionMode.GlobalMotionVector or
Av1PredictionMode.GlobalGlobalMotionVector;
if (usesPrimaryGlobalMotion &&
Math.Min(modeInfo.BlockSize.GetWidth(), modeInfo.BlockSize.GetHeight()) >= 8 &&
globalMotion.Type > Av1GlobalMotionType.Translation)
{
// A qualifying rotation/zoom or affine GLOBALMV block samples the complete warped model. Its center
// vector is a stack fallback only and cannot be substituted into the translational predictor.
throw new NotSupportedException("AV1 non-translational global prediction is not implemented.");
}
referenceFrameBuffer = this.ResolveReferenceFrame(modeInfo.ReferenceFrames[0]);
if (isCompound)
{
int secondaryCanonicalReferenceIndex = (int)modeInfo.ReferenceFrames[1] - (int)Av1ReferenceFrameType.Last;
Av1GlobalMotionParameters secondaryGlobalMotion = this.frameHeader.GetGlobalMotionParameters()[secondaryCanonicalReferenceIndex];
if (modeInfo.YMode == Av1PredictionMode.GlobalGlobalMotionVector &&
Math.Min(modeInfo.BlockSize.GetWidth(), modeInfo.BlockSize.GetHeight()) >= 8 &&
secondaryGlobalMotion.Type > Av1GlobalMotionType.Translation)
{
throw new NotSupportedException("AV1 non-translational global prediction is not implemented.");
}
secondaryReferenceFrameBuffer = this.ResolveReferenceFrame(modeInfo.ReferenceFrames[1]);
if (modeInfo.CompoundType == Av1CompoundType.DistanceWeighted)
{
@ -370,9 +346,47 @@ internal sealed class Av1BlockDecoder : IDisposable
bool isScaledReference = activeReferenceFrameBuffer.Width != this.frameHeader.FrameSize.FrameWidth ||
activeReferenceFrameBuffer.Height != this.frameHeader.FrameSize.FrameHeight;
if (referenceIndex == 0 &&
// Warped prediction is selected per plane. In subsampled frames an otherwise qualifying 8x8 luma
// block has a 4x4 chroma prediction, which libaom deliberately reconstructs with the translational
// center motion vector. Scaled references and integer-only frames exclude both local and global warp.
bool canUseWarpedPrediction =
!isScaledReference &&
!this.frameHeader.ForceIntegerMotionVector &&
predictionWidth >= 8 &&
predictionHeight >= 8;
Av1GlobalMotionParameters warpedMotionParameters = modeInfo.WarpedMotionParameters;
bool useWarpedPrediction =
canUseWarpedPrediction &&
referenceIndex == 0 &&
modeInfo.MotionMode == Av1MotionMode.Warped &&
!modeInfo.WarpedMotionParameters.IsInvalid)
!warpedMotionParameters.IsInvalid;
if (canUseWarpedPrediction && !useWarpedPrediction)
{
bool usesGlobalMotion = modeInfo.YMode == Av1PredictionMode.GlobalGlobalMotionVector ||
(referenceIndex == 0 && modeInfo.YMode == Av1PredictionMode.GlobalMotionVector);
if (usesGlobalMotion)
{
int canonicalReferenceIndex =
(int)modeInfo.ReferenceFrames[referenceIndex] - (int)Av1ReferenceFrameType.Last;
Av1GlobalMotionParameters globalMotionParameters =
this.frameHeader.GetGlobalMotionParameters()[canonicalReferenceIndex];
// Identity and translation GLOBALMV modes use their derived center vector. Rotation/zoom and
// affine models use the complete matrix only when the decoded shear parameters are valid.
if (globalMotionParameters.Type > Av1GlobalMotionType.Translation &&
!globalMotionParameters.IsInvalid)
{
warpedMotionParameters = globalMotionParameters;
useWarpedPrediction = true;
}
}
}
if (useWarpedPrediction)
{
int referencePlaneWidth = Av1Math.DivideLog2Ceiling(activeReferenceFrameBuffer.Width, subX);
int referencePlaneHeight = Av1Math.DivideLog2Ceiling(activeReferenceFrameBuffer.Height, subY);
@ -386,7 +400,9 @@ internal sealed class Av1BlockDecoder : IDisposable
out Point sourceOrigin);
Span<ushort> destination = MemoryMarshal.Cast<short, ushort>(
highBitDepthBlockReconstructionBuffer[reconstructionStride..]);
referenceIndex == 0
? highBitDepthBlockReconstructionBuffer[reconstructionStride..]
: secondPredictionStorage);
Av1InterPredictor.PredictWarped(
source,
@ -395,14 +411,14 @@ internal sealed class Av1BlockDecoder : IDisposable
referencePlaneWidth,
referencePlaneHeight,
destination,
reconstructionStride,
destinationStride,
pixelPosition,
predictionWidth,
predictionHeight,
subX,
subY,
this.frameBuffer.BitDepth.GetBitCount(),
modeInfo.WarpedMotionParameters,
warpedMotionParameters,
predictionScratch);
}
else
@ -414,20 +430,24 @@ internal sealed class Av1BlockDecoder : IDisposable
out int sourceStride,
out Point sourceOrigin);
Span<byte> destination = referenceIndex == 0
? blockReconstructionBuffer[reconstructionStride..]
: secondPrediction;
Av1InterPredictor.PredictWarped(
source,
sourceStride,
sourceOrigin,
referencePlaneWidth,
referencePlaneHeight,
blockReconstructionBuffer[reconstructionStride..],
reconstructionStride,
destination,
destinationStride,
pixelPosition,
predictionWidth,
predictionHeight,
subX,
subY,
modeInfo.WarpedMotionParameters,
warpedMotionParameters,
predictionScratch);
}

247
tests/ImageSharp.Tests/Formats/Heif/Av1/Av1CompoundBlockDecoderTests.cs

@ -11,6 +11,7 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction.Inter;
using SixLabors.ImageSharp.Formats.Heif.Av1.ReferenceFrames;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
using SixLabors.ImageSharp.Tests.TestUtilities;
namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
@ -20,6 +21,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
[Trait("Format", "Avif")]
public class Av1CompoundBlockDecoderTests
{
/// <summary>
/// The hardware configurations covering the warped predictor's vector and scalar paths.
/// </summary>
private const HwIntrinsics GlobalWarpConfigurations = HwIntrinsics.AllowAll | HwIntrinsics.DisableHWIntrinsic;
/// <summary>
/// Verifies that two retained reference planes are predicted and averaged before residual reconstruction.
/// </summary>
@ -111,6 +117,15 @@ public class Av1CompoundBlockDecoderTests
}
}
/// <summary>
/// Verifies that both references of a GLOBAL_GLOBALMV block use their complete matrix before compound averaging.
/// </summary>
[Fact]
public void DecodeBlockReconstructsCompoundGlobalWarpPrediction()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(
ValidateCompoundGlobalWarpPrediction,
GlobalWarpConfigurations);
/// <summary>
/// Verifies that the production block branch maps a smaller current frame into a larger retained reference.
/// </summary>
@ -601,13 +616,238 @@ public class Av1CompoundBlockDecoderTests
return modeInfo;
}
/// <summary>
/// Reconstructs a compound global-warp block at every supported native sample depth.
/// </summary>
private static void ValidateCompoundGlobalWarpPrediction()
{
foreach (Av1BitDepth bitDepth in new[] { Av1BitDepth.EightBit, Av1BitDepth.TenBit, Av1BitDepth.TwelveBit })
{
ValidateCompoundGlobalWarpPredictionAtBitDepth(bitDepth);
}
}
/// <summary>
/// Reconstructs one compound global-warp block and compares it with independently invoked scalar predictors.
/// </summary>
/// <param name="bitDepth">The native sample depth.</param>
private static void ValidateCompoundGlobalWarpPredictionAtBitDepth(Av1BitDepth bitDepth)
{
const int frameSize = 32;
const int blockOrigin = 8;
const int blockSize = 8;
ObuSequenceHeader sequenceHeader = CreateSequenceHeader(bitDepth, frameSize);
ObuFrameHeader frameHeader = CreateFrameHeader(frameSize);
frameHeader.GetReferenceFrameIndices()[0] = 0;
frameHeader.GetReferenceFrameIndices()[1] = 1;
Av1GlobalMotionParameters globalMotionParameters = Av1GlobalMotionParameters.Identity;
globalMotionParameters.Type = Av1GlobalMotionType.RotationZoom;
globalMotionParameters[0] = -357376;
globalMotionParameters[1] = 372736;
globalMotionParameters[2] = 65468;
globalMotionParameters[3] = 2856;
globalMotionParameters[4] = -2856;
globalMotionParameters[5] = 65468;
globalMotionParameters.UpdateShearParameters();
Assert.False(globalMotionParameters.IsInvalid);
frameHeader.GetGlobalMotionParameters()[0] = globalMotionParameters;
frameHeader.GetGlobalMotionParameters()[1] = globalMotionParameters;
using Av1ReferenceFrameStore referenceFrames = new();
Assert.True(referenceFrames.Commit(
1,
CreatePatternReferenceFrame(sequenceHeader, CreateFrameHeader(frameSize)),
showFrame: false));
Assert.True(referenceFrames.Commit(
2,
CreatePatternReferenceFrame(sequenceHeader, CreateFrameHeader(frameSize), sampleOffset: 40),
showFrame: false));
Av1FrameBuffer<byte> firstReference = referenceFrames.Resolve(0)!.FrameBuffer;
Av1FrameBuffer<byte> secondReference = referenceFrames.Resolve(1)!.FrameBuffer;
byte[] firstBytePrediction = new byte[blockSize * blockSize];
byte[] secondBytePrediction = new byte[blockSize * blockSize];
ushort[] firstHighBitDepthPrediction = new ushort[blockSize * blockSize];
ushort[] secondHighBitDepthPrediction = new ushort[blockSize * blockSize];
short[] firstScratch = new short[Av1InterPredictor.WarpedScratchLength];
short[] secondScratch = new short[Av1InterPredictor.WarpedScratchLength];
Point blockPosition = new(blockOrigin, blockOrigin);
if (bitDepth == Av1BitDepth.EightBit)
{
Span<byte> firstSource = firstReference.GetPaddedPlaneSpan(
Av1Plane.Y,
0,
0,
out int firstStride,
out Point firstOrigin);
Span<byte> secondSource = secondReference.GetPaddedPlaneSpan(
Av1Plane.Y,
0,
0,
out int secondStride,
out Point secondOrigin);
Av1InterPredictor.PredictWarpedScalar(
firstSource,
firstStride,
firstOrigin,
frameSize,
frameSize,
firstBytePrediction,
blockSize,
blockPosition,
blockSize,
blockSize,
0,
0,
globalMotionParameters,
firstScratch);
Av1InterPredictor.PredictWarpedScalar(
secondSource,
secondStride,
secondOrigin,
frameSize,
frameSize,
secondBytePrediction,
blockSize,
blockPosition,
blockSize,
blockSize,
0,
0,
globalMotionParameters,
secondScratch);
}
else
{
Span<ushort> firstSource = firstReference.GetPaddedPlaneSpan16(
Av1Plane.Y,
0,
0,
out int firstStride,
out Point firstOrigin);
Span<ushort> secondSource = secondReference.GetPaddedPlaneSpan16(
Av1Plane.Y,
0,
0,
out int secondStride,
out Point secondOrigin);
int bitDepthValue = bitDepth.GetBitCount();
Av1InterPredictor.PredictWarpedScalar(
firstSource,
firstStride,
firstOrigin,
frameSize,
frameSize,
firstHighBitDepthPrediction,
blockSize,
blockPosition,
blockSize,
blockSize,
0,
0,
bitDepthValue,
globalMotionParameters,
firstScratch);
Av1InterPredictor.PredictWarpedScalar(
secondSource,
secondStride,
secondOrigin,
frameSize,
frameSize,
secondHighBitDepthPrediction,
blockSize,
blockPosition,
blockSize,
blockSize,
0,
0,
bitDepthValue,
globalMotionParameters,
secondScratch);
}
using Av1FrameBuffer<byte> frameBuffer = new(
Configuration.Default,
sequenceHeader,
Av1ColorFormat.Yuv400,
false);
using Av1FrameInfo frameInfo = new(sequenceHeader);
Av1SuperblockInfo superblockInfo = frameInfo.GetSuperblock(Point.Empty);
superblockInfo.GetTransformInfoY()[0] = new Av1TransformInfo(Av1TransformSize.Size8x8, 0, 0);
Av1BlockModeInfo modeInfo = new(Av1BlockSize.Block8x8, new Point(2, 2))
{
Skip = true,
YMode = Av1PredictionMode.GlobalGlobalMotionVector,
CompoundIndex = true,
CompoundType = Av1CompoundType.Average,
};
modeInfo.ReferenceFrames[0] = Av1ReferenceFrameType.Last;
modeInfo.ReferenceFrames[1] = Av1ReferenceFrameType.Last2;
modeInfo.InterpolationFilters.Clear();
modeInfo.SetTransformUnitCount(Av1PlaneType.Y, 1);
Av1LoopFilterContext loopFilterContext = new(sequenceHeader);
Av1InverseQuantizer inverseQuantizer = new(sequenceHeader, frameHeader);
using Av1BlockDecoder decoder = new(
sequenceHeader,
frameHeader,
frameBuffer,
loopFilterContext,
inverseQuantizer,
referenceFrames);
decoder.UpdateSuperblock(superblockInfo);
decoder.DecodeBlock(
modeInfo,
new Point(2, 2),
Av1BlockSize.Block8x8,
superblockInfo,
new Av1TileInfo(0, 0, frameHeader));
for (int row = 0; row < blockSize; row++)
{
for (int column = 0; column < blockSize; column++)
{
int predictionIndex = (row * blockSize) + column;
if (bitDepth == Av1BitDepth.EightBit)
{
byte expected = (byte)((firstBytePrediction[predictionIndex] +
secondBytePrediction[predictionIndex] + 1) >> 1);
Span<byte> samples = frameBuffer.DeriveBlockPointer(Av1Plane.Y, 0, 0).DangerousGetRowSpan(blockOrigin + row);
Assert.Equal(expected, samples[blockOrigin + column]);
}
else
{
ushort expected = (ushort)((firstHighBitDepthPrediction[predictionIndex] +
secondHighBitDepthPrediction[predictionIndex] + 1) >> 1);
Span<ushort> samples = frameBuffer.GetHighBitDepthRowSpan(Av1Plane.Y, blockOrigin + row, 0, 0);
Assert.Equal(expected, samples[blockOrigin + column]);
}
}
}
}
/// <summary>
/// Creates one retained frame whose integer-coordinate luma samples make both OBMC axes observable.
/// </summary>
private static Av1ReferenceFrame CreatePatternReferenceFrame(
ObuSequenceHeader sequenceHeader,
ObuFrameHeader frameHeader,
Av1ColorFormat colorFormat = Av1ColorFormat.Yuv400)
Av1ColorFormat colorFormat = Av1ColorFormat.Yuv400,
int sampleOffset = 0)
{
Av1FrameBuffer<byte> frameBuffer = new(
Configuration.Default,
@ -628,7 +868,7 @@ public class Av1CompoundBlockDecoderTests
Span<byte> samples = frameBuffer.DeriveBlockPointer((Av1Plane)plane, subX, subY).DangerousGetRowSpan(row);
for (int column = 0; column < planeWidth; column++)
{
samples[column] = (byte)GetPlanePatternValue(plane, column, row);
samples[column] = (byte)(GetPlanePatternValue(plane, column, row) + sampleOffset);
}
}
else
@ -636,12 +876,13 @@ public class Av1CompoundBlockDecoderTests
Span<ushort> samples = frameBuffer.GetHighBitDepthRowSpan((Av1Plane)plane, row, subX, subY);
for (int column = 0; column < planeWidth; column++)
{
samples[column] = (ushort)GetPlanePatternValue(plane, column, row);
samples[column] = (ushort)(GetPlanePatternValue(plane, column, row) + sampleOffset);
}
}
}
}
Av1ReferenceFrameBorder.Extend(frameBuffer);
using Av1FrameInfo frameInfo = new(sequenceHeader);
return new Av1ReferenceFrame(frameBuffer, frameHeader, frameInfo);
}

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

@ -6,7 +6,9 @@ using System.Text;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Heif;
using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.Motion;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
using SixLabors.ImageSharp.Memory;
@ -198,6 +200,11 @@ public class Av1ReconstructionConformanceTests
/// </summary>
private const int LocalWarpCoverage = 1 << 8;
/// <summary>
/// The coverage bit representing non-translational global warped-motion prediction.
/// </summary>
private const int GlobalWarpCoverage = 1 << 9;
/// <summary>
/// The hardware configurations covering the available vector widths and the scalar color-conversion fallback.
/// </summary>
@ -796,6 +803,29 @@ public class Av1ReconstructionConformanceTests
returned => returned.AllocationId == allocation.AllocationId));
}
/// <summary>
/// Verifies production non-translational global-motion reconstruction against pinned native and presentation references.
/// </summary>
[Fact]
public void DecodeRealLibavifGlobalWarpSequenceMatchesPinnedReferences()
=> FeatureTestRunner.RunWithHwIntrinsicsFeature(
ValidateGlobalWarpSequenceWithDefaultConfiguration,
ReconstructionConfigurations);
/// <summary>
/// Verifies production non-translational global-motion reconstruction through a constrained allocator.
/// </summary>
[Fact]
[ValidateDisposedMemoryAllocations]
public void DecodeRealLibavifGlobalWarpSequenceUsesContiguousPlanes()
=> ValidateInterPredictionSequenceWithConstrainedAllocator(
TestImages.Heif.Av1GlobalWarpSequenceAvif,
TestImages.Heif.Av1GlobalWarpSequenceNativeReference,
TestImages.Heif.Av1GlobalWarpSequencePresentationReference,
GlobalWarpCoverage,
fixtureSize: 256,
visibleFrameCount: 2);
/// <summary>
/// Verifies one complete inter-prediction sequence with a separately tracked constrained allocator.
/// </summary>
@ -803,7 +833,9 @@ public class Av1ReconstructionConformanceTests
string imagePath,
string nativeReferencePath,
string presentationReferencePath,
int requiredCoverage)
int requiredCoverage,
int fixtureSize = AverageCompoundFixtureSize,
int visibleFrameCount = AverageCompoundFixtureFrameCount)
{
TestMemoryAllocator allocator = new() { BufferCapacityInBytes = 1_024 };
allocator.EnableNonThreadSafeLogging();
@ -816,7 +848,9 @@ public class Av1ReconstructionConformanceTests
nativeReferencePath,
presentationReferencePath,
requiredCoverage,
comparePresentation: false);
comparePresentation: false,
fixtureSize,
visibleFrameCount);
Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "RetainedMotionFieldEntry");
Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "TemporalMotionFieldEntry");
@ -860,6 +894,20 @@ public class Av1ReconstructionConformanceTests
fixtureSize: 256,
visibleFrameCount: 2);
/// <summary>
/// Runs the non-translational global-motion sequence with exact final presentation comparison.
/// </summary>
private static void ValidateGlobalWarpSequenceWithDefaultConfiguration()
=> ValidateInterPredictionSequence(
Configuration.Default,
TestImages.Heif.Av1GlobalWarpSequenceAvif,
TestImages.Heif.Av1GlobalWarpSequenceNativeReference,
TestImages.Heif.Av1GlobalWarpSequencePresentationReference,
GlobalWarpCoverage,
comparePresentation: true,
fixtureSize: 256,
visibleFrameCount: 2);
/// <summary>
/// Validates every selectable compound fixture with the requested decoder configuration.
/// </summary>
@ -996,11 +1044,12 @@ public class Av1ReconstructionConformanceTests
}
/// <summary>
/// Collects the selectable compound, inter-intra, and OBMC modes retained in one decoded frame.
/// Collects the compound, inter-intra, OBMC, and warped modes retained in one decoded frame.
/// </summary>
private static int GetInterPredictionCoverage(Av1Decoder decoder)
{
ObuSequenceHeader sequenceHeader = Assert.IsType<ObuSequenceHeader>(decoder.SequenceHeader);
ObuFrameHeader frameHeader = Assert.IsType<ObuFrameHeader>(decoder.FrameHeader);
Av1FrameInfo frameInfo = Assert.IsType<Av1FrameInfo>(decoder.FrameInfo);
int superblockSizeLog2 = sequenceHeader.SuperblockSizeLog2;
int superblockColumnCount = Av1Math.AlignPowerOf2(sequenceHeader.MaxFrameWidth, superblockSizeLog2) >> superblockSizeLog2;
@ -1023,6 +1072,26 @@ public class Av1ReconstructionConformanceTests
coverage |= LocalWarpCoverage;
}
if (modeInfo.YMode is Av1PredictionMode.GlobalMotionVector or Av1PredictionMode.GlobalGlobalMotionVector &&
Math.Min(modeInfo.BlockSize.GetWidth(), modeInfo.BlockSize.GetHeight()) >= 8)
{
int referenceCount = modeInfo.ReferenceFrames[1] > Av1ReferenceFrameType.Intra ? 2 : 1;
for (int referenceIndex = 0; referenceIndex < referenceCount; referenceIndex++)
{
int canonicalReferenceIndex =
(int)modeInfo.ReferenceFrames[referenceIndex] - (int)Av1ReferenceFrameType.Last;
Av1GlobalMotionParameters globalMotionParameters =
frameHeader.GetGlobalMotionParameters()[canonicalReferenceIndex];
if (globalMotionParameters.Type > Av1GlobalMotionType.Translation &&
!globalMotionParameters.IsInvalid)
{
coverage |= GlobalWarpCoverage;
}
}
}
if (modeInfo.ReferenceFrames[1] == Av1ReferenceFrameType.Intra)
{
coverage |= modeInfo.UseInterIntraWedge ? WedgeInterIntraCoverage : SmoothInterIntraCoverage;

3
tests/ImageSharp.Tests/TestImages.cs

@ -1383,6 +1383,9 @@ public static class TestImages
public const string Av1LocalWarpSequenceAvif = "Heif/Av1/Conformance/libavif-rotating-grid-local-warp.avif";
public const string Av1LocalWarpSequenceNativeReference = "Heif/Av1/Conformance/libavif-rotating-grid-local-warp-libaom.y4m";
public const string Av1LocalWarpSequencePresentationReference = "Heif/Av1/Conformance/libavif-rotating-grid-local-warp-libavif.png";
public const string Av1GlobalWarpSequenceAvif = "Heif/Av1/Conformance/libavif-rotating-grid-global-warp.avif";
public const string Av1GlobalWarpSequenceNativeReference = "Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libaom.y4m";
public const string Av1GlobalWarpSequencePresentationReference = "Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libavif.png";
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 Av1Cdef8BitAvif = "Heif/Av1/Conformance/libavif-cdef-kodim23-8b.avif";

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

@ -44,6 +44,7 @@ The reference builds use `AOM_TARGET_CPU=generic` and disable libyuv. Native rec
| `libavif-webp-logo-inter-intra` | Smooth and wedge inter-intra prediction |
| `libavif-webp-logo-obmc` | Above and left overlapping motion compensation through a 19-frame dependent sequence |
| `libavif-rotating-grid-local-warp` | Multi-sample local affine projection and warped prediction through a two-frame dependent sequence |
| `libavif-rotating-grid-global-warp` | Non-translational rotation/zoom GLOBALMV prediction through a two-frame dependent sequence |
The corresponding tests also assert the syntax required by each family before comparing output. This prevents an inactive tool or an incorrectly substituted stream from passing solely because its final pixels happen to match.
@ -132,6 +133,18 @@ The `libavif-rotating-grid-local-warp.avif` fixture was encoded from a determini
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.
## Global warped-motion fixture
The `libavif-rotating-grid-global-warp.avif` fixture uses the same deterministic two-frame 256x256 limited-range YUV444 source and its `82C1468C95C996B05165590417184F59373D67896F8C7B0EB398582C29C9C7A7` SHA-256. Pinned libavif commit `062e582e8afda88e6baf988fdcf046a801efa0f5` and libaom commit `03087864cf4bea6abb0d28f95cf7843511413d8f` generated the fixture and references with:
```text
./avifenc -j 1 -s 0 -q 100 -a color:enable-warped-motion=0 -a color:enable-global-motion=1 -a color:enable-obmc=0 rotating-grid-256-two-frame.y4m libavif-rotating-grid-global-warp.avif
./avifdec -j 1 --index 1 libavif-rotating-grid-global-warp.avif libavif-rotating-grid-global-warp-libaom.y4m
./avifdec -j 1 --index 1 libavif-rotating-grid-global-warp.avif libavif-rotating-grid-global-warp-libavif.png
```
The AVIF SHA-256 is `EE8CDF6DF36FB2999A17D2A86C41040D8BE13B958A1D5AE53E37343C6FB49E0E`. The retained frame-1 Y4M SHA-256 is `A36D445778BB2D37D69526A1058E3569DA24F3913317EFE22ADB61748A0F7511`, and the frame-1 PNG SHA-256 is `F7D27ABF79450DFA311F72106FD1DA80997EABC0937F2F5578EF627119FF83B0`. Pinned libaom tracing records seven actual `GLOBALMV` blocks using the valid rotation/zoom matrix `[-357376, 372736, 65468, 2856, -2856, 65468]` and reduced shear `[-64, 2880, -2880, 64]`. The production sequence test requires that decoded model and 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. A direct production-branch test independently drives both references of `GLOBAL_GLOBALMV` through the matrix predictor and compound averaging at 8, 10, and 12 bits.
## Updating fixtures
Do not create conformance references with ImageSharp. Generate both the native-plane and presentation references with an independent decoder, record the exact upstream revisions and source license, and preserve exact comparisons. A new tool-specific fixture should demonstrate that the relevant syntax is active and should be no larger than required to cover that behavior.

3
tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libaom.y4m

File diff suppressed because one or more lines are too long

3
tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libavif.png

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

3
tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp.avif

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