diff --git a/HEIF_IMPLEMENTATION_PLAN.md b/HEIF_IMPLEMENTATION_PLAN.md index 5a0874d27..e2feec34a 100644 --- a/HEIF_IMPLEMENTATION_PLAN.md +++ b/HEIF_IMPLEMENTATION_PLAN.md @@ -29,7 +29,7 @@ Checkboxes may be marked complete only when the implementation and the verificat ## Delivery dashboard -Last reconciled with the source tree on 2026-08-30 against production checkpoint `9d7348efd`. Committed checkpoints include the AV1 transform architecture, OBU framing, tile partitioning, mode information, segmentation, delta quantization, transform-size selection, coefficient decoding, inverse quantization, inverse transforms, complete intra prediction, intra-block copy, official extreme-displacement intra-block-copy conformance, the 12-profile reconstruction matrix, corrected twelve-bit inverse-transform SIMD arithmetic, 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, local warped prediction, non-translational global prediction, official motion-vector conformance, official spatial- and temporal-layer default-operating-point conformance, official active-film-grain and monochrome sequence conformance, selected spatial-layer presentation, progressive color and auxiliary-alpha conformance, pinned-HM HEVC CABAC verification, pinned-HM HEVC coding-tree traversal verification, official HEVC intra-prediction verification, official HEVC residual-reconstruction verification, HEVC parallel slice decoding, bounded HEVC supplemental presentation and metadata handling, and the complete independently coded HEVC Range Extensions native-plane profile/tool matrix. 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-30 against production checkpoint `640b64ee5` and the current local HEVC precision and presentation corrections. Committed checkpoints include the AV1 transform architecture, OBU framing, tile partitioning, mode information, segmentation, delta quantization, transform-size selection, coefficient decoding, inverse quantization, inverse transforms, complete intra prediction, intra-block copy, official extreme-displacement intra-block-copy conformance, the 12-profile reconstruction matrix, corrected twelve-bit inverse-transform SIMD arithmetic, 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, local warped prediction, non-translational global prediction, official motion-vector conformance, official spatial- and temporal-layer default-operating-point conformance, official active-film-grain and monochrome sequence conformance, selected spatial-layer presentation, progressive color and auxiliary-alpha conformance, pinned-HM HEVC CABAC verification, pinned-HM HEVC coding-tree traversal verification, official HEVC intra-prediction verification, official HEVC residual-reconstruction verification, HEVC parallel slice decoding, bounded HEVC supplemental presentation and metadata handling, and the complete independently coded HEVC Range Extensions native-plane profile/tool matrix. 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. Commit `a0d1b5af56acb3a3a9aebb29c916d1b36cd49367` restores the established JPEG color-converter operator architecture throughout the HEIF implementation. `Av1ForwardTransformer` owns its nested one-dimensional contract and all twelve concrete forward transform operators; `Av1Inverse2dTransformer` owns the corresponding inverse contract and operators; and `Av1InverseTransformer` owns the byte and high-bit-depth reconstruction-output operators. Each contract lives in the owner's `.Operator.cs`, while every semantic transform with a shared traversal has its own `.Operator.cs` partial-family file and implements concrete scalar and SIMD overload bodies without a forwarding semantic core. The same owner-and-partial-file rule now covers HEVC inverse transforms and intra prediction, AV1 and HEVC deblocking, AV1 CDEF, and HEVC transform-skip reconstruction. Vector-width and sample-storage adapters that are not semantic dispatch operators are named `Operations`; no operator type is named after a hardware width, no static contract uses CRTP, no source file groups multiple concrete semantic operator structs, and no semantic operator remains top-level. Roslynk reports zero compiler errors, both Release source targets build with zero warnings and errors, and 736 focused `net10.0` transform, loop-filter, prediction, reconstruction, transfer-function, and film-grain cases pass without failures or skips through the existing `FeatureTestRunner` coverage. All 56 new C# paths resolve to the existing `csharp` diff driver without an attributes change, and `git diff --check` is clean. @@ -83,16 +83,16 @@ 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 4 — complete HEVC still-image decoding.** The AV1 still-image exit gate is complete across the exact 12-profile matrix, layered reference-dependent items, every connected normative reconstruction tool, official quantizer and size boundaries, constrained allocation, and pinned native and presentation output. The bounded HEVC item-local syntax, allocator-backed decoder lifecycle, CABAC arithmetic and context state, coding-tree traversal, intra prediction, residual reconstruction, in-loop filtering, tiles, wavefront entry points, dependent slices, entry-point offset handling, supplemental presentation and metadata, and independently coded Range Extensions native-plane profile/tool matrix are implemented and verified through pinned-HM tables and analysis, official native-plane output, real HEIC payloads, constrained allocation, constructor failure, public presentation cases, and SIMD/scalar feature isolation. The next dependency is independently encoded HEIC container-presentation evidence across every exposed profile and required Range Extensions tool. Neither AV1 nor HEVC production encoding is implemented. +Current development stage: **Stage 4 — complete decoded presentation and animation.** The AV1 and independently coded HEVC still-image exit gates are complete across their exact profile, tool, constrained-allocation, SIMD-fallback, native-plane, and presentation matrices. The next dependency is the remaining shared color, ICC, alpha, grid, transform, metadata, and reference-dependent bounded-sequence decode matrix. Neither AV1 nor HEVC production encoding is implemented. -Immediate checkpoint: **current — close the HEVC container-presentation matrix.** Retain or independently produce genuine HEIC files across every exposed profile and required Range Extensions tool, preserve the completed exact native-plane oracle, and compare final ImageSharp presentation with an independent HEIF decoder before closing the Phase 4 decoder exit gate. +Immediate checkpoint: **current — close shared decoded presentation and bounded animation.** Complete the remaining color-signaling and ICC matrix, alpha, grid, transform, metadata, HEVC sequence, and reference-dependent AV1/HEVC presentation gates before starting either payload encoder. | 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** | AV1 still-image decoding has passed its complete exact native/presentation profile, layered-item, normative-tool, official-sequence, constrained-allocation, and SIMD-fallback exit gate. HEVC item-local syntax, lifecycle, CABAC, coding-tree traversal, intra prediction, residual reconstruction, in-loop filtering, tiles, wavefront entry points, dependent slices, entry-point offsets, bounded supplemental presentation and metadata, and the independently coded Range Extensions native-plane profile/tool matrix pass the recorded pinned-HM, official-plane, constrained-allocation, and scalar/SIMD evidence. | Close the remaining genuine-HEIC presentation matrix across every exposed profile and required Range Extensions tool. | -| 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. | +| 3 | Still-image AV1 and HEVC decoding | Complete | AV1 still-image decoding has passed its complete exact native/presentation profile, layered-item, normative-tool, official-sequence, constrained-allocation, and SIMD-fallback exit gate. HEVC independently coded still-image decoding passes the complete Range Extensions profile/tool matrix with exact pinned-HM native planes, exact pinned presentation, constrained allocation, and scalar/SIMD evidence. | None for bounded still-image decoding. | +| 4 | Complete decoded presentation and animation | **Current** | 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. | | 7 | Animated AVIF and HEIC encoding | Not started | Image-level repetition and per-frame duration contracts exist; bounded sequence parsing defines the required container surface. | Write the bounded sequence container and encode frame dependencies, timing, repetition, alpha, presentation, color, and metadata through both completed payload encoders. | @@ -151,8 +151,8 @@ Immediate checkpoint: **current — close the HEVC container-presentation matrix - [x] Verify HEVC CABAC arithmetic and every required context transition against pinned HM tables and complete production slices. - [x] Complete coding-tree, coding-unit, prediction-unit, and transform-unit traversal across every permitted size and partition mode. Eight official ITU first pictures compare exactly with pinned-HM native planes, pinned HM matches every archive complete-sequence MD5 and every RQT decoded-picture hash SEI, analyser output proves the recorded coding and transform sizes and partition alternatives, and all 150 focused HEVC decoder cases pass in Release. Commit `66d1f3c41b0baeaa98726b57d5feaeba50874f16` records the checkpoint. - [x] Complete HEVC intra prediction for every luma and chroma mode, including strong intra smoothing and constrained prediction rules. The official `IPRED_B_Nokia_3` native output and independently coded first `CIP_A_Panasonic_3` picture match pinned HM, all 149 focused HEVC decoder cases pass in Release, and commit `9bc5b9842` records the checkpoint. -- [ ] **Current:** complete the genuine-HEIC presentation matrix across every exposed HEVC profile and required Range Extensions tool, then close Phase 4 still-image decoding. -- [ ] Close shared decoded presentation, ICC, alpha, grid, transform, metadata, and animated AV1/HEVC decode gates. +- [x] Correct and reverify the genuine-HEIC presentation matrix across every exposed HEVC profile and required Range Extensions tool, then close Phase 4 still-image decoding. +- [ ] **Current:** close shared decoded presentation, ICC, alpha, grid, transform, metadata, and animated AV1/HEVC decode gates. - [ ] Implement and independently verify real AV1/AVIF still encoding. - [ ] Implement and independently verify real HEVC/HEIC still encoding. - [ ] Implement and independently verify animated AVIF and HEIC encoding through the bounded image-sequence surface. @@ -162,7 +162,7 @@ Performance, allocation, documentation, and independent test work are part of ea ## Detailed implementation ledger -- [ ] **Implemented foundation; conformance gate open:** complete HEVC still-picture reconstruction and connect its native planes to the verified shared SIMD-first HEIF color pipeline. +- [ ] **Implemented and profile/tool presentation verified; complete color-signaling conformance remains:** complete HEVC still-picture reconstruction and connect its native planes to the verified shared SIMD-first HEIF color pipeline. - [x] Correct AV1 clipped-edge partition entropy handling and verify every block-mode cell from a real libavif AVIF against libaom 3.14.1. - [x] Preserve the exact ICC payload from an independently encoded AVIF primary item. - [x] Prove that a genuine non-sRGB AVIF profile changes decoded pixels and matches the independently converted source image within the documented AV1 tolerance. @@ -175,6 +175,7 @@ Performance, allocation, documentation, and independent test work are part of ea - [x] Implement SIMD 4:2:0 and 4:2:2 encoder downsampling with odd-width and odd-height tails, and verify the stored 8/12-bit chroma samples against independently encoded full-resolution planes. - [x] Move the H.273 parameter resolver, closed color operators, transfer functions, sample loading/storage, chroma filtering, and RGB packing into one shared HEIF color pipeline used by both AV1 and HEVC rather than maintaining codec-specific arithmetic copies. - [x] Drive AV1 and HEVC through the same `IHeifPlanarSampleBuffer` and `HeifPlanarColorConverter` architecture. Codec namespaces now adapt only native rows, sample precision, subsampling, crop windows, chroma positions, and codec color signaling; pooled row scheduling, chroma reconstruction/downsampling, fixed-point specialization, SIMD traversal, scalar tails, and RGB packing are selected by the shared HEIF driver. + - [x] Remove redundant `internal` member visibility from internal HEIF types. Existing assembly-visible methods, properties, accessors, and the cross-type constructor now use public member visibility, while type-local private members and JPEG-style internal nested operator contracts remain unchanged. Both Release source builds complete with zero warnings and zero errors, Roslynk reports zero compiler errors, and all 266 focused HEVC cases pass. Commit `6e906fed4` records the correction. - [x] Implement sequential pooled HEVC conversion in both directions for monochrome, 4:2:0, 4:2:2, and 4:4:4; independent luma/chroma precision; 8/10/12-bit full/limited ranges; and all six progressive 4:2:0 chroma sample locations. Eight-bit paths use JPEG's optimized RGB plane contracts, while high-bit-depth paths retain 16-bit packed pixels. - [x] Implement allocation-free SIMD-first HEVC intra prediction for all 35 modes, 4/8/16/32 blocks, and 8/10/12-bit samples, including three-tap and strong-bilinear reference filtering, negative-angle reference extension, luma boundary filters, and SIMD horizontal transposition. Verify the normal and forced-scalar paths against one scalar oracle. - [x] Match HM's channel-specific smoothing rules: combined 4:4:4 chroma uses the normal three-tap filter when selected, while strong bilinear smoothing remains restricted to luma syntax. Exact official RExt reconstruction passes at 8, 10, and 12 bits. @@ -186,6 +187,7 @@ Performance, allocation, documentation, and independent test work are part of ea - [x] Compare complete HEIC presentation output exactly with libheif 1.23.1 and libde265 1.1.1 for single images, multi-tile grids, an auxiliary alpha image, ICC-bearing images, 4:2:0, and 4:4:4 output. Keep the exact HM native-plane tests as the independent codec-reconstruction oracle. - [x] Add permanent official HEVC 8/10/12-bit monochrome, 4:2:0, 4:2:2, and 4:4:4 fixtures with exact native-plane references and published per-plane digests. All 10 first pictures from the Sony GENERAL RExt conformance streams match every Y, Cb, and Cr sample with normal SIMD dispatch and with all hardware intrinsics disabled. - [x] Extend the permanent HEVC matrix to every exposed profile and each Range Extensions tool not individually isolated by the Sony GENERAL streams, with exact native-plane references from HM or another independent decoder. Commit `9d7348efd6496b54cef7ec27e42352641439c400` records 25 additional official-picture cases, exact profile/tool signaling, exact native-plane hashes, the PCM precision and chroma-deblocking corrections, both zero-warning Release source builds, all 220 focused HEVC cases, verified existing LFS attributes and fixture hashes, zero Roslynk compiler errors, and clean `git diff --check`. + - [x] Retain 35 real HEIC containers and verify the complete independently coded profile/tool presentation matrix. Exact native-plane reconstruction remains pinned to HM; direct pinned-libheif presentation is used only where its HEVC backend reproduces those planes. Rejected or incorrectly reconstructed libheif profiles use pinned HM planes passed through an independent reproduction of libheif 1.23.1's float32 H.273 conversion, including nearest chroma traversal and source-precision clipping. FFmpeg raw output is accepted only as a byte-exact HM cross-check and its PNG conversion is not a reference. High-bit-depth conversion now retains source precision through `Rgba64` instead of an eight-bit intermediate. The exact 25-case native matrix, 29 direct presentation cases, and three `FeatureTestRunner` presentation cases pass; the latter cover 8-bit subsampled, 12-bit full-resolution, and 12-bit `Rgba64` output across the available SIMD widths and scalar fallback. Five constrained tracked-allocator cases retain balanced exactly-once returns. Both `net10.0` and `net11.0` Release source builds pass with zero warnings and errors. Commit `640b64ee5` records the original fixture matrix and the now-superseded weak comparison; the current local correction replaces that tolerance with exact pinned presentation evidence. - [x] Implement the shared SIMD-first YUV/CICP paths in both directions for AV1 and HEVC bit depths, chroma formats, ranges, matrix coefficients, transfer functions, color primaries, and chroma positions, with scalar fallback only after the available vector widths are exhausted. - [ ] Complete the independently generated AV1 and HEVC conformance matrix for every supported color-signaling combination before closing the Phase 5 color exit gate. - [x] Apply ICC conversion only after the SIMD YUV/CICP stage, alpha composition, grid assembly, and presentation transforms have produced the presented RGB image; retain ImageSharp's shared ICC converter and optimize reusable bulk kernels rather than creating a HEIF-specific color-management implementation. @@ -432,16 +434,16 @@ This assessment was reconciled with the source tree on 2026-08-30, including pro - Decode now resolves `cdsc`-associated Exif and `application/rdf+xml` XMP items for the primary still image, validates the declared Exif TIFF-header offset, and attaches the payloads through ImageSharp's existing profile types before presentation transforms. Independent AVIF, HEIC, and HIF metadata fixtures and Identify-time profile reporting remain required. - ICC and `nclx` CICP color properties are now associated with the presented color item instead of global parser state, validated, and exposed on Decode and Identify through the existing ImageSharp profiles. AV1 decode requires specified sequence-header fields and the range flag to match `nclx`, uses the property only for fields the bitstream leaves unspecified, and exposes the effective sequence-header CICP description when no property is present. Independent libavif fixtures verify exact ICC byte preservation, observable non-sRGB conversion, canonical-sRGB compaction, non-sRGB compact preservation, and metadata skipping for primary, grid, alpha-composited, and every presented sequence frame; the alpha vector also verifies that ICC conversion does not alter composed alpha. Identify-time bitstream fallback, independent CICP vectors, and HEVC integration remain required. - Pixel aspect ratio now preserves the complete unsigned spacing pair, affects Decode and Identify through ImageSharp's existing unitless resolution metadata, and follows quarter-turn presentation rotation. Independent grid, rotation, and maximum-spacing fixtures remain required. -- AV1 codec configuration is now retained per `av01` image item rather than in decoder-global state. Decode requires the property, validates its fixed record against the item's sequence header and any associated `pixi` channel depths, and requires matching configurations across grid tiles. Identify now reports the configuration's 8/10/12-bit precision and monochrome shape. The optional `configOBUs` sequence is bounded and validated, including its mandatory size fields, first-position/at-most-one sequence-header rule, the image item's exactly-one sequence-header rule, and exact comparison of a repeated configuration header with the item header. Content light-level and mastering-display color-volume information are decoded from the bounded `clli` and `mdcv` image properties and matching AV1 HDR metadata OBUs, with the representations' distinct fixed-point precision, grid/property precedence, and `SkipMetadata` behavior preserved. The still-image `cclv`, `amve`, `reve`, and `ndwt` properties preserve content-volume, ambient-viewing, mastering-environment, and diffuse-white descriptions without importing their video-SEI or sample-entry state models. Independent fixtures and encoder preservation remain required. HEVC `hvcC` is associated with each `hvc1` image item, structurally validated through its VPS/SPS/PPS arrays, and used to report encoded precision and monochrome shape. The bounded decoder reconstructs exact native planes for the complete independently coded 8/10/12-bit monochrome, 4:2:0, 4:2:2, and 4:4:4 Range Extensions profile/tool matrix; genuine HEIC container-presentation evidence across that complete matrix remains open. +- AV1 codec configuration is now retained per `av01` image item rather than in decoder-global state. Decode requires the property, validates its fixed record against the item's sequence header and any associated `pixi` channel depths, and requires matching configurations across grid tiles. Identify now reports the configuration's 8/10/12-bit precision and monochrome shape. The optional `configOBUs` sequence is bounded and validated, including its mandatory size fields, first-position/at-most-one sequence-header rule, the image item's exactly-one sequence-header rule, and exact comparison of a repeated configuration header with the item header. Content light-level and mastering-display color-volume information are decoded from the bounded `clli` and `mdcv` image properties and matching AV1 HDR metadata OBUs, with the representations' distinct fixed-point precision, grid/property precedence, and `SkipMetadata` behavior preserved. The still-image `cclv`, `amve`, `reve`, and `ndwt` properties preserve content-volume, ambient-viewing, mastering-environment, and diffuse-white descriptions without importing their video-SEI or sample-entry state models. Independent fixtures and encoder preservation remain required. HEVC `hvcC` is associated with each `hvc1` image item, structurally validated through its VPS/SPS/PPS arrays, and used to report encoded precision and monochrome shape. The bounded decoder reconstructs exact native planes and exact genuine-HEIC presentation for the complete independently coded 8/10/12-bit monochrome, 4:2:0, 4:2:2, and 4:4:4 Range Extensions profile/tool matrix. - Several image-item properties and relationships remain missing or parsed without fully affecting output. - Identify and decode now use the same bounded metadata parser and both validate the complete leading file type box. The parsed state is still mutable and Identify does not yet report the complete bit depth, color, profile, or transform model. ### HEVC decoder and encoder - `Heif4CharCode` recognizes `hvc1` image items, `HevcCodecConfiguration` validates and associates the bounded `hvcC` property, Identify reports its HEVC precision and monochrome shape, and `HeifCompressionFactory` registers the bounded HEVC still-image decoder. -- The HEVC path validates NAL headers and RBSP escaping, links `hvcC` VPS/SPS/PPS structures through Range Extensions, parses one length-delimited base-layer IDR picture, and reconstructs its complete intra-coded coding tree. It includes CABAC, transform traversal, coefficient decoding, intra prediction, inverse quantization and transform, PCM, deblocking, sample-adaptive offset, and allocator-owned native `ushort` planes for monochrome, 4:2:0, 4:2:2, 4:4:4, separate-color-plane, and 8-through-16-bit samples. The item adapter converts the SPS conformance window directly through the shared pooled SIMD-first H.273 pipeline and preserves the effective container-or-VUI CICP description. Four real item payloads match HM 18 native planes exactly, ten official Sony GENERAL pictures cover the 8/10/12-bit chroma-layout boundary, and 25 additional official pictures cover every exposed independently coded Range Extensions profile and required tool with exact native-plane hashes. Complete images covering grids, auxiliary alpha, ICC, 4:2:0, and 4:4:4 presentation also match independent libheif output exactly. Genuine HEIC presentation across the complete profile/tool matrix and the complete color matrix remain open. +- The HEVC path validates NAL headers and RBSP escaping, links `hvcC` VPS/SPS/PPS structures through Range Extensions, parses one length-delimited base-layer IDR picture, and reconstructs its complete intra-coded coding tree. It includes CABAC, transform traversal, coefficient decoding, intra prediction, inverse quantization and transform, PCM, deblocking, sample-adaptive offset, and allocator-owned native `ushort` planes for monochrome, 4:2:0, 4:2:2, 4:4:4, separate-color-plane, and 8-through-16-bit samples. The item adapter converts the SPS conformance window directly through the shared pooled SIMD-first H.273 pipeline and preserves the effective container-or-VUI CICP description. Four real item payloads match HM 18 native planes exactly, ten official Sony GENERAL pictures cover the 8/10/12-bit chroma-layout boundary, and 25 additional official pictures cover every exposed independently coded Range Extensions profile and required tool with exact native-plane hashes. Complete images covering grids, auxiliary alpha, ICC, and the complete independently coded Range Extensions profile/tool matrix match pinned presentation references exactly. The complete color-signaling matrix remains open. - There is no HEVC encoder. `HeifEncoderCore` rejects `HeifCompressionMethod.Hevc`; the separately selected legacy JPEG path emits a generic HEIF/HIF-style JPEG image item and does not provide HEIC output. -- Permanent HEVC conformance tests compare extracted item planes exactly with HM output or normative decoded-picture hashes and complete presented images exactly with pinned libheif/libde265 reference PNGs. Native-plane fixtures cover the complete independently coded exposed profile/tool matrix; genuine HEIC presentation fixtures do not yet cover that complete matrix. +- Permanent HEVC conformance tests compare extracted item planes exactly with HM output or normative decoded-picture hashes and complete presented images exactly with pinned references. Direct libheif/libde265 output is retained where its native reconstruction is exact; other profile/tool cases use pinned HM planes and independently reproduced pinned-libheif conversion. Native-plane and genuine-HEIC presentation fixtures cover the complete independently coded exposed profile/tool matrix. ### AV1 decoder @@ -481,7 +483,7 @@ This assessment was reconciled with the source tree on 2026-08-30, including pro ### Tests -- HEVC coverage includes exact native-plane comparison with HM output or normative decoded-picture hashes, exact complete-image comparison with pinned libheif/libde265 references, ten official Sony GENERAL pictures across the 8/10/12-bit chroma-layout boundary, and 25 additional official Range Extensions pictures across every exposed independently coded profile and required tool. The remaining Phase 4 evidence is genuine HEIC presentation across that complete profile/tool matrix. +- HEVC coverage includes exact native-plane comparison with HM output or normative decoded-picture hashes, exact complete-image comparison with pinned presentation references, ten official Sony GENERAL pictures across the 8/10/12-bit chroma-layout boundary, and 25 additional official Range Extensions pictures across every exposed independently coded profile and required tool. Genuine HEIC presentation covers that complete independently coded profile/tool matrix; dependent-picture decoding and encoding remain separate Phase 4 work. - AV1 has focused bitstream, prediction, entropy, reconstruction, filter, film-grain, color, and transform coverage, plus real libavif inputs. A real two-layer libavif-derived OBU stream verifies the bounded frame lifecycle, retained-slot occupancy, resolved inter references, and `frame_size_with_refs` dimensions through a fake tile lifecycle. The corrected progressive color item then verifies its production single-reference inter branch against exact pinned-libaom native planes and pinned-libavif presentation. The pinned 19-frame YUV444 sequence separately reaches production equal-average compound reconstruction after every preceding reference sample and matches its final native and presented references exactly. A real palette stream truncated inside its tile entropy payload verifies libaom-equivalent overflow/trailing-bit rejection and decoder-session recovery. The committed equal-average checkpoint passes 119 direct focused cases plus three `FeatureTestRunner` cases, zero-warning `net10.0` and `net11.0` source builds, a zero-error test-project analyzer build with pre-existing repository warnings, allocator lifetime validation, and `git diff --check`. Four additional pinned sequences reach distance-weighted, both wedge signs, both difference-mask orientations, and smooth and wedge inter-intra reconstruction with exact final native and presented output. Commit `864b11ad9791d3254a38691246270c569001b5a1` records the selectable-compound checkpoint after both source targets, the test-project analyzer build, 25 direct focused cases, six `FeatureTestRunner` cases, constrained allocation, exactly-once tracked returns, and `git diff --check` passed. Commit `59a4fbad5ed3bc7c34331c4bdc65acc7acde3f04` adds exact traced OBMC sequence evidence, subsampled direct reconstruction, constrained allocation, both source builds, the analyzer build, 14 direct cases, the normal/scalar `FeatureTestRunner` comparison, and clean staged `git diff --check`. Commit `8f57c29b250b4291f034b31c1ea3de3fa3345467` adds a genuine size-changing layered AVIF, exact retained-base and final native planes, exact final presentation, active inter deblocking, constrained allocation, normal/scalar dispatch, direct 8/10/12-bit block reconstruction, and 87 passing focused cases. The local-warp checkpoint adds a genuine two-frame 256x256 bounded AVIF with many traced `WARPED_CAUSAL` blocks, exact pinned multi-sample projection, exact final native and presentation comparisons, constrained allocation, normal/scalar `FeatureTestRunner` dispatch, direct 8/10/12-bit predictor parity, zero-warning source builds, and 86 passing focused cases. Valid still-image syntax paths still contain explicit unsupported branches, so the independent AV1 decode matrix is not complete. - Local-warp fixture provenance is pinned to libavif `062e582e8afda88e6baf988fdcf046a801efa0f5` and libaom `03087864cf4bea6abb0d28f95cf7843511413d8f`. A deterministic two-frame limited-range YUV444 grid sequence was encoded with `avifenc -j 1 -s 0 -q 60 -a color:enable-warped-motion=1 -a color:enable-global-motion=0 -a color:enable-obmc=0`. SHA-256 values are `990BAC4AD443005C217B0DA4FCCFA9ADFB3AA147AD06C85F9A655A4433E9E8A7` for the AVIF, `984B2815CEE0C05FDE26430F150A21B5C993141E25BA1ED4FDE09372DB64AC13` for the pinned-libaom frame-1 Y4M, and `4490D62FB6679378E92CACA48427359091AD2106BE49FC1A3848F78BE03BEEB1` for the pinned-libavif frame-1 PNG. - Scaled-reference fixture provenance is pinned to libavif `062e582e8afda88e6baf988fdcf046a801efa0f5` and libaom `03087864cf4bea6abb0d28f95cf7843511413d8f`. The source is libavif `tests/data/webp_logo_animated.y4m`, encoded as two layered YUV444 inputs with `avifenc -j 1 -q 90 --layered --scaling-mode:u 1/2 --scaling-mode:u 1/1 `. The resulting item contains a 701-byte 40x40 base layer followed by a 1,494-byte 80x80 dependent layer. SHA-256 values are `EB239F31EC8DBF5E97AD6F52670FCA6497AE2A933822CFE724C75F66AAA2520B` for the AVIF, `B7E30E04A935414A517BAA2DF06AB756DA18BA7C291220D9D7C063297761AE82` for the 2,195-byte logical AV1 payload, `873DC1AB5623910FBF8053CBF684399F4F3BDDBA4110492E3E11DE86E01FEC1B` for the 4,800-byte pinned-libaom base YUV, `964F4D85A79FC10EEB3722E2C9DA3415083E1EB8C2611FE154946FA55E2171ED` for the pinned-libaom final Y4M, and `DC4C6DBE6BD92C5FCE1E3E23700AFA603EF04ED02EDD336213EBBA1E3BD84BA0` for the pinned-libavif final PNG. @@ -901,8 +903,8 @@ The dashboard and immediate execution queue define the remaining critical path. - [x] Complete progressive color and auxiliary-alpha verification through exact native and presentation comparisons, every required `FeatureTestRunner` fallback, and constrained tracked allocation. - [x] Correct the audited 12-bit inverse ADST4, Identity4, and Identity16 arithmetic through exact pinned boundary vectors and SIMD/scalar feature isolation. - [x] Remove every other unsupported valid AV1 still-image syntax path and prove the complete AVIF decode matrix with independent inputs and scalar/SIMD parity. Commit `2219edbc91edb6a2d905f1221a45207eb2719abc` closes Phase 3. -- [ ] **Current:** close Phase 4 with genuine HEIC presentation evidence across every exposed profile and required Range Extensions tool; the native-plane matrix is complete. -- [ ] 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. +- [x] Close Phase 4 with genuine HEIC presentation evidence across every exposed profile and required Range Extensions tool while retaining the exact native-plane matrix. +- [ ] **Current:** 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. - [ ] Complete Phase 6 with a real AV1 encoder and independent AVIF cross-decode across every public option and metadata combination. - [ ] Complete Phase 7 with a real HEVC encoder and independent HEIC cross-decode across every public option and metadata combination. diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifPlanarColorConverter.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifPlanarColorConverter.cs index 082933fb1..522b2d0a5 100644 --- a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifPlanarColorConverter.cs +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifPlanarColorConverter.cs @@ -48,7 +48,7 @@ internal static class HeifPlanarColorConverter where TPixel : unmanaged, IPixel where TBuffer : struct, IHeifPlanarSampleBuffer { - if (HeifYuv420ToRgb8Converter.IsSupported( + if (HeifYuvToRgb8Converter.SupportsFixedPointConversion( buffer.ChromaSubsamplingX, buffer.ChromaSubsamplingY, buffer.LumaBitDepth, @@ -59,7 +59,7 @@ internal static class HeifPlanarColorConverter { // The fixed-point operator preserves the exact code-value rounding used by the verified eight-bit // presentation path. Selection belongs here so no codec can acquire a private color-conversion route. - HeifYuv420ToRgb8Converter.Convert(configuration, buffer, image, in parameters, sourceX, sourceY); + HeifYuvToRgb8Converter.ConvertFixedPoint(configuration, buffer, image, in parameters, sourceX, sourceY); return; } diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifSampleConversion.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifSampleConversion.cs index 9817cad90..39bcbc436 100644 --- a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifSampleConversion.cs +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifSampleConversion.cs @@ -589,6 +589,81 @@ internal static class HeifSampleConversion } } + /// + /// Packs 16-bit RGB component rows into opaque 16-bit RGBA pixels. + /// + /// The red components. + /// The green components. + /// The blue components. + /// The destination pixels. + public static void PackRgba64(ReadOnlySpan red, ReadOnlySpan green, ReadOnlySpan blue, Span destination) + { + ref ushort redBase = ref MemoryMarshal.GetReference(red); + ref ushort greenBase = ref MemoryMarshal.GetReference(green); + ref ushort blueBase = ref MemoryMarshal.GetReference(blue); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); + int length = destination.Length; + int i = 0; + + if (Vector512.IsHardwareAccelerated) + { + int oneVectorFromEnd = length - Vector512.Count; + for (; i <= oneVectorFromEnd; i += Vector512.Count) + { + (Vector256 redLower, Vector256 redUpper) = Vector256.Widen(Vector256.LoadUnsafe(ref Unsafe.Add(ref redBase, i))); + (Vector256 greenLower, Vector256 greenUpper) = Vector256.Widen(Vector256.LoadUnsafe(ref Unsafe.Add(ref greenBase, i))); + (Vector256 blueLower, Vector256 blueUpper) = Vector256.Widen(Vector256.LoadUnsafe(ref Unsafe.Add(ref blueBase, i))); + Vector512 r = Vector512.Create(redLower, redUpper).AsInt32(); + Vector512 g = Vector512.Create(greenLower, greenUpper).AsInt32(); + Vector512 b = Vector512.Create(blueLower, blueUpper).AsInt32(); + StoreRgba64Batch(r.GetLower().GetLower(), g.GetLower().GetLower(), b.GetLower().GetLower(), ref Unsafe.Add(ref destinationBase, i)); + StoreRgba64Batch(r.GetLower().GetUpper(), g.GetLower().GetUpper(), b.GetLower().GetUpper(), ref Unsafe.Add(ref destinationBase, i + 4)); + StoreRgba64Batch(r.GetUpper().GetLower(), g.GetUpper().GetLower(), b.GetUpper().GetLower(), ref Unsafe.Add(ref destinationBase, i + 8)); + StoreRgba64Batch(r.GetUpper().GetUpper(), g.GetUpper().GetUpper(), b.GetUpper().GetUpper(), ref Unsafe.Add(ref destinationBase, i + 12)); + } + } + + if (Vector256.IsHardwareAccelerated) + { + int oneVectorFromEnd = length - Vector256.Count; + for (; i <= oneVectorFromEnd; i += Vector256.Count) + { + Vector128 red16 = Vector128.LoadUnsafe(ref Unsafe.Add(ref redBase, i)); + Vector128 green16 = Vector128.LoadUnsafe(ref Unsafe.Add(ref greenBase, i)); + Vector128 blue16 = Vector128.LoadUnsafe(ref Unsafe.Add(ref blueBase, i)); + Vector256 r = Vector256.Create(Vector128.WidenLower(red16), Vector128.WidenUpper(red16)).AsInt32(); + Vector256 g = Vector256.Create(Vector128.WidenLower(green16), Vector128.WidenUpper(green16)).AsInt32(); + Vector256 b = Vector256.Create(Vector128.WidenLower(blue16), Vector128.WidenUpper(blue16)).AsInt32(); + StoreRgba64Batch(r.GetLower(), g.GetLower(), b.GetLower(), ref Unsafe.Add(ref destinationBase, i)); + StoreRgba64Batch(r.GetUpper(), g.GetUpper(), b.GetUpper(), ref Unsafe.Add(ref destinationBase, i + 4)); + } + } + + if (Vector128.IsHardwareAccelerated) + { + int oneVectorFromEnd = length - Vector128.Count; + for (; i <= oneVectorFromEnd; i += Vector128.Count) + { + ulong packedRed = Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref redBase, i))); + ulong packedGreen = Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref greenBase, i))); + ulong packedBlue = Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref blueBase, i))); + Vector128 r = Vector128.WidenLower(Vector128.CreateScalarUnsafe(packedRed).AsUInt16()).AsInt32(); + Vector128 g = Vector128.WidenLower(Vector128.CreateScalarUnsafe(packedGreen).AsUInt16()).AsInt32(); + Vector128 b = Vector128.WidenLower(Vector128.CreateScalarUnsafe(packedBlue).AsUInt16()).AsInt32(); + StoreRgba64Batch(r, g, b, ref Unsafe.Add(ref destinationBase, i)); + } + } + + for (; i < length; i++) + { + Unsafe.Add(ref destinationBase, i) = new Rgba64( + Unsafe.Add(ref redBase, i), + Unsafe.Add(ref greenBase, i), + Unsafe.Add(ref blueBase, i), + ushort.MaxValue); + } + } + /// /// Packs normalized RGB component rows into opaque 16-bit RGBA pixels. /// diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.Parameters.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.Parameters.cs deleted file mode 100644 index 7584e9b00..000000000 --- a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.Parameters.cs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.Intrinsics; - -namespace SixLabors.ImageSharp.Formats.Heif.Components; - -/// -/// Provides fixed-point scalar and SIMD coefficient storage for eight-bit 4:2:0 conversion. -/// -internal static partial class HeifYuv420ToRgb8Converter -{ - /// - /// Stores every scalar and SIMD coefficient representation resolved once for an image. - /// - private readonly struct ConversionParameters - { - /// - /// The scalar fixed-point coefficients. - /// - public readonly FixedPointParameters Scalar; - - /// - /// The four-lane SIMD coefficients. - /// - public readonly Vector128Parameters FourLane; - - /// - /// The eight-lane SIMD coefficients. - /// - public readonly Vector256Parameters EightLane; - - /// - /// The sixteen-lane SIMD coefficients. - /// - public readonly Vector512Parameters SixteenLane; - - /// - /// Initializes a new instance of the struct. - /// - /// The shared floating-point conversion parameters. - public ConversionParameters(in HeifColorConversionParameters parameters) - { - FixedPointParameters scalar = new(in parameters); - this.Scalar = scalar; - this.FourLane = new(in scalar); - this.EightLane = new(in scalar); - this.SixteenLane = new(in scalar); - } - } - - /// - /// Stores the scalar fixed-point coefficients resolved for one image. - /// - private readonly struct FixedPointParameters - { - /// - /// Initializes a new instance of the struct. - /// - /// The shared floating-point conversion parameters. - public FixedPointParameters(in HeifColorConversionParameters parameters) - { - float scale = 1 << CoefficientShift; - - // Rounding each image-invariant coefficient once gives the integer kernel eight fractional bits. - // The signed green coefficients retain the exact addition and rounding order used by every SIMD lane. - this.RedCr = (int)MathF.Round(parameters.RedChromaScale * scale, MidpointRounding.AwayFromZero); - this.GreenCb = -(int)MathF.Round(parameters.GreenBlueChromaScale * scale, MidpointRounding.AwayFromZero); - this.GreenCr = -(int)MathF.Round(parameters.GreenRedChromaScale * scale, MidpointRounding.AwayFromZero); - this.BlueCb = (int)MathF.Round(parameters.BlueChromaScale * scale, MidpointRounding.AwayFromZero); - } - - /// - /// Gets the red contribution from centered Cr. - /// - public int RedCr { get; } - - /// - /// Gets the green contribution from centered Cb. - /// - public int GreenCb { get; } - - /// - /// Gets the green contribution from centered Cr. - /// - public int GreenCr { get; } - - /// - /// Gets the blue contribution from centered Cb. - /// - public int BlueCb { get; } - } - - /// - /// Broadcasts the fixed-point coefficients for four-lane conversion. - /// - private readonly struct Vector128Parameters - { - /// - /// Initializes a new instance of the struct. - /// - /// The scalar fixed-point coefficients. - public Vector128Parameters(in FixedPointParameters parameters) - { - this.ChromaMidpoint = Vector128.Create(HeifYuv420ToRgb8Converter.ChromaMidpoint); - this.RoundingBias = Vector128.Create(HeifYuv420ToRgb8Converter.RoundingBias); - this.Maximum = Vector128.Create((int)byte.MaxValue); - this.RedCr = Vector128.Create(parameters.RedCr); - this.GreenCb = Vector128.Create(parameters.GreenCb); - this.GreenCr = Vector128.Create(parameters.GreenCr); - this.BlueCb = Vector128.Create(parameters.BlueCb); - } - - /// - /// Gets the neutral chroma code-value lanes. - /// - public Vector128 ChromaMidpoint { get; } - - /// - /// Gets the fixed-point rounding-bias lanes. - /// - public Vector128 RoundingBias { get; } - - /// - /// Gets the maximum eight-bit sample lanes. - /// - public Vector128 Maximum { get; } - - /// - /// Gets the red Cr coefficient lanes. - /// - public Vector128 RedCr { get; } - - /// - /// Gets the green Cb coefficient lanes. - /// - public Vector128 GreenCb { get; } - - /// - /// Gets the green Cr coefficient lanes. - /// - public Vector128 GreenCr { get; } - - /// - /// Gets the blue Cb coefficient lanes. - /// - public Vector128 BlueCb { get; } - } - - /// - /// Broadcasts the fixed-point coefficients for eight-lane conversion. - /// - private readonly struct Vector256Parameters - { - /// - /// Initializes a new instance of the struct. - /// - /// The scalar fixed-point coefficients. - public Vector256Parameters(in FixedPointParameters parameters) - { - this.ChromaMidpoint = Vector256.Create(HeifYuv420ToRgb8Converter.ChromaMidpoint); - this.RoundingBias = Vector256.Create(HeifYuv420ToRgb8Converter.RoundingBias); - this.Maximum = Vector256.Create((int)byte.MaxValue); - this.RedCr = Vector256.Create(parameters.RedCr); - this.GreenCb = Vector256.Create(parameters.GreenCb); - this.GreenCr = Vector256.Create(parameters.GreenCr); - this.BlueCb = Vector256.Create(parameters.BlueCb); - } - - /// - /// Gets the neutral chroma code-value lanes. - /// - public Vector256 ChromaMidpoint { get; } - - /// - /// Gets the fixed-point rounding-bias lanes. - /// - public Vector256 RoundingBias { get; } - - /// - /// Gets the maximum eight-bit sample lanes. - /// - public Vector256 Maximum { get; } - - /// - /// Gets the red Cr coefficient lanes. - /// - public Vector256 RedCr { get; } - - /// - /// Gets the green Cb coefficient lanes. - /// - public Vector256 GreenCb { get; } - - /// - /// Gets the green Cr coefficient lanes. - /// - public Vector256 GreenCr { get; } - - /// - /// Gets the blue Cb coefficient lanes. - /// - public Vector256 BlueCb { get; } - } - - /// - /// Broadcasts the fixed-point coefficients for sixteen-lane conversion. - /// - private readonly struct Vector512Parameters - { - /// - /// Initializes a new instance of the struct. - /// - /// The scalar fixed-point coefficients. - public Vector512Parameters(in FixedPointParameters parameters) - { - this.ChromaMidpoint = Vector512.Create(HeifYuv420ToRgb8Converter.ChromaMidpoint); - this.RoundingBias = Vector512.Create(HeifYuv420ToRgb8Converter.RoundingBias); - this.Maximum = Vector512.Create((int)byte.MaxValue); - this.RedCr = Vector512.Create(parameters.RedCr); - this.GreenCb = Vector512.Create(parameters.GreenCb); - this.GreenCr = Vector512.Create(parameters.GreenCr); - this.BlueCb = Vector512.Create(parameters.BlueCb); - } - - /// - /// Gets the neutral chroma code-value lanes. - /// - public Vector512 ChromaMidpoint { get; } - - /// - /// Gets the fixed-point rounding-bias lanes. - /// - public Vector512 RoundingBias { get; } - - /// - /// Gets the maximum eight-bit sample lanes. - /// - public Vector512 Maximum { get; } - - /// - /// Gets the red Cr coefficient lanes. - /// - public Vector512 RedCr { get; } - - /// - /// Gets the green Cb coefficient lanes. - /// - public Vector512 GreenCb { get; } - - /// - /// Gets the green Cr coefficient lanes. - /// - public Vector512 GreenCr { get; } - - /// - /// Gets the blue Cb coefficient lanes. - /// - public Vector512 BlueCb { get; } - } -} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.cs deleted file mode 100644 index ef81c90b4..000000000 --- a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Buffers; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.Metadata.Profiles.Cicp; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Formats.Heif.Components; - -/// -/// Converts full-range eight-bit HEIF 4:2:0 planes with an unspecified matrix to packed RGB pixels. -/// -internal static partial class HeifYuv420ToRgb8Converter -{ - /// - /// The fixed-point precision used for H.273 matrix coefficients. - /// - private const int CoefficientShift = 8; - - /// - /// The half-unit bias used before fixed-point coefficient results are shifted to integer samples. - /// - private const int RoundingBias = 1 << (CoefficientShift - 1); - - /// - /// The neutral code value for full-range eight-bit chroma. - /// - private const int ChromaMidpoint = 128; - - /// - /// Determines whether the specialized integer conversion supports the supplied plane and color description. - /// - /// The horizontal chroma subsampling shift. - /// The vertical chroma subsampling shift. - /// The luma sample precision in bits. - /// The chroma sample precision in bits. - /// Whether the samples use the complete numeric range. - /// The H.273 matrix-coefficient code point. - /// The resolved H.273 conversion operation. - /// when the planes can use this converter; otherwise, . - public static bool IsSupported( - int subsamplingX, - int subsamplingY, - int lumaBitDepth, - int chromaBitDepth, - bool isFullRange, - CicpMatrixCoefficients matrixCoefficients, - HeifColorConversionMode mode) - => subsamplingX == 1 - && subsamplingY == 1 - && lumaBitDepth == 8 - && chromaBitDepth == 8 - && isFullRange - && matrixCoefficients == CicpMatrixCoefficients.Unspecified - && mode == HeifColorConversionMode.Coefficients; - - /// - /// Converts supported HEIF component planes to packed pixels using integer SIMD with a scalar tail. - /// - /// The destination pixel type. - /// The codec adapter that exposes reconstructed component rows. - /// The configuration used for allocation and pixel conversion. - /// The reconstructed component-plane buffer. - /// The destination image frame. - /// The resolved H.273 conversion parameters. - /// The horizontal luma-sample offset of the output window. - /// The vertical luma-sample offset of the output window. - public static void Convert( - Configuration configuration, - TBuffer buffer, - ImageFrame image, - in HeifColorConversionParameters parameters, - int sourceX, - int sourceY) - where TPixel : unmanaged, IPixel - where TBuffer : struct, IHeifPlanarSampleBuffer - { - ConversionParameters conversionParameters = new(in parameters); - using IMemoryOwner componentOwner = configuration.MemoryAllocator.Allocate(image.Width * 3); - Span components = componentOwner.GetSpan(); - Span red = components[..image.Width]; - Span green = components.Slice(image.Width, image.Width); - Span blue = components.Slice(image.Width * 2, image.Width); - - // The value-type buffer closes the row-access contract at the call site. Constrained calls are therefore - // devirtualized without boxing while keeping codec-specific buffer ownership outside the color pipeline. - for (int y = 0; y < image.Height; y++) - { - int lumaY = sourceY + y; - - // The codec boundary validates 4:2:0 crop offsets in complete chroma-sample units. Each native chroma - // sample therefore covers one 2x2 luma cell without an alignment branch in the SIMD loop. - ReadOnlySpan luma = buffer.GetLumaRowSpan(lumaY).Slice(sourceX, image.Width); - ReadOnlySpan chromaBlue = buffer.GetChromaBlueRowSpan(lumaY >> 1).Slice(sourceX >> 1); - ReadOnlySpan chromaRed = buffer.GetChromaRedRowSpan(lumaY >> 1).Slice(sourceX >> 1); - - ConvertRow(luma, chromaBlue, chromaRed, red, green, blue, in conversionParameters); - - Span destination = image.PixelBuffer.DangerousGetRowSpan(y); - PixelOperations.Instance.PackFromRgbPlanes(red, green, blue, destination); - } - } -} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.LibheifCoefficientOperator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.LibheifCoefficientOperator.cs new file mode 100644 index 000000000..942aff347 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.LibheifCoefficientOperator.cs @@ -0,0 +1,151 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Provides pinned-libheif high-bit-depth coefficient conversion at the source RGB precision. +/// +internal static partial class HeifYuvToRgb16Converter +{ + /// + /// Implements pinned-libheif coefficient conversion for scalar and SIMD lanes. + /// + private readonly struct LibheifCoefficientOperator : IHeifYuvToRgb16Operator + { + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b) + { + Vector512Parameters values = parameters.SixteenLane; + Vector512 luma = (Vector512.ConvertToSingle(y) - values.LumaOffset) * values.LumaScale; + Vector512 blueDifference = (Vector512.ConvertToSingle(cb) - values.ChromaMidpoint) * values.ChromaScale; + Vector512 redDifference = (Vector512.ConvertToSingle(cr) - values.ChromaMidpoint) * values.ChromaScale; + Vector512 half = Vector512.Create(0.5F); + + // libheif evaluates these as distinct float32 multiplies and adds; FMA changes some 12-bit results by one. + Vector512 redValue = Vector512.Multiply(values.RedCr, redDifference); + redValue = Vector512.Add(luma, redValue); + Vector512 greenValue = Vector512.Multiply(values.GreenCb, blueDifference); + greenValue = Vector512.Add(luma, greenValue); + Vector512 greenRedValue = Vector512.Multiply(values.GreenCr, redDifference); + greenValue = Vector512.Add(greenValue, greenRedValue); + Vector512 blueValue = Vector512.Multiply(values.BlueCb, blueDifference); + blueValue = Vector512.Add(luma, blueValue); + Vector512 red = Vector512.ConvertToInt32(Vector512.Truncate(Vector512.Add(redValue, half))); + Vector512 green = Vector512.ConvertToInt32(Vector512.Truncate(Vector512.Add(greenValue, half))); + Vector512 blue = Vector512.ConvertToInt32(Vector512.Truncate(Vector512.Add(blueValue, half))); + + r = Vector512.Clamp(red, default, values.Maximum); + g = Vector512.Clamp(green, default, values.Maximum); + b = Vector512.Clamp(blue, default, values.Maximum); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector256 y, + Vector256 cb, + Vector256 cr, + in ConversionParameters parameters, + out Vector256 r, + out Vector256 g, + out Vector256 b) + { + Vector256Parameters values = parameters.EightLane; + Vector256 luma = (Vector256.ConvertToSingle(y) - values.LumaOffset) * values.LumaScale; + Vector256 blueDifference = (Vector256.ConvertToSingle(cb) - values.ChromaMidpoint) * values.ChromaScale; + Vector256 redDifference = (Vector256.ConvertToSingle(cr) - values.ChromaMidpoint) * values.ChromaScale; + Vector256 half = Vector256.Create(0.5F); + Vector256 redValue = Vector256.Multiply(values.RedCr, redDifference); + redValue = Vector256.Add(luma, redValue); + Vector256 greenValue = Vector256.Multiply(values.GreenCb, blueDifference); + greenValue = Vector256.Add(luma, greenValue); + Vector256 greenRedValue = Vector256.Multiply(values.GreenCr, redDifference); + greenValue = Vector256.Add(greenValue, greenRedValue); + Vector256 blueValue = Vector256.Multiply(values.BlueCb, blueDifference); + blueValue = Vector256.Add(luma, blueValue); + Vector256 red = Vector256.ConvertToInt32(Vector256.Truncate(Vector256.Add(redValue, half))); + Vector256 green = Vector256.ConvertToInt32(Vector256.Truncate(Vector256.Add(greenValue, half))); + Vector256 blue = Vector256.ConvertToInt32(Vector256.Truncate(Vector256.Add(blueValue, half))); + + r = Vector256.Clamp(red, default, values.Maximum); + g = Vector256.Clamp(green, default, values.Maximum); + b = Vector256.Clamp(blue, default, values.Maximum); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b) + { + Vector128Parameters values = parameters.FourLane; + Vector128 luma = (Vector128.ConvertToSingle(y) - values.LumaOffset) * values.LumaScale; + Vector128 blueDifference = (Vector128.ConvertToSingle(cb) - values.ChromaMidpoint) * values.ChromaScale; + Vector128 redDifference = (Vector128.ConvertToSingle(cr) - values.ChromaMidpoint) * values.ChromaScale; + Vector128 half = Vector128.Create(0.5F); + Vector128 redValue = Vector128.Multiply(values.RedCr, redDifference); + redValue = Vector128.Add(luma, redValue); + Vector128 greenValue = Vector128.Multiply(values.GreenCb, blueDifference); + greenValue = Vector128.Add(luma, greenValue); + Vector128 greenRedValue = Vector128.Multiply(values.GreenCr, redDifference); + greenValue = Vector128.Add(greenValue, greenRedValue); + Vector128 blueValue = Vector128.Multiply(values.BlueCb, blueDifference); + blueValue = Vector128.Add(luma, blueValue); + Vector128 red = Vector128.ConvertToInt32(Vector128.Truncate(Vector128.Add(redValue, half))); + Vector128 green = Vector128.ConvertToInt32(Vector128.Truncate(Vector128.Add(greenValue, half))); + Vector128 blue = Vector128.ConvertToInt32(Vector128.Truncate(Vector128.Add(blueValue, half))); + + r = Vector128.Clamp(red, default, values.Maximum); + g = Vector128.Clamp(green, default, values.Maximum); + b = Vector128.Clamp(blue, default, values.Maximum); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + ushort y, + ushort cb, + ushort cr, + in ConversionParameters parameters, + out int r, + out int g, + out int b) + { + ScalarParameters values = parameters.Scalar; + float luma = (y - values.LumaOffset) * values.LumaScale; + float blueDifference = (cb - values.ChromaMidpoint) * values.ChromaScale; + float redDifference = (cr - values.ChromaMidpoint) * values.ChromaScale; + + // Keep each assignment separate so the JIT cannot fuse the reference float32 operations. + float redValue = values.RedCr * redDifference; + redValue = luma + redValue; + float greenValue = values.GreenCb * blueDifference; + greenValue = luma + greenValue; + float greenRedValue = values.GreenCr * redDifference; + greenValue += greenRedValue; + float blueValue = values.BlueCb * blueDifference; + blueValue = luma + blueValue; + + r = Numerics.Clamp((int)(redValue + 0.5F), 0, values.Maximum); + g = Numerics.Clamp((int)(greenValue + 0.5F), 0, values.Maximum); + b = Numerics.Clamp((int)(blueValue + 0.5F), 0, values.Maximum); + } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.LibheifMonochromeOperator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.LibheifMonochromeOperator.cs new file mode 100644 index 000000000..06cf40bd1 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.LibheifMonochromeOperator.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Provides pinned-libheif high-bit-depth monochrome presentation without luma-range expansion. +/// +internal static partial class HeifYuvToRgb16Converter +{ + /// + /// Copies source-precision luma into each source-precision RGB component. + /// + private readonly struct LibheifMonochromeOperator : IHeifYuvToRgb16Operator + { + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b) + { + r = y; + g = y; + b = y; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector256 y, + Vector256 cb, + Vector256 cr, + in ConversionParameters parameters, + out Vector256 r, + out Vector256 g, + out Vector256 b) + { + r = y; + g = y; + b = y; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b) + { + r = y; + g = y; + b = y; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + ushort y, + ushort cb, + ushort cr, + in ConversionParameters parameters, + out int r, + out int g, + out int b) + { + r = y; + g = y; + b = y; + } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.Operator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.Operator.cs new file mode 100644 index 000000000..8715f5fff --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.Operator.cs @@ -0,0 +1,293 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.Common.Helpers; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Defines closed high-bit-depth color operators and nearest-sample row traversal. +/// +internal static partial class HeifYuvToRgb16Converter +{ + /// + /// Defines source-precision RGB arithmetic for scalar and SIMD lanes. + /// + private interface IHeifYuvToRgb16Operator + { + /// + /// Converts sixteen YCbCr samples to source-precision RGB lanes. + /// + /// The luma lanes. + /// The blue-difference lanes. + /// The red-difference lanes. + /// The image conversion parameters. + /// The converted red lanes. + /// The converted green lanes. + /// The converted blue lanes. + public static abstract void Convert( + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b); + + /// + /// Converts eight YCbCr samples to source-precision RGB lanes. + /// + /// The luma lanes. + /// The blue-difference lanes. + /// The red-difference lanes. + /// The image conversion parameters. + /// The converted red lanes. + /// The converted green lanes. + /// The converted blue lanes. + public static abstract void Convert( + Vector256 y, + Vector256 cb, + Vector256 cr, + in ConversionParameters parameters, + out Vector256 r, + out Vector256 g, + out Vector256 b); + + /// + /// Converts four YCbCr samples to source-precision RGB lanes. + /// + /// The luma lanes. + /// The blue-difference lanes. + /// The red-difference lanes. + /// The image conversion parameters. + /// The converted red lanes. + /// The converted green lanes. + /// The converted blue lanes. + public static abstract void Convert( + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b); + + /// + /// Converts one YCbCr sample to source-precision RGB. + /// + /// The luma sample. + /// The blue-difference sample. + /// The red-difference sample. + /// The image conversion parameters. + /// The converted red sample. + /// The converted green sample. + /// The converted blue sample. + public static abstract void Convert( + ushort y, + ushort cb, + ushort cr, + in ConversionParameters parameters, + out int r, + out int g, + out int b); + } + + /// + /// Converts one luma row and its nearest native chroma row to planar 16-bit RGB storage. + /// + /// The source-precision color arithmetic selected for the row. + /// The full-resolution luma samples. + /// The native blue-difference samples. + /// The native red-difference samples. + /// The destination red samples. + /// The destination green samples. + /// The destination blue samples. + /// The horizontal chroma subsampling shift. + /// The image conversion parameters. + private static void ConvertRow( + ReadOnlySpan luma, + ReadOnlySpan chromaBlue, + ReadOnlySpan chromaRed, + Span red, + Span green, + Span blue, + int subsamplingX, + in ConversionParameters parameters) + where TOperator : struct, IHeifYuvToRgb16Operator + { + ref ushort lumaBase = ref MemoryMarshal.GetReference(luma); + ref ushort chromaBlueBase = ref MemoryMarshal.GetReference(chromaBlue); + ref ushort chromaRedBase = ref MemoryMarshal.GetReference(chromaRed); + ref ushort redBase = ref MemoryMarshal.GetReference(red); + ref ushort greenBase = ref MemoryMarshal.GetReference(green); + ref ushort blueBase = ref MemoryMarshal.GetReference(blue); + int outputLeftShift = parameters.Scalar.OutputLeftShift; + int x = 0; + + // Each operator produces code values at the source precision. The traversal then left-aligns those values in + // UInt16 storage, matching libheif's high-bit-depth RGB output without discarding low source bits. + if (Vector512.IsHardwareAccelerated) + { + int oneVectorFromEnd = luma.Length - Vector512.Count; + + for (; x <= oneVectorFromEnd; x += Vector512.Count) + { + Vector512 y = LoadVector512(ref Unsafe.Add(ref lumaBase, x)); + Vector512 cb = subsamplingX == 0 + ? LoadVector512(ref Unsafe.Add(ref chromaBlueBase, x)) + : LoadRepeatedVector512(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); + + Vector512 cr = subsamplingX == 0 + ? LoadVector512(ref Unsafe.Add(ref chromaRedBase, x)) + : LoadRepeatedVector512(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + + TOperator.Convert(y, cb, cr, in parameters, out Vector512 r, out Vector512 g, out Vector512 b); + HeifUShortSampleConverter.Store(r << outputLeftShift, ref Unsafe.Add(ref redBase, x)); + HeifUShortSampleConverter.Store(g << outputLeftShift, ref Unsafe.Add(ref greenBase, x)); + HeifUShortSampleConverter.Store(b << outputLeftShift, ref Unsafe.Add(ref blueBase, x)); + } + } + + if (Vector256.IsHardwareAccelerated) + { + int oneVectorFromEnd = luma.Length - Vector256.Count; + + for (; x <= oneVectorFromEnd; x += Vector256.Count) + { + Vector256 y = LoadVector256(ref Unsafe.Add(ref lumaBase, x)); + Vector256 cb = subsamplingX == 0 + ? LoadVector256(ref Unsafe.Add(ref chromaBlueBase, x)) + : LoadRepeatedVector256(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); + + Vector256 cr = subsamplingX == 0 + ? LoadVector256(ref Unsafe.Add(ref chromaRedBase, x)) + : LoadRepeatedVector256(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + + TOperator.Convert(y, cb, cr, in parameters, out Vector256 r, out Vector256 g, out Vector256 b); + HeifUShortSampleConverter.Store(r << outputLeftShift, ref Unsafe.Add(ref redBase, x)); + HeifUShortSampleConverter.Store(g << outputLeftShift, ref Unsafe.Add(ref greenBase, x)); + HeifUShortSampleConverter.Store(b << outputLeftShift, ref Unsafe.Add(ref blueBase, x)); + } + } + + if (Vector128.IsHardwareAccelerated) + { + int oneVectorFromEnd = luma.Length - Vector128.Count; + + for (; x <= oneVectorFromEnd; x += Vector128.Count) + { + Vector128 y = LoadVector128(ref Unsafe.Add(ref lumaBase, x)); + Vector128 cb = subsamplingX == 0 + ? LoadVector128(ref Unsafe.Add(ref chromaBlueBase, x)) + : LoadRepeatedVector128(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); + + Vector128 cr = subsamplingX == 0 + ? LoadVector128(ref Unsafe.Add(ref chromaRedBase, x)) + : LoadRepeatedVector128(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + + TOperator.Convert(y, cb, cr, in parameters, out Vector128 r, out Vector128 g, out Vector128 b); + HeifUShortSampleConverter.Store(r << outputLeftShift, ref Unsafe.Add(ref redBase, x)); + HeifUShortSampleConverter.Store(g << outputLeftShift, ref Unsafe.Add(ref greenBase, x)); + HeifUShortSampleConverter.Store(b << outputLeftShift, ref Unsafe.Add(ref blueBase, x)); + } + } + + for (; x < luma.Length; x++) + { + TOperator.Convert( + Unsafe.Add(ref lumaBase, x), + Unsafe.Add(ref chromaBlueBase, x >> subsamplingX), + Unsafe.Add(ref chromaRedBase, x >> subsamplingX), + in parameters, + out int r, + out int g, + out int b); + + Unsafe.Add(ref redBase, x) = (ushort)(r << outputLeftShift); + Unsafe.Add(ref greenBase, x) = (ushort)(g << outputLeftShift); + Unsafe.Add(ref blueBase, x) = (ushort)(b << outputLeftShift); + } + } + + /// + /// Loads sixteen native samples as signed 32-bit SIMD lanes. + /// + /// The first native sample. + /// The widened sample lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector512 LoadVector512(ref ushort source) + { + (Vector256 lower, Vector256 upper) = Vector256.Widen(Vector256.LoadUnsafe(ref source)); + return Vector512.Create(lower, upper).AsInt32(); + } + + /// + /// Loads eight native samples as signed 32-bit SIMD lanes. + /// + /// The first native sample. + /// The widened sample lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 LoadVector256(ref ushort source) + { + Vector128 samples = Vector128.LoadUnsafe(ref source); + return Vector256.Create(Vector128.WidenLower(samples), Vector128.WidenUpper(samples)).AsInt32(); + } + + /// + /// Loads four native samples as signed 32-bit SIMD lanes. + /// + /// The first native sample. + /// The widened sample lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 LoadVector128(ref ushort source) + { + ulong packed = Unsafe.ReadUnaligned(ref Unsafe.As(ref source)); + return Vector128.WidenLower(Vector128.CreateScalarUnsafe(packed).AsUInt16()).AsInt32(); + } + + /// + /// Loads eight chroma samples and repeats each sample into two of sixteen 32-bit SIMD lanes. + /// + /// The first native chroma sample. + /// The horizontally replicated chroma lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector512 LoadRepeatedVector512(ref ushort source) + { + Vector128 samples = Vector128.LoadUnsafe(ref source); + Vector128 lower = Vector128_.UnpackLow(samples.AsInt16(), samples.AsInt16()).AsUInt16(); + Vector128 upper = Vector128_.UnpackHigh(samples.AsInt16(), samples.AsInt16()).AsUInt16(); + (Vector256 widenedLower, Vector256 widenedUpper) = Vector256.Widen(Vector256.Create(lower, upper)); + return Vector512.Create(widenedLower, widenedUpper).AsInt32(); + } + + /// + /// Loads four chroma samples and repeats each sample into two of eight 32-bit SIMD lanes. + /// + /// The first native chroma sample. + /// The horizontally replicated chroma lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 LoadRepeatedVector256(ref ushort source) + { + ulong packed = Unsafe.ReadUnaligned(ref Unsafe.As(ref source)); + Vector128 samples = Vector128.CreateScalarUnsafe(packed).AsUInt16(); + Vector128 repeated = Vector128_.UnpackLow(samples.AsInt16(), samples.AsInt16()).AsUInt16(); + return Vector256.Create(Vector128.WidenLower(repeated), Vector128.WidenUpper(repeated)).AsInt32(); + } + + /// + /// Loads two chroma samples and repeats each sample into two of four 32-bit SIMD lanes. + /// + /// The first native chroma sample. + /// The horizontally replicated chroma lanes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 LoadRepeatedVector128(ref ushort source) + { + uint packed = Unsafe.ReadUnaligned(ref Unsafe.As(ref source)); + Vector128 samples = Vector128.CreateScalarUnsafe(packed).AsUInt16(); + Vector128 repeated = Vector128_.UnpackLow(samples.AsInt16(), samples.AsInt16()).AsUInt16(); + return Vector128.WidenLower(repeated).AsInt32(); + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.Parameters.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.Parameters.cs new file mode 100644 index 000000000..b7cbbd770 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.Parameters.cs @@ -0,0 +1,347 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Provides scalar and SIMD parameter storage for high-bit-depth pinned-libheif conversion. +/// +internal static partial class HeifYuvToRgb16Converter +{ + /// + /// Stores every scalar and SIMD coefficient representation resolved once for an image. + /// + private readonly struct ConversionParameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The resolved H.273 matrix and range values. + /// The common source component precision. + public ConversionParameters(in HeifColorConversionParameters parameters, int bitDepth) + { + ScalarParameters scalar = new(in parameters, bitDepth); + this.Scalar = scalar; + this.SixteenLane = new(in scalar); + this.EightLane = new(in scalar); + this.FourLane = new(in scalar); + } + + /// + /// Gets the scalar conversion parameters. + /// + public ScalarParameters Scalar { get; } + + /// + /// Gets the sixteen-lane conversion parameters. + /// + public Vector512Parameters SixteenLane { get; } + + /// + /// Gets the eight-lane conversion parameters. + /// + public Vector256Parameters EightLane { get; } + + /// + /// Gets the four-lane conversion parameters. + /// + public Vector128Parameters FourLane { get; } + } + + /// + /// Stores the scalar arithmetic and output scaling used by pinned libheif. + /// + private readonly struct ScalarParameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The resolved H.273 matrix and range values. + /// The common source component precision. + public ScalarParameters(in HeifColorConversionParameters parameters, int bitDepth) + { + this.LumaOffset = parameters.IsFullRange ? 0F : parameters.LumaBias; + this.LumaScale = parameters.IsFullRange ? 1F : 1.1689F; + this.ChromaMidpoint = parameters.ChromaBias; + this.ChromaScale = parameters.IsFullRange ? 1F : 1.1429F; + if (parameters.MatrixCoefficients == CicpMatrixCoefficients.Unspecified) + { + // libheif falls back to these literal Rec.601 coefficients when no matrix is signaled. Deriving them + // from Kr and Kb produces different float32 values and can move high-bit-depth green by one code value. + this.RedCr = 1.402F; + this.GreenCb = -0.344136F; + this.GreenCr = -0.714136F; + this.BlueCb = 1.772F; + } + else + { + float kr = parameters.Kr; + float kb = parameters.Kb; + this.RedCr = 2F * (-kr + 1F); + this.GreenCb = 2F * kb * (-kb + 1F) / (kb + kr - 1F); + this.GreenCr = 2F * kr * (-kr + 1F) / (kb + kr - 1F); + this.BlueCb = 2F * (-kb + 1F); + } + + this.Maximum = (1 << bitDepth) - 1; + this.OutputLeftShift = 16 - bitDepth; + } + + /// + /// Gets the luma code-value offset removed before limited-range expansion. + /// + public float LumaOffset { get; } + + /// + /// Gets the luma range-expansion factor. + /// + public float LumaScale { get; } + + /// + /// Gets the neutral chroma code value. + /// + public float ChromaMidpoint { get; } + + /// + /// Gets the chroma range-expansion factor. + /// + public float ChromaScale { get; } + + /// + /// Gets the red contribution from Cr. + /// + public float RedCr { get; } + + /// + /// Gets the green contribution from Cb. + /// + public float GreenCb { get; } + + /// + /// Gets the green contribution from Cr. + /// + public float GreenCr { get; } + + /// + /// Gets the blue contribution from Cb. + /// + public float BlueCb { get; } + + /// + /// Gets the largest source-precision RGB code value. + /// + public int Maximum { get; } + + /// + /// Gets the left shift mapping source-precision RGB into 16-bit pixel storage. + /// + public int OutputLeftShift { get; } + } + + /// + /// Broadcasts pinned-libheif coefficients for sixteen-lane conversion. + /// + private readonly struct Vector512Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar pinned-libheif coefficients. + public Vector512Parameters(in ScalarParameters parameters) + { + this.LumaOffset = Vector512.Create(parameters.LumaOffset); + this.LumaScale = Vector512.Create(parameters.LumaScale); + this.ChromaMidpoint = Vector512.Create(parameters.ChromaMidpoint); + this.ChromaScale = Vector512.Create(parameters.ChromaScale); + this.RedCr = Vector512.Create(parameters.RedCr); + this.GreenCb = Vector512.Create(parameters.GreenCb); + this.GreenCr = Vector512.Create(parameters.GreenCr); + this.BlueCb = Vector512.Create(parameters.BlueCb); + this.Maximum = Vector512.Create(parameters.Maximum); + } + + /// + /// Gets the luma offset lanes. + /// + public Vector512 LumaOffset { get; } + + /// + /// Gets the luma scale lanes. + /// + public Vector512 LumaScale { get; } + + /// + /// Gets the chroma-midpoint lanes. + /// + public Vector512 ChromaMidpoint { get; } + + /// + /// Gets the chroma-scale lanes. + /// + public Vector512 ChromaScale { get; } + + /// + /// Gets the red Cr coefficient lanes. + /// + public Vector512 RedCr { get; } + + /// + /// Gets the green Cb coefficient lanes. + /// + public Vector512 GreenCb { get; } + + /// + /// Gets the green Cr coefficient lanes. + /// + public Vector512 GreenCr { get; } + + /// + /// Gets the blue Cb coefficient lanes. + /// + public Vector512 BlueCb { get; } + + /// + /// Gets the maximum source-precision RGB lanes. + /// + public Vector512 Maximum { get; } + } + + /// + /// Broadcasts pinned-libheif coefficients for eight-lane conversion. + /// + private readonly struct Vector256Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar pinned-libheif coefficients. + public Vector256Parameters(in ScalarParameters parameters) + { + this.LumaOffset = Vector256.Create(parameters.LumaOffset); + this.LumaScale = Vector256.Create(parameters.LumaScale); + this.ChromaMidpoint = Vector256.Create(parameters.ChromaMidpoint); + this.ChromaScale = Vector256.Create(parameters.ChromaScale); + this.RedCr = Vector256.Create(parameters.RedCr); + this.GreenCb = Vector256.Create(parameters.GreenCb); + this.GreenCr = Vector256.Create(parameters.GreenCr); + this.BlueCb = Vector256.Create(parameters.BlueCb); + this.Maximum = Vector256.Create(parameters.Maximum); + } + + /// + /// Gets the luma offset lanes. + /// + public Vector256 LumaOffset { get; } + + /// + /// Gets the luma scale lanes. + /// + public Vector256 LumaScale { get; } + + /// + /// Gets the chroma-midpoint lanes. + /// + public Vector256 ChromaMidpoint { get; } + + /// + /// Gets the chroma-scale lanes. + /// + public Vector256 ChromaScale { get; } + + /// + /// Gets the red Cr coefficient lanes. + /// + public Vector256 RedCr { get; } + + /// + /// Gets the green Cb coefficient lanes. + /// + public Vector256 GreenCb { get; } + + /// + /// Gets the green Cr coefficient lanes. + /// + public Vector256 GreenCr { get; } + + /// + /// Gets the blue Cb coefficient lanes. + /// + public Vector256 BlueCb { get; } + + /// + /// Gets the maximum source-precision RGB lanes. + /// + public Vector256 Maximum { get; } + } + + /// + /// Broadcasts pinned-libheif coefficients for four-lane conversion. + /// + private readonly struct Vector128Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar pinned-libheif coefficients. + public Vector128Parameters(in ScalarParameters parameters) + { + this.LumaOffset = Vector128.Create(parameters.LumaOffset); + this.LumaScale = Vector128.Create(parameters.LumaScale); + this.ChromaMidpoint = Vector128.Create(parameters.ChromaMidpoint); + this.ChromaScale = Vector128.Create(parameters.ChromaScale); + this.RedCr = Vector128.Create(parameters.RedCr); + this.GreenCb = Vector128.Create(parameters.GreenCb); + this.GreenCr = Vector128.Create(parameters.GreenCr); + this.BlueCb = Vector128.Create(parameters.BlueCb); + this.Maximum = Vector128.Create(parameters.Maximum); + } + + /// + /// Gets the luma offset lanes. + /// + public Vector128 LumaOffset { get; } + + /// + /// Gets the luma scale lanes. + /// + public Vector128 LumaScale { get; } + + /// + /// Gets the chroma-midpoint lanes. + /// + public Vector128 ChromaMidpoint { get; } + + /// + /// Gets the chroma-scale lanes. + /// + public Vector128 ChromaScale { get; } + + /// + /// Gets the red Cr coefficient lanes. + /// + public Vector128 RedCr { get; } + + /// + /// Gets the green Cb coefficient lanes. + /// + public Vector128 GreenCb { get; } + + /// + /// Gets the green Cr coefficient lanes. + /// + public Vector128 GreenCr { get; } + + /// + /// Gets the blue Cb coefficient lanes. + /// + public Vector128 BlueCb { get; } + + /// + /// Gets the maximum source-precision RGB lanes. + /// + public Vector128 Maximum { get; } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.cs new file mode 100644 index 000000000..127a8ada0 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb16Converter.cs @@ -0,0 +1,114 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Converts high-bit-depth HEIF YUV planes to packed pixels through opaque 16-bit RGB. +/// +internal static partial class HeifYuvToRgb16Converter +{ + /// + /// Determines whether the pinned libheif-compatible high-bit-depth conversion supports the supplied planes. + /// + /// The horizontal chroma subsampling shift. + /// The vertical chroma subsampling shift. + /// The luma sample precision in bits. + /// The chroma sample precision in bits. + /// Whether the image contains only luma samples. + /// The resolved H.273 conversion operation. + /// when the planes can use this converter; otherwise, . + public static bool SupportsLibheifConversion( + int subsamplingX, + int subsamplingY, + int lumaBitDepth, + int chromaBitDepth, + bool isMonochrome, + HeifColorConversionMode mode) + => (isMonochrome || (subsamplingX is 0 or 1 && subsamplingY is 0 or 1)) + && lumaBitDepth is > 8 and <= 16 + && (isMonochrome || chromaBitDepth == lumaBitDepth) + && mode == HeifColorConversionMode.Coefficients; + + /// + /// Converts supported high-bit-depth HEVC planes using pinned libheif arithmetic and nearest chroma sampling. + /// + /// The destination pixel type. + /// The codec adapter that exposes reconstructed component rows. + /// The configuration used for allocation and pixel conversion. + /// The reconstructed component-plane buffer. + /// The destination image frame. + /// The resolved H.273 conversion parameters. + /// The horizontal luma-sample offset of the output window. + /// The vertical luma-sample offset of the output window. + public static void Convert( + Configuration configuration, + TBuffer buffer, + ImageFrame image, + in HeifColorConversionParameters parameters, + int sourceX, + int sourceY) + where TPixel : unmanaged, IPixel + where TBuffer : struct, IHeifPlanarSampleBuffer + { + ConversionParameters conversionParameters = new(in parameters, buffer.LumaBitDepth); + + // Three planar rows and one packed Rgba64 row share a single image-lifetime allocation. The latter occupies + // four UInt16 values per pixel, so the complete scratch requirement is seven samples per output pixel. + using IMemoryOwner rowOwner = configuration.MemoryAllocator.Allocate(image.Width * 7); + Span storage = rowOwner.GetSpan(); + Span red = storage[..image.Width]; + Span green = storage.Slice(image.Width, image.Width); + Span blue = storage.Slice(image.Width * 2, image.Width); + Span packed = MemoryMarshal.Cast(storage[(image.Width * 3)..]); + + for (int y = 0; y < image.Height; y++) + { + int lumaY = sourceY + y; + ReadOnlySpan luma = buffer.GetLumaRowSpan(lumaY).Slice(sourceX, image.Width); + if (buffer.IsMonochrome) + { + // Pinned libheif copies the reconstructed luma code value directly to RGB for monochrome images. + // Scaling to the 16-bit pixel domain happens after that copy, without limited-range expansion. + ConvertRow( + luma, + luma, + luma, + red, + green, + blue, + 0, + in conversionParameters); + } + else + { + int subsamplingX = buffer.ChromaSubsamplingX; + int chromaY = lumaY >> buffer.ChromaSubsamplingY; + ReadOnlySpan chromaBlue = buffer.GetChromaBlueRowSpan(chromaY).Slice(sourceX >> subsamplingX); + ReadOnlySpan chromaRed = buffer.GetChromaRedRowSpan(chromaY).Slice(sourceX >> subsamplingX); + + // libheif's selected direct conversion addresses the native chroma sample at x >> subsamplingX. + // The HEIF crop boundary already keeps sourceX aligned to complete chroma samples. + ConvertRow( + luma, + chromaBlue, + chromaRed, + red, + green, + blue, + subsamplingX, + in conversionParameters); + } + + HeifSampleConversion.PackRgba64(red, green, blue, packed); + Span destination = image.PixelBuffer.DangerousGetRowSpan(y); + PixelOperations.Instance.FromRgba64(configuration, packed, destination); + } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.CoefficientOperator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.FixedPointCoefficientOperator.cs similarity index 50% rename from src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.CoefficientOperator.cs rename to src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.FixedPointCoefficientOperator.cs index 7945220be..82b6b7d8f 100644 --- a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.CoefficientOperator.cs +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.FixedPointCoefficientOperator.cs @@ -11,47 +11,30 @@ namespace SixLabors.ImageSharp.Formats.Heif.Components; /// chroma sample. Matrix coefficients use a common fixed-point scale; every component rounds once after its complete /// weighted sum, then clips before the enclosing row kernel narrows and packs the RGB result. /// -internal static partial class HeifYuv420ToRgb8Converter +internal static partial class HeifYuvToRgb8Converter { /// /// Implements full-range coefficient-based YCbCr conversion for scalar and SIMD lanes. /// - private readonly struct FixedPointCoefficientOperator : IHeifYuv420ToRgb8Operator + private readonly struct FixedPointCoefficientOperator : IHeifYuvToRgb8Operator { - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Convert(ushort y, ushort cb, ushort cr, in FixedPointParameters parameters, out byte r, out byte g, out byte b) - { - int centeredBlue = cb - ChromaMidpoint; - int centeredRed = cr - ChromaMidpoint; - - // All overloads preserve this term grouping and round once after the complete contribution for a - // component has been accumulated, so vector width cannot change an output code value. - int red = y + (((parameters.RedCr * centeredRed) + RoundingBias) >> CoefficientShift); - int green = y + (((parameters.GreenCb * centeredBlue) + (parameters.GreenCr * centeredRed) + RoundingBias) >> CoefficientShift); - int blue = y + (((parameters.BlueCb * centeredBlue) + RoundingBias) >> CoefficientShift); - - r = (byte)Numerics.Clamp(red, 0, byte.MaxValue); - g = (byte)Numerics.Clamp(green, 0, byte.MaxValue); - b = (byte)Numerics.Clamp(blue, 0, byte.MaxValue); - } - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert( - Vector128 y, - Vector128 cb, - Vector128 cr, - in Vector128Parameters parameters, - out Vector128 r, - out Vector128 g, - out Vector128 b) + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b) { - cb -= parameters.ChromaMidpoint; - cr -= parameters.ChromaMidpoint; - r = Vector128.Clamp(y + (((parameters.RedCr * cr) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); - g = Vector128.Clamp(y + (((parameters.GreenCb * cb) + (parameters.GreenCr * cr) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); - b = Vector128.Clamp(y + (((parameters.BlueCb * cb) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); + Vector512Parameters fixedPoint = parameters.FixedPointSixteenLane; + cb -= fixedPoint.ChromaMidpoint; + cr -= fixedPoint.ChromaMidpoint; + r = Vector512.Clamp(y + (((fixedPoint.RedCr * cr) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + g = Vector512.Clamp(y + (((fixedPoint.GreenCb * cb) + (fixedPoint.GreenCr * cr) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + b = Vector512.Clamp(y + (((fixedPoint.BlueCb * cb) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); } /// @@ -60,34 +43,55 @@ internal static partial class HeifYuv420ToRgb8Converter Vector256 y, Vector256 cb, Vector256 cr, - in Vector256Parameters parameters, + in ConversionParameters parameters, out Vector256 r, out Vector256 g, out Vector256 b) { - cb -= parameters.ChromaMidpoint; - cr -= parameters.ChromaMidpoint; - r = Vector256.Clamp(y + (((parameters.RedCr * cr) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); - g = Vector256.Clamp(y + (((parameters.GreenCb * cb) + (parameters.GreenCr * cr) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); - b = Vector256.Clamp(y + (((parameters.BlueCb * cb) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); + Vector256Parameters fixedPoint = parameters.FixedPointEightLane; + cb -= fixedPoint.ChromaMidpoint; + cr -= fixedPoint.ChromaMidpoint; + r = Vector256.Clamp(y + (((fixedPoint.RedCr * cr) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + g = Vector256.Clamp(y + (((fixedPoint.GreenCb * cb) + (fixedPoint.GreenCr * cr) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + b = Vector256.Clamp(y + (((fixedPoint.BlueCb * cb) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert( - Vector512 y, - Vector512 cb, - Vector512 cr, - in Vector512Parameters parameters, - out Vector512 r, - out Vector512 g, - out Vector512 b) + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b) + { + Vector128Parameters fixedPoint = parameters.FixedPointFourLane; + cb -= fixedPoint.ChromaMidpoint; + cr -= fixedPoint.ChromaMidpoint; + r = Vector128.Clamp(y + (((fixedPoint.RedCr * cr) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + g = Vector128.Clamp(y + (((fixedPoint.GreenCb * cb) + (fixedPoint.GreenCr * cr) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + b = Vector128.Clamp(y + (((fixedPoint.BlueCb * cb) + fixedPoint.RoundingBias) >> CoefficientShift), default, fixedPoint.Maximum); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert(ushort y, ushort cb, ushort cr, in ConversionParameters parameters, out byte r, out byte g, out byte b) { - cb -= parameters.ChromaMidpoint; - cr -= parameters.ChromaMidpoint; - r = Vector512.Clamp(y + (((parameters.RedCr * cr) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); - g = Vector512.Clamp(y + (((parameters.GreenCb * cb) + (parameters.GreenCr * cr) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); - b = Vector512.Clamp(y + (((parameters.BlueCb * cb) + parameters.RoundingBias) >> CoefficientShift), default, parameters.Maximum); + FixedPointParameters fixedPoint = parameters.FixedPointScalar; + int centeredBlue = cb - ChromaMidpoint; + int centeredRed = cr - ChromaMidpoint; + + // All overloads preserve this term grouping and round once after the complete contribution for a + // component has been accumulated, so vector width cannot change an output code value. + int red = y + (((fixedPoint.RedCr * centeredRed) + RoundingBias) >> CoefficientShift); + int green = y + (((fixedPoint.GreenCb * centeredBlue) + (fixedPoint.GreenCr * centeredRed) + RoundingBias) >> CoefficientShift); + int blue = y + (((fixedPoint.BlueCb * centeredBlue) + RoundingBias) >> CoefficientShift); + + r = (byte)Numerics.Clamp(red, 0, byte.MaxValue); + g = (byte)Numerics.Clamp(green, 0, byte.MaxValue); + b = (byte)Numerics.Clamp(blue, 0, byte.MaxValue); } } } diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.LibheifCoefficientOperator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.LibheifCoefficientOperator.cs new file mode 100644 index 000000000..f7946a5c3 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.LibheifCoefficientOperator.cs @@ -0,0 +1,125 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Provides the coefficient conversion executed by pinned libheif 1.23.1. Each SIMD lane carries one output pixel. +/// Range expansion and matrix arithmetic remain in single precision, RGB is rounded and clipped at the coded +/// precision, and the final integer shift reproduces libheif's separate high-bit-depth-to-eight-bit operation. +/// +internal static partial class HeifYuvToRgb8Converter +{ + /// + /// Implements pinned-libheif coefficient conversion for scalar and SIMD lanes. + /// + private readonly struct LibheifCoefficientOperator : IHeifYuvToRgb8Operator + { + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b) + { + LibheifVector512Parameters values = parameters.LibheifSixteenLane; + Vector512 luma = (Vector512.ConvertToSingle(y) - values.LumaOffset) * values.LumaScale; + Vector512 blueDifference = (Vector512.ConvertToSingle(cb) - values.ChromaMidpoint) * values.ChromaScale; + Vector512 redDifference = (Vector512.ConvertToSingle(cr) - values.ChromaMidpoint) * values.ChromaScale; + Vector512 half = Vector512.Create(0.5F); + + // Sixteen independent samples use the same float32 ordering as the narrower paths. The closed operator + // keeps this compatibility arithmetic outside the row dispatch while allowing an exact scalar fallback. + Vector512 red = Vector512.ConvertToInt32(Vector512.Truncate(luma + (values.RedCr * redDifference) + half)); + Vector512 green = Vector512.ConvertToInt32(Vector512.Truncate(luma + (values.GreenCb * blueDifference) + (values.GreenCr * redDifference) + half)); + Vector512 blue = Vector512.ConvertToInt32(Vector512.Truncate(luma + (values.BlueCb * blueDifference) + half)); + + r = Vector512.Clamp(red, default, values.Maximum) >> values.OutputShift; + g = Vector512.Clamp(green, default, values.Maximum) >> values.OutputShift; + b = Vector512.Clamp(blue, default, values.Maximum) >> values.OutputShift; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector256 y, + Vector256 cb, + Vector256 cr, + in ConversionParameters parameters, + out Vector256 r, + out Vector256 g, + out Vector256 b) + { + LibheifVector256Parameters values = parameters.LibheifEightLane; + Vector256 luma = (Vector256.ConvertToSingle(y) - values.LumaOffset) * values.LumaScale; + Vector256 blueDifference = (Vector256.ConvertToSingle(cb) - values.ChromaMidpoint) * values.ChromaScale; + Vector256 redDifference = (Vector256.ConvertToSingle(cr) - values.ChromaMidpoint) * values.ChromaScale; + Vector256 half = Vector256.Create(0.5F); + + // Eight YUV tuples remain planar across the YMM arithmetic. The expression association matches the + // pinned scalar source, including the two successive green additions before truncation. + Vector256 red = Vector256.ConvertToInt32(Vector256.Truncate(luma + (values.RedCr * redDifference) + half)); + Vector256 green = Vector256.ConvertToInt32(Vector256.Truncate(luma + (values.GreenCb * blueDifference) + (values.GreenCr * redDifference) + half)); + Vector256 blue = Vector256.ConvertToInt32(Vector256.Truncate(luma + (values.BlueCb * blueDifference) + half)); + + r = Vector256.Clamp(red, default, values.Maximum) >> values.OutputShift; + g = Vector256.Clamp(green, default, values.Maximum) >> values.OutputShift; + b = Vector256.Clamp(blue, default, values.Maximum) >> values.OutputShift; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b) + { + LibheifVector128Parameters values = parameters.LibheifFourLane; + Vector128 luma = (Vector128.ConvertToSingle(y) - values.LumaOffset) * values.LumaScale; + Vector128 blueDifference = (Vector128.ConvertToSingle(cb) - values.ChromaMidpoint) * values.ChromaScale; + Vector128 redDifference = (Vector128.ConvertToSingle(cr) - values.ChromaMidpoint) * values.ChromaScale; + Vector128 half = Vector128.Create(0.5F); + + // Truncate after the explicit half-unit bias to mirror C++ float-to-int conversion. Clipping in integer + // lanes then preserves the source-precision boundary before the common eight-bit reduction shift. + Vector128 red = Vector128.ConvertToInt32(Vector128.Truncate(luma + (values.RedCr * redDifference) + half)); + Vector128 green = Vector128.ConvertToInt32(Vector128.Truncate(luma + (values.GreenCb * blueDifference) + (values.GreenCr * redDifference) + half)); + Vector128 blue = Vector128.ConvertToInt32(Vector128.Truncate(luma + (values.BlueCb * blueDifference) + half)); + + r = Vector128.Clamp(red, default, values.Maximum) >> values.OutputShift; + g = Vector128.Clamp(green, default, values.Maximum) >> values.OutputShift; + b = Vector128.Clamp(blue, default, values.Maximum) >> values.OutputShift; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert(ushort y, ushort cb, ushort cr, in ConversionParameters parameters, out byte r, out byte g, out byte b) + { + LibheifParameters values = parameters.LibheifScalar; + float luma = (y - values.LumaOffset) * values.LumaScale; + float blueDifference = (cb - values.ChromaMidpoint) * values.ChromaScale; + float redDifference = (cr - values.ChromaMidpoint) * values.ChromaScale; + + // libheif's clip_f_u16 adds one half, truncates toward zero, and then clips. RGB is rounded before + // the high-bit-depth plane is reduced, so moving the shift into the floating-point scale changes bytes. + int red = (int)(luma + (values.RedCr * redDifference) + 0.5F); + int green = (int)(luma + (values.GreenCb * blueDifference) + (values.GreenCr * redDifference) + 0.5F); + int blue = (int)(luma + (values.BlueCb * blueDifference) + 0.5F); + + r = (byte)(Numerics.Clamp(red, 0, values.Maximum) >> values.OutputShift); + g = (byte)(Numerics.Clamp(green, 0, values.Maximum) >> values.OutputShift); + b = (byte)(Numerics.Clamp(blue, 0, values.Maximum) >> values.OutputShift); + } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.LibheifMonochromeOperator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.LibheifMonochromeOperator.cs new file mode 100644 index 000000000..a62795004 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.LibheifMonochromeOperator.cs @@ -0,0 +1,82 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Provides pinned-libheif monochrome presentation. The luma code value is reduced directly to eight bits and copied +/// to all RGB components; signaled luma-range expansion is intentionally absent because libheif's direct monochrome +/// operation does not apply it. +/// +internal static partial class HeifYuvToRgb8Converter +{ + /// + /// Implements pinned-libheif monochrome conversion for scalar and SIMD lanes. + /// + private readonly struct LibheifMonochromeOperator : IHeifYuvToRgb8Operator + { + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b) + { + Vector512 value = y >> parameters.LibheifSixteenLane.OutputShift; + r = value; + g = value; + b = value; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector256 y, + Vector256 cb, + Vector256 cr, + in ConversionParameters parameters, + out Vector256 r, + out Vector256 g, + out Vector256 b) + { + Vector256 value = y >> parameters.LibheifEightLane.OutputShift; + r = value; + g = value; + b = value; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert( + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b) + { + Vector128 value = y >> parameters.LibheifFourLane.OutputShift; + r = value; + g = value; + b = value; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Convert(ushort y, ushort cb, ushort cr, in ConversionParameters parameters, out byte r, out byte g, out byte b) + { + byte value = (byte)(y >> parameters.LibheifScalar.OutputShift); + r = value; + g = value; + b = value; + } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.Operator.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.Operator.cs similarity index 79% rename from src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.Operator.cs rename to src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.Operator.cs index c881188bb..63b3142b1 100644 --- a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuv420ToRgb8Converter.Operator.cs +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.Operator.cs @@ -13,51 +13,39 @@ namespace SixLabors.ImageSharp.Formats.Heif.Components; /// pixels; each native chroma sample is duplicated into the two lanes covered by horizontal subsampling before the /// closed color operator runs. All products remain in signed 32-bit lanes until clipped RGB values are narrowed. /// -internal static partial class HeifYuv420ToRgb8Converter +internal static partial class HeifYuvToRgb8Converter { /// /// Defines fixed-point color arithmetic for scalar and SIMD lanes. /// - private interface IHeifYuv420ToRgb8Operator + private interface IHeifYuvToRgb8Operator { /// - /// Converts one full-range YCbCr sample to eight-bit RGB. - /// - /// The luma sample. - /// The blue-difference sample. - /// The red-difference sample. - /// The scalar fixed-point parameters. - /// The converted red sample. - /// The converted green sample. - /// The converted blue sample. - public static abstract void Convert(ushort y, ushort cb, ushort cr, in FixedPointParameters parameters, out byte r, out byte g, out byte b); - - /// - /// Converts four full-range YCbCr samples to eight-bit RGB lanes. + /// Converts sixteen YCbCr samples to eight-bit RGB lanes. /// /// The luma lanes. /// The blue-difference lanes. /// The red-difference lanes. - /// The four-lane fixed-point parameters. + /// The image conversion parameters. /// The converted red lanes. /// The converted green lanes. /// The converted blue lanes. public static abstract void Convert( - Vector128 y, - Vector128 cb, - Vector128 cr, - in Vector128Parameters parameters, - out Vector128 r, - out Vector128 g, - out Vector128 b); + Vector512 y, + Vector512 cb, + Vector512 cr, + in ConversionParameters parameters, + out Vector512 r, + out Vector512 g, + out Vector512 b); /// - /// Converts eight full-range YCbCr samples to eight-bit RGB lanes. + /// Converts eight YCbCr samples to eight-bit RGB lanes. /// /// The luma lanes. /// The blue-difference lanes. /// The red-difference lanes. - /// The eight-lane fixed-point parameters. + /// The image conversion parameters. /// The converted red lanes. /// The converted green lanes. /// The converted blue lanes. @@ -65,29 +53,41 @@ internal static partial class HeifYuv420ToRgb8Converter Vector256 y, Vector256 cb, Vector256 cr, - in Vector256Parameters parameters, + in ConversionParameters parameters, out Vector256 r, out Vector256 g, out Vector256 b); /// - /// Converts sixteen full-range YCbCr samples to eight-bit RGB lanes. + /// Converts four YCbCr samples to eight-bit RGB lanes. /// /// The luma lanes. /// The blue-difference lanes. /// The red-difference lanes. - /// The sixteen-lane fixed-point parameters. + /// The image conversion parameters. /// The converted red lanes. /// The converted green lanes. /// The converted blue lanes. public static abstract void Convert( - Vector512 y, - Vector512 cb, - Vector512 cr, - in Vector512Parameters parameters, - out Vector512 r, - out Vector512 g, - out Vector512 b); + Vector128 y, + Vector128 cb, + Vector128 cr, + in ConversionParameters parameters, + out Vector128 r, + out Vector128 g, + out Vector128 b); + + /// + /// Converts one YCbCr sample to eight-bit RGB. + /// + /// The luma sample. + /// The blue-difference sample. + /// The red-difference sample. + /// The image conversion parameters. + /// The converted red sample. + /// The converted green sample. + /// The converted blue sample. + public static abstract void Convert(ushort y, ushort cb, ushort cr, in ConversionParameters parameters, out byte r, out byte g, out byte b); } /// @@ -100,6 +100,7 @@ internal static partial class HeifYuv420ToRgb8Converter /// The destination red samples. /// The destination green samples. /// The destination blue samples. + /// The horizontal chroma subsampling shift. /// The fixed-point matrix coefficients. private static void ConvertRow( ReadOnlySpan luma, @@ -108,8 +109,9 @@ internal static partial class HeifYuv420ToRgb8Converter Span red, Span green, Span blue, + int subsamplingX, in ConversionParameters parameters) - where TOperator : struct, IHeifYuv420ToRgb8Operator + where TOperator : struct, IHeifYuvToRgb8Operator { ref ushort lumaBase = ref MemoryMarshal.GetReference(luma); ref ushort chromaBlueBase = ref MemoryMarshal.GetReference(chromaBlue); @@ -128,10 +130,15 @@ internal static partial class HeifYuv420ToRgb8Converter for (; x <= oneVectorFromEnd; x += Vector512.Count) { Vector512 y = LoadVector512(ref Unsafe.Add(ref lumaBase, x)); - Vector512 cb = LoadRepeatedVector512(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); - Vector512 cr = LoadRepeatedVector512(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + Vector512 cb = subsamplingX == 0 + ? LoadVector512(ref Unsafe.Add(ref chromaBlueBase, x)) + : LoadRepeatedVector512(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); + + Vector512 cr = subsamplingX == 0 + ? LoadVector512(ref Unsafe.Add(ref chromaRedBase, x)) + : LoadRepeatedVector512(ref Unsafe.Add(ref chromaRedBase, x >> 1)); - TOperator.Convert(y, cb, cr, in parameters.SixteenLane, out Vector512 r, out Vector512 g, out Vector512 b); + TOperator.Convert(y, cb, cr, in parameters, out Vector512 r, out Vector512 g, out Vector512 b); HeifByteSampleConverter.Store(r, ref Unsafe.Add(ref redBase, x)); HeifByteSampleConverter.Store(g, ref Unsafe.Add(ref greenBase, x)); HeifByteSampleConverter.Store(b, ref Unsafe.Add(ref blueBase, x)); @@ -145,10 +152,15 @@ internal static partial class HeifYuv420ToRgb8Converter for (; x <= oneVectorFromEnd; x += Vector256.Count) { Vector256 y = LoadVector256(ref Unsafe.Add(ref lumaBase, x)); - Vector256 cb = LoadRepeatedVector256(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); - Vector256 cr = LoadRepeatedVector256(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + Vector256 cb = subsamplingX == 0 + ? LoadVector256(ref Unsafe.Add(ref chromaBlueBase, x)) + : LoadRepeatedVector256(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); - TOperator.Convert(y, cb, cr, in parameters.EightLane, out Vector256 r, out Vector256 g, out Vector256 b); + Vector256 cr = subsamplingX == 0 + ? LoadVector256(ref Unsafe.Add(ref chromaRedBase, x)) + : LoadRepeatedVector256(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + + TOperator.Convert(y, cb, cr, in parameters, out Vector256 r, out Vector256 g, out Vector256 b); HeifByteSampleConverter.Store(r, ref Unsafe.Add(ref redBase, x)); HeifByteSampleConverter.Store(g, ref Unsafe.Add(ref greenBase, x)); HeifByteSampleConverter.Store(b, ref Unsafe.Add(ref blueBase, x)); @@ -162,10 +174,15 @@ internal static partial class HeifYuv420ToRgb8Converter for (; x <= oneVectorFromEnd; x += Vector128.Count) { Vector128 y = LoadVector128(ref Unsafe.Add(ref lumaBase, x)); - Vector128 cb = LoadRepeatedVector128(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); - Vector128 cr = LoadRepeatedVector128(ref Unsafe.Add(ref chromaRedBase, x >> 1)); + Vector128 cb = subsamplingX == 0 + ? LoadVector128(ref Unsafe.Add(ref chromaBlueBase, x)) + : LoadRepeatedVector128(ref Unsafe.Add(ref chromaBlueBase, x >> 1)); + + Vector128 cr = subsamplingX == 0 + ? LoadVector128(ref Unsafe.Add(ref chromaRedBase, x)) + : LoadRepeatedVector128(ref Unsafe.Add(ref chromaRedBase, x >> 1)); - TOperator.Convert(y, cb, cr, in parameters.FourLane, out Vector128 r, out Vector128 g, out Vector128 b); + TOperator.Convert(y, cb, cr, in parameters, out Vector128 r, out Vector128 g, out Vector128 b); HeifByteSampleConverter.Store(r, ref Unsafe.Add(ref redBase, x)); HeifByteSampleConverter.Store(g, ref Unsafe.Add(ref greenBase, x)); HeifByteSampleConverter.Store(b, ref Unsafe.Add(ref blueBase, x)); @@ -176,9 +193,9 @@ internal static partial class HeifYuv420ToRgb8Converter { TOperator.Convert( Unsafe.Add(ref lumaBase, x), - Unsafe.Add(ref chromaBlueBase, x >> 1), - Unsafe.Add(ref chromaRedBase, x >> 1), - in parameters.Scalar, + Unsafe.Add(ref chromaBlueBase, x >> subsamplingX), + Unsafe.Add(ref chromaRedBase, x >> subsamplingX), + in parameters, out Unsafe.Add(ref redBase, x), out Unsafe.Add(ref greenBase, x), out Unsafe.Add(ref blueBase, x)); diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.Parameters.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.Parameters.cs new file mode 100644 index 000000000..340b7db39 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.Parameters.cs @@ -0,0 +1,540 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Provides fixed-point scalar and SIMD coefficient storage for eight-bit 4:2:0 conversion. +/// +internal static partial class HeifYuvToRgb8Converter +{ + /// + /// Stores every scalar and SIMD coefficient representation resolved once for an image. + /// + private readonly struct ConversionParameters + { + /// + /// The scalar fixed-point coefficients. + /// + public readonly FixedPointParameters FixedPointScalar; + + /// + /// The four-lane SIMD coefficients. + /// + public readonly Vector128Parameters FixedPointFourLane; + + /// + /// The eight-lane SIMD coefficients. + /// + public readonly Vector256Parameters FixedPointEightLane; + + /// + /// The sixteen-lane SIMD coefficients. + /// + public readonly Vector512Parameters FixedPointSixteenLane; + + /// + /// The scalar pinned-libheif conversion parameters. + /// + public readonly LibheifParameters LibheifScalar; + + /// + /// The four-lane pinned-libheif conversion parameters. + /// + public readonly LibheifVector128Parameters LibheifFourLane; + + /// + /// The eight-lane pinned-libheif conversion parameters. + /// + public readonly LibheifVector256Parameters LibheifEightLane; + + /// + /// The sixteen-lane pinned-libheif conversion parameters. + /// + public readonly LibheifVector512Parameters LibheifSixteenLane; + + /// + /// Initializes a new instance of the struct. + /// + /// The shared floating-point conversion parameters. + /// The common source component precision. + public ConversionParameters(in HeifColorConversionParameters parameters, int bitDepth) + { + FixedPointParameters scalar = new(in parameters); + this.FixedPointScalar = scalar; + this.FixedPointFourLane = new(in scalar); + this.FixedPointEightLane = new(in scalar); + this.FixedPointSixteenLane = new(in scalar); + + LibheifParameters libheif = new(in parameters, bitDepth); + this.LibheifScalar = libheif; + this.LibheifFourLane = new(in libheif); + this.LibheifEightLane = new(in libheif); + this.LibheifSixteenLane = new(in libheif); + } + } + + /// + /// Stores the scalar fixed-point coefficients resolved for one image. + /// + private readonly struct FixedPointParameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The shared floating-point conversion parameters. + public FixedPointParameters(in HeifColorConversionParameters parameters) + { + float scale = 1 << CoefficientShift; + + // Rounding each image-invariant coefficient once gives the integer kernel eight fractional bits. + // The signed green coefficients retain the exact addition and rounding order used by every SIMD lane. + this.RedCr = (int)MathF.Round(parameters.RedChromaScale * scale, MidpointRounding.AwayFromZero); + this.GreenCb = -(int)MathF.Round(parameters.GreenBlueChromaScale * scale, MidpointRounding.AwayFromZero); + this.GreenCr = -(int)MathF.Round(parameters.GreenRedChromaScale * scale, MidpointRounding.AwayFromZero); + this.BlueCb = (int)MathF.Round(parameters.BlueChromaScale * scale, MidpointRounding.AwayFromZero); + } + + /// + /// Gets the red contribution from centered Cr. + /// + public int RedCr { get; } + + /// + /// Gets the green contribution from centered Cb. + /// + public int GreenCb { get; } + + /// + /// Gets the green contribution from centered Cr. + /// + public int GreenCr { get; } + + /// + /// Gets the blue contribution from centered Cb. + /// + public int BlueCb { get; } + } + + /// + /// Broadcasts the fixed-point coefficients for four-lane conversion. + /// + private readonly struct Vector128Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar fixed-point coefficients. + public Vector128Parameters(in FixedPointParameters parameters) + { + this.ChromaMidpoint = Vector128.Create(HeifYuvToRgb8Converter.ChromaMidpoint); + this.RoundingBias = Vector128.Create(HeifYuvToRgb8Converter.RoundingBias); + this.Maximum = Vector128.Create((int)byte.MaxValue); + this.RedCr = Vector128.Create(parameters.RedCr); + this.GreenCb = Vector128.Create(parameters.GreenCb); + this.GreenCr = Vector128.Create(parameters.GreenCr); + this.BlueCb = Vector128.Create(parameters.BlueCb); + } + + /// + /// Gets the neutral chroma code-value lanes. + /// + public Vector128 ChromaMidpoint { get; } + + /// + /// Gets the fixed-point rounding-bias lanes. + /// + public Vector128 RoundingBias { get; } + + /// + /// Gets the maximum eight-bit sample lanes. + /// + public Vector128 Maximum { get; } + + /// + /// Gets the red Cr coefficient lanes. + /// + public Vector128 RedCr { get; } + + /// + /// Gets the green Cb coefficient lanes. + /// + public Vector128 GreenCb { get; } + + /// + /// Gets the green Cr coefficient lanes. + /// + public Vector128 GreenCr { get; } + + /// + /// Gets the blue Cb coefficient lanes. + /// + public Vector128 BlueCb { get; } + } + + /// + /// Broadcasts the fixed-point coefficients for eight-lane conversion. + /// + private readonly struct Vector256Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar fixed-point coefficients. + public Vector256Parameters(in FixedPointParameters parameters) + { + this.ChromaMidpoint = Vector256.Create(HeifYuvToRgb8Converter.ChromaMidpoint); + this.RoundingBias = Vector256.Create(HeifYuvToRgb8Converter.RoundingBias); + this.Maximum = Vector256.Create((int)byte.MaxValue); + this.RedCr = Vector256.Create(parameters.RedCr); + this.GreenCb = Vector256.Create(parameters.GreenCb); + this.GreenCr = Vector256.Create(parameters.GreenCr); + this.BlueCb = Vector256.Create(parameters.BlueCb); + } + + /// + /// Gets the neutral chroma code-value lanes. + /// + public Vector256 ChromaMidpoint { get; } + + /// + /// Gets the fixed-point rounding-bias lanes. + /// + public Vector256 RoundingBias { get; } + + /// + /// Gets the maximum eight-bit sample lanes. + /// + public Vector256 Maximum { get; } + + /// + /// Gets the red Cr coefficient lanes. + /// + public Vector256 RedCr { get; } + + /// + /// Gets the green Cb coefficient lanes. + /// + public Vector256 GreenCb { get; } + + /// + /// Gets the green Cr coefficient lanes. + /// + public Vector256 GreenCr { get; } + + /// + /// Gets the blue Cb coefficient lanes. + /// + public Vector256 BlueCb { get; } + } + + /// + /// Broadcasts the fixed-point coefficients for sixteen-lane conversion. + /// + private readonly struct Vector512Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar fixed-point coefficients. + public Vector512Parameters(in FixedPointParameters parameters) + { + this.ChromaMidpoint = Vector512.Create(HeifYuvToRgb8Converter.ChromaMidpoint); + this.RoundingBias = Vector512.Create(HeifYuvToRgb8Converter.RoundingBias); + this.Maximum = Vector512.Create((int)byte.MaxValue); + this.RedCr = Vector512.Create(parameters.RedCr); + this.GreenCb = Vector512.Create(parameters.GreenCb); + this.GreenCr = Vector512.Create(parameters.GreenCr); + this.BlueCb = Vector512.Create(parameters.BlueCb); + } + + /// + /// Gets the neutral chroma code-value lanes. + /// + public Vector512 ChromaMidpoint { get; } + + /// + /// Gets the fixed-point rounding-bias lanes. + /// + public Vector512 RoundingBias { get; } + + /// + /// Gets the maximum eight-bit sample lanes. + /// + public Vector512 Maximum { get; } + + /// + /// Gets the red Cr coefficient lanes. + /// + public Vector512 RedCr { get; } + + /// + /// Gets the green Cb coefficient lanes. + /// + public Vector512 GreenCb { get; } + + /// + /// Gets the green Cr coefficient lanes. + /// + public Vector512 GreenCr { get; } + + /// + /// Gets the blue Cb coefficient lanes. + /// + public Vector512 BlueCb { get; } + } + + /// + /// Stores the scalar coefficients and range values used by pinned libheif 1.23.1. + /// + private readonly struct LibheifParameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The resolved H.273 matrix and range values. + /// The common source component precision. + public LibheifParameters(in HeifColorConversionParameters parameters, int bitDepth) + { + this.LumaOffset = parameters.IsFullRange ? 0F : parameters.LumaBias; + this.LumaScale = parameters.IsFullRange ? 1F : 1.1689F; + this.ChromaMidpoint = parameters.ChromaBias; + this.ChromaScale = parameters.IsFullRange ? 1F : 1.1429F; + if (parameters.MatrixCoefficients == CicpMatrixCoefficients.Unspecified) + { + // libheif falls back to these literal Rec.601 coefficients when no matrix is signaled. + this.RedCr = 1.402F; + this.GreenCb = -0.344136F; + this.GreenCr = -0.714136F; + this.BlueCb = 1.772F; + } + else + { + float kr = parameters.Kr; + float kb = parameters.Kb; + this.RedCr = 2F * (-kr + 1F); + this.GreenCb = 2F * kb * (-kb + 1F) / (kb + kr - 1F); + this.GreenCr = 2F * kr * (-kr + 1F) / (kb + kr - 1F); + this.BlueCb = 2F * (-kb + 1F); + } + + this.Maximum = (1 << bitDepth) - 1; + this.OutputShift = bitDepth - 8; + } + + /// + /// Gets the luma code-value offset removed before limited-range expansion. + /// + public float LumaOffset { get; } + + /// + /// Gets the luma range-expansion factor. + /// + public float LumaScale { get; } + + /// + /// Gets the neutral chroma code value. + /// + public float ChromaMidpoint { get; } + + /// + /// Gets the chroma range-expansion factor. + /// + public float ChromaScale { get; } + + /// + /// Gets the red contribution from Cr. + /// + public float RedCr { get; } + + /// + /// Gets the green contribution from Cb. + /// + public float GreenCb { get; } + + /// + /// Gets the green contribution from Cr. + /// + public float GreenCr { get; } + + /// + /// Gets the blue contribution from Cb. + /// + public float BlueCb { get; } + + /// + /// Gets the largest RGB code value at the source precision. + /// + public int Maximum { get; } + + /// + /// Gets the right shift reducing source-precision RGB to eight bits. + /// + public int OutputShift { get; } + } + + /// + /// Broadcasts pinned-libheif coefficients for four-lane conversion. + /// + private readonly struct LibheifVector128Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar pinned-libheif coefficients. + public LibheifVector128Parameters(in LibheifParameters parameters) + { + this.LumaOffset = Vector128.Create(parameters.LumaOffset); + this.LumaScale = Vector128.Create(parameters.LumaScale); + this.ChromaMidpoint = Vector128.Create(parameters.ChromaMidpoint); + this.ChromaScale = Vector128.Create(parameters.ChromaScale); + this.RedCr = Vector128.Create(parameters.RedCr); + this.GreenCb = Vector128.Create(parameters.GreenCb); + this.GreenCr = Vector128.Create(parameters.GreenCr); + this.BlueCb = Vector128.Create(parameters.BlueCb); + this.Maximum = Vector128.Create(parameters.Maximum); + this.OutputShift = parameters.OutputShift; + } + + /// Gets the luma offset lanes. + public Vector128 LumaOffset { get; } + + /// Gets the luma scale lanes. + public Vector128 LumaScale { get; } + + /// Gets the chroma-midpoint lanes. + public Vector128 ChromaMidpoint { get; } + + /// Gets the chroma-scale lanes. + public Vector128 ChromaScale { get; } + + /// Gets the red Cr coefficient lanes. + public Vector128 RedCr { get; } + + /// Gets the green Cb coefficient lanes. + public Vector128 GreenCb { get; } + + /// Gets the green Cr coefficient lanes. + public Vector128 GreenCr { get; } + + /// Gets the blue Cb coefficient lanes. + public Vector128 BlueCb { get; } + + /// Gets the maximum RGB code-value lanes. + public Vector128 Maximum { get; } + + /// Gets the output reduction shift. + public int OutputShift { get; } + } + + /// + /// Broadcasts pinned-libheif coefficients for eight-lane conversion. + /// + private readonly struct LibheifVector256Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar pinned-libheif coefficients. + public LibheifVector256Parameters(in LibheifParameters parameters) + { + this.LumaOffset = Vector256.Create(parameters.LumaOffset); + this.LumaScale = Vector256.Create(parameters.LumaScale); + this.ChromaMidpoint = Vector256.Create(parameters.ChromaMidpoint); + this.ChromaScale = Vector256.Create(parameters.ChromaScale); + this.RedCr = Vector256.Create(parameters.RedCr); + this.GreenCb = Vector256.Create(parameters.GreenCb); + this.GreenCr = Vector256.Create(parameters.GreenCr); + this.BlueCb = Vector256.Create(parameters.BlueCb); + this.Maximum = Vector256.Create(parameters.Maximum); + this.OutputShift = parameters.OutputShift; + } + + /// Gets the luma offset lanes. + public Vector256 LumaOffset { get; } + + /// Gets the luma scale lanes. + public Vector256 LumaScale { get; } + + /// Gets the chroma-midpoint lanes. + public Vector256 ChromaMidpoint { get; } + + /// Gets the chroma-scale lanes. + public Vector256 ChromaScale { get; } + + /// Gets the red Cr coefficient lanes. + public Vector256 RedCr { get; } + + /// Gets the green Cb coefficient lanes. + public Vector256 GreenCb { get; } + + /// Gets the green Cr coefficient lanes. + public Vector256 GreenCr { get; } + + /// Gets the blue Cb coefficient lanes. + public Vector256 BlueCb { get; } + + /// Gets the maximum RGB code-value lanes. + public Vector256 Maximum { get; } + + /// Gets the output reduction shift. + public int OutputShift { get; } + } + + /// + /// Broadcasts pinned-libheif coefficients for sixteen-lane conversion. + /// + private readonly struct LibheifVector512Parameters + { + /// + /// Initializes a new instance of the struct. + /// + /// The scalar pinned-libheif coefficients. + public LibheifVector512Parameters(in LibheifParameters parameters) + { + this.LumaOffset = Vector512.Create(parameters.LumaOffset); + this.LumaScale = Vector512.Create(parameters.LumaScale); + this.ChromaMidpoint = Vector512.Create(parameters.ChromaMidpoint); + this.ChromaScale = Vector512.Create(parameters.ChromaScale); + this.RedCr = Vector512.Create(parameters.RedCr); + this.GreenCb = Vector512.Create(parameters.GreenCb); + this.GreenCr = Vector512.Create(parameters.GreenCr); + this.BlueCb = Vector512.Create(parameters.BlueCb); + this.Maximum = Vector512.Create(parameters.Maximum); + this.OutputShift = parameters.OutputShift; + } + + /// Gets the luma offset lanes. + public Vector512 LumaOffset { get; } + + /// Gets the luma scale lanes. + public Vector512 LumaScale { get; } + + /// Gets the chroma-midpoint lanes. + public Vector512 ChromaMidpoint { get; } + + /// Gets the chroma-scale lanes. + public Vector512 ChromaScale { get; } + + /// Gets the red Cr coefficient lanes. + public Vector512 RedCr { get; } + + /// Gets the green Cb coefficient lanes. + public Vector512 GreenCb { get; } + + /// Gets the green Cr coefficient lanes. + public Vector512 GreenCr { get; } + + /// Gets the blue Cb coefficient lanes. + public Vector512 BlueCb { get; } + + /// Gets the maximum RGB code-value lanes. + public Vector512 Maximum { get; } + + /// Gets the output reduction shift. + public int OutputShift { get; } + } +} diff --git a/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.cs b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.cs new file mode 100644 index 000000000..6e2f74942 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Components/ColorConverters/HeifYuvToRgb8Converter.cs @@ -0,0 +1,207 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Heif.Components; + +/// +/// Converts HEIF YUV planes directly to packed eight-bit RGB pixels. +/// +internal static partial class HeifYuvToRgb8Converter +{ + /// + /// The fixed-point precision used for H.273 matrix coefficients. + /// + private const int CoefficientShift = 8; + + /// + /// The half-unit bias used before fixed-point coefficient results are shifted to integer samples. + /// + private const int RoundingBias = 1 << (CoefficientShift - 1); + + /// + /// The neutral code value for full-range eight-bit chroma. + /// + private const int ChromaMidpoint = 128; + + /// + /// Determines whether the specialized fixed-point conversion supports the supplied plane and color description. + /// + /// The horizontal chroma subsampling shift. + /// The vertical chroma subsampling shift. + /// The luma sample precision in bits. + /// The chroma sample precision in bits. + /// Whether the samples use the complete numeric range. + /// The H.273 matrix-coefficient code point. + /// The resolved H.273 conversion operation. + /// when the planes can use this converter; otherwise, . + public static bool SupportsFixedPointConversion( + int subsamplingX, + int subsamplingY, + int lumaBitDepth, + int chromaBitDepth, + bool isFullRange, + CicpMatrixCoefficients matrixCoefficients, + HeifColorConversionMode mode) + => subsamplingX == 1 + && subsamplingY == 1 + && lumaBitDepth == 8 + && chromaBitDepth == 8 + && isFullRange + && matrixCoefficients == CicpMatrixCoefficients.Unspecified + && mode == HeifColorConversionMode.Coefficients; + + /// + /// Determines whether the pinned libheif-compatible conversion supports the supplied plane and color description. + /// + /// The horizontal chroma subsampling shift. + /// The vertical chroma subsampling shift. + /// The luma sample precision in bits. + /// The chroma sample precision in bits. + /// Whether the image contains only luma samples. + /// The resolved H.273 conversion operation. + /// when the planes can use this converter; otherwise, . + public static bool SupportsLibheifConversion( + int subsamplingX, + int subsamplingY, + int lumaBitDepth, + int chromaBitDepth, + bool isMonochrome, + HeifColorConversionMode mode) + => (isMonochrome || (subsamplingX is 0 or 1 && subsamplingY is 0 or 1)) + && lumaBitDepth == 8 + && (isMonochrome || chromaBitDepth == 8) + && mode == HeifColorConversionMode.Coefficients; + + /// + /// Converts supported HEIF component planes to packed pixels using integer SIMD with a scalar tail. + /// + /// The destination pixel type. + /// The codec adapter that exposes reconstructed component rows. + /// The configuration used for allocation and pixel conversion. + /// The reconstructed component-plane buffer. + /// The destination image frame. + /// The resolved H.273 conversion parameters. + /// The horizontal luma-sample offset of the output window. + /// The vertical luma-sample offset of the output window. + public static void ConvertFixedPoint( + Configuration configuration, + TBuffer buffer, + ImageFrame image, + in HeifColorConversionParameters parameters, + int sourceX, + int sourceY) + where TPixel : unmanaged, IPixel + where TBuffer : struct, IHeifPlanarSampleBuffer + { + ConversionParameters conversionParameters = new(in parameters, 8); + using IMemoryOwner componentOwner = configuration.MemoryAllocator.Allocate(image.Width * 3); + Span components = componentOwner.GetSpan(); + Span red = components[..image.Width]; + Span green = components.Slice(image.Width, image.Width); + Span blue = components.Slice(image.Width * 2, image.Width); + + // The value-type buffer closes the row-access contract at the call site. Constrained calls are therefore + // devirtualized without boxing while keeping codec-specific buffer ownership outside the color pipeline. + for (int y = 0; y < image.Height; y++) + { + int lumaY = sourceY + y; + + // The codec boundary validates 4:2:0 crop offsets in complete chroma-sample units. Each native chroma + // sample therefore covers one 2x2 luma cell without an alignment branch in the SIMD loop. + ReadOnlySpan luma = buffer.GetLumaRowSpan(lumaY).Slice(sourceX, image.Width); + ReadOnlySpan chromaBlue = buffer.GetChromaBlueRowSpan(lumaY >> 1).Slice(sourceX >> 1); + ReadOnlySpan chromaRed = buffer.GetChromaRedRowSpan(lumaY >> 1).Slice(sourceX >> 1); + + ConvertRow( + luma, + chromaBlue, + chromaRed, + red, + green, + blue, + 1, + in conversionParameters); + + Span destination = image.PixelBuffer.DangerousGetRowSpan(y); + PixelOperations.Instance.PackFromRgbPlanes(red, green, blue, destination); + } + } + + /// + /// Converts supported HEVC planes with the arithmetic and nearest-sample traversal used by pinned libheif. + /// + /// The destination pixel type. + /// The codec adapter that exposes reconstructed component rows. + /// The configuration used for allocation and pixel conversion. + /// The reconstructed component-plane buffer. + /// The destination image frame. + /// The resolved H.273 conversion parameters. + /// The horizontal luma-sample offset of the output window. + /// The vertical luma-sample offset of the output window. + public static void ConvertLibheif( + Configuration configuration, + TBuffer buffer, + ImageFrame image, + in HeifColorConversionParameters parameters, + int sourceX, + int sourceY) + where TPixel : unmanaged, IPixel + where TBuffer : struct, IHeifPlanarSampleBuffer + { + ConversionParameters conversionParameters = new(in parameters, buffer.LumaBitDepth); + using IMemoryOwner componentOwner = configuration.MemoryAllocator.Allocate(image.Width * 3); + Span components = componentOwner.GetSpan(); + Span red = components[..image.Width]; + Span green = components.Slice(image.Width, image.Width); + Span blue = components.Slice(image.Width * 2, image.Width); + + for (int y = 0; y < image.Height; y++) + { + int lumaY = sourceY + y; + ReadOnlySpan luma = buffer.GetLumaRowSpan(lumaY).Slice(sourceX, image.Width); + if (buffer.IsMonochrome) + { + // Pinned libheif reduces monochrome precision first and copies that code value to RGB. It does not + // apply the signaled limited-range expansion used by its three-component conversion operation. + ConvertRow( + luma, + luma, + luma, + red, + green, + blue, + 0, + in conversionParameters); + } + else + { + int subsamplingX = buffer.ChromaSubsamplingX; + int chromaY = lumaY >> buffer.ChromaSubsamplingY; + + // The HEIF crop boundary validates horizontal offsets in complete chroma-sample units. Slicing once + // therefore preserves libheif's x >> subsampling mapping without a phase branch in the SIMD loop. + ReadOnlySpan chromaBlue = buffer.GetChromaBlueRowSpan(chromaY).Slice(sourceX >> subsamplingX); + ReadOnlySpan chromaRed = buffer.GetChromaRedRowSpan(chromaY).Slice(sourceX >> subsamplingX); + + ConvertRow( + luma, + chromaBlue, + chromaRed, + red, + green, + blue, + subsamplingX, + in conversionParameters); + } + + Span destination = image.PixelBuffer.DangerousGetRowSpan(y); + PixelOperations.Instance.PackFromRgbPlanes(red, green, blue, destination); + } + } +} diff --git a/src/ImageSharp/Formats/Heif/Hevc/Color/HevcYuvConverter.cs b/src/ImageSharp/Formats/Heif/Hevc/Color/HevcYuvConverter.cs index 92a8af514..87923cb5c 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/Color/HevcYuvConverter.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/Color/HevcYuvConverter.cs @@ -36,6 +36,50 @@ internal static class HevcYuvConverter { HeifColorConversionParameters parameters = GetConversionParameters(picture, colorProfile, out HeifColorConversionMode mode); HevcPlanarSampleBuffer buffer = new(picture, chromaSampleLocation); + if (HeifYuvToRgb8Converter.SupportsLibheifConversion( + buffer.ChromaSubsamplingX, + buffer.ChromaSubsamplingY, + buffer.LumaBitDepth, + buffer.ChromaBitDepth, + buffer.IsMonochrome, + mode)) + { + // libheif 1.23.1 is the pinned HEIC presentation implementation. Its pipeline search selects the + // lower-cost direct YCbCr operation when preferred-only upsampling is disabled, so subsampled chroma is + // nearest-replicated and high-bit-depth RGB is rounded before a separate shift to eight bits. + HeifYuvToRgb8Converter.ConvertLibheif( + configuration, + buffer, + image, + in parameters, + sourceX, + sourceY); + + return; + } + + if (HeifYuvToRgb16Converter.SupportsLibheifConversion( + buffer.ChromaSubsamplingX, + buffer.ChromaSubsamplingY, + buffer.LumaBitDepth, + buffer.ChromaBitDepth, + buffer.IsMonochrome, + mode)) + { + // High-bit-depth conversion retains every rounded source-precision RGB bit in UInt16 storage before + // PixelOperations performs the requested TPixel conversion. This prevents an Rgba32 test from concealing + // precision loss in Rgba64, Rgb48, or floating-point decoder output. + HeifYuvToRgb16Converter.Convert( + configuration, + buffer, + image, + in parameters, + sourceX, + sourceY); + + return; + } + HeifPlanarColorConverter.ConvertToRgb( configuration, buffer, diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs index ca8ea5a38..2813c9c27 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1ReconstructionConformanceTests.cs @@ -467,9 +467,27 @@ public class Av1ReconstructionConformanceTests /// Verifies exact presented pixels and public metadata for independently encoded eight-, ten-, and twelve-bit /// active-CDEF AVIF images across the available vector widths and the scalar fallback. /// - [Fact] - public void DecodeWithActiveCdefMatchesPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidatePresentedFixtures, PresentationConfigurations); + /// The AVIF input and matching reference-output naming context. + /// The expected presented width. + /// The expected presented height. + /// The expected public sample precision. + [Theory] + [WithFile(TestImages.Heif.Av1Cdef8BitAvif, PixelTypes.Rgba32, 768, 512, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Cdef10BitAvif, PixelTypes.Rgba32, 1024, 428, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Cdef12BitAvif, PixelTypes.Rgba32, 1024, 428, HeifBitDepth.Bit12)] + public void DecodeWithActiveCdefMatchesPinnedLibavifPresentation( + TestImageProvider provider, + int width, + int height, + HeifBitDepth bitDepth) + { + AssertPresentedMetadata(provider, width, height, bitDepth); + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); + } /// /// Verifies exact native reconstruction for every valid AV1 profile, bit-depth, and chroma-format combination @@ -491,17 +509,41 @@ public class Av1ReconstructionConformanceTests /// Verifies exact presented pixels, public bit-depth metadata, and CICP signaling for every valid AV1 profile, /// bit-depth, and chroma-format combination supported by AVIF. /// - [Fact] - public void DecodeProfileMatrixMatchesPinnedLibavifPresentation() - => ValidateProfilePresentedFixtures(); + /// The AVIF input and matching reference-output naming context. + /// The expected public sample precision. + [Theory] + [WithFile(TestImages.Heif.Av1Profile8BitMonochromeAvif, PixelTypes.Rgba32, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Profile8Bit420Avif, PixelTypes.Rgba32, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Profile8Bit422Avif, PixelTypes.Rgba32, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Profile8Bit444Avif, PixelTypes.Rgba32, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Profile10BitMonochromeAvif, PixelTypes.Rgba32, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Profile10Bit420Avif, PixelTypes.Rgba32, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Profile10Bit422Avif, PixelTypes.Rgba32, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Profile10Bit444Avif, PixelTypes.Rgba32, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Profile12BitMonochromeAvif, PixelTypes.Rgba32, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.Av1Profile12Bit420Avif, PixelTypes.Rgba32, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.Av1Profile12Bit422Avif, PixelTypes.Rgba32, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.Av1Profile12Bit444Avif, PixelTypes.Rgba32, HeifBitDepth.Bit12)] + public void DecodeProfileMatrixMatchesPinnedLibavifPresentation( + TestImageProvider provider, + HeifBitDepth bitDepth) + { + using Image image = provider.GetImage(); + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); + Assert.Equal(HeifCompressionMethod.Av1, metadata.CompressionMethod); + Assert.Equal(bitDepth, metadata.BitDepth); - /// - /// Verifies exact presented pixels, public bit-depth metadata, and CICP signaling under each narrower vector width - /// and the scalar fallback. - /// - [Fact] - public void DecodeProfileMatrixFallbacksMatchPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateProfilePresentedFixtures, ProfileFallbackConfigurations); + CicpProfile colorProfile = Assert.IsType(image.Metadata.CicpProfile); + Assert.Equal(CicpColorPrimaries.ItuRBt709_6, colorProfile.ColorPrimaries); + Assert.Equal(CicpTransferCharacteristics.Iec61966_2_1, colorProfile.TransferCharacteristics); + Assert.Equal(CicpMatrixCoefficients.ItuRBt601_7_525, colorProfile.MatrixCoefficients); + Assert.True(colorProfile.FullRange); + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); + } /// /// Verifies decoded luma and chroma palette syntax and exact native samples against scalar libaom for an @@ -567,9 +609,14 @@ public class Av1ReconstructionConformanceTests /// Verifies decoded luma and chroma palette syntax and exact presented pixels for an independently encoded AVIF /// image across the available vector widths and the scalar fallback. /// - [Fact] - public void DecodeWithPaletteMatchesPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidatePalettePresentedFixture, PresentationConfigurations); + /// The AVIF input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.Av1Palette8BitAvif, PixelTypes.Rgba32)] + public void DecodeWithPaletteMatchesPinnedLibavifPresentation(TestImageProvider provider) + => FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); /// /// Verifies that malformed data following a decoded palette tile releases its frame state before the same decoder @@ -619,19 +666,31 @@ public class Av1ReconstructionConformanceTests /// Verifies exact presented pixels for independently encoded intra-block-copy AVIF images across the available /// vector widths and the scalar fallback. /// - [Fact] - public void DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateIntraBlockCopyPresentedFixtures, PresentationConfigurations); + /// The AVIF input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.Av1IntraBlockCopy8BitAvif, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.Av1IntraBlockCopy10BitAvif, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.Av1IntraBlockCopy12BitAvif, PixelTypes.Rgba32)] + public void DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation( + TestImageProvider provider) + => FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); /// /// Verifies the production single-reference inter-reconstruction path against exact native and presentation /// references across the available vector widths and scalar fallback. /// - [Fact] - public void DecodeProgressiveSingleReferenceMatchesPinnedReferences() + /// The AVIF input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.Av1Progressive8BitAvif, PixelTypes.Rgba32)] + public void DecodeProgressiveSingleReferenceMatchesPinnedReferences( + TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateProgressiveSingleReferenceFixtureWithDefaultConfiguration, - PresentationConfigurations); + PresentationConfigurations, + provider); /// /// Verifies production single-reference inter reconstruction with a constrained allocator. @@ -645,7 +704,7 @@ public class Av1ReconstructionConformanceTests Configuration configuration = Configuration.Default.Clone(); configuration.MemoryAllocator = allocator; - ValidateProgressiveSingleReferenceFixture(configuration, verifyPresentation: true); + ValidateProgressiveSingleReferenceFixture(configuration); Assert.Equal(allocator.AllocationLog.Count, allocator.ReturnLog.Count); Assert.All( @@ -659,11 +718,15 @@ public class Av1ReconstructionConformanceTests /// Verifies that an essential lsel property returns the selected base spatial layer rather than the final /// progressive layer, with exact pinned-libaom native planes and pinned-libavif presentation. /// - [Fact] - public void DecodeSelectedProgressiveSpatialLayerMatchesPinnedReferences() + /// The selected-layer AVIF input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.Av1ScaledReferenceSelectedLayerAvif, PixelTypes.Rgba32)] + public void DecodeSelectedProgressiveSpatialLayerMatchesPinnedReferences( + TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateSelectedProgressiveSpatialLayerWithDefaultConfiguration, - PresentationConfigurations); + PresentationConfigurations, + provider); /// /// Verifies selected-layer native reconstruction and public presentation with constrained tracked allocation. @@ -691,11 +754,14 @@ public class Av1ReconstructionConformanceTests /// Verifies an independently encoded 40x40 retained layer scaled into an 80x80 dependent layer against exact /// pinned-libaom native planes and pinned-libavif presentation. /// - [Fact] - public void DecodeScaledReferenceMatchesPinnedReferences() + /// The AVIF input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.Av1ScaledReferenceAvif, PixelTypes.Rgba32)] + public void DecodeScaledReferenceMatchesPinnedReferences(TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateScaledReferenceFixtureWithDefaultConfiguration, - ReconstructionConfigurations); + ReconstructionConfigurations, + provider); /// /// Verifies scaled-reference reconstruction with constrained tracked allocation and contiguous frame planes. @@ -709,7 +775,7 @@ public class Av1ReconstructionConformanceTests Configuration configuration = Configuration.Default.Clone(); configuration.MemoryAllocator = allocator; - ValidateScaledReferenceFixture(configuration, verifyPresentation: false); + ValidateScaledReferenceFixture(configuration); Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "RetainedMotionFieldEntry"); Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "TemporalMotionFieldEntry"); @@ -783,11 +849,15 @@ public class Av1ReconstructionConformanceTests /// Verifies exact native reconstruction and presentation for a genuine pinned-libavif image sequence that uses /// equal-weight compound prediction. /// - [Fact] - public void DecodeRealLibavifSequenceWithEqualAverageCompoundMatchesPinnedReferences() + [Theory] + [WithFile(TestImages.Heif.Av1AverageCompoundSequenceAvif, PixelTypes.Rgba32)] + public void DecodeRealLibavifSequenceWithEqualAverageCompoundMatchesPinnedReferences( + TestImageProvider provider) + => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateAverageCompoundSequenceWithDefaultConfiguration, - ReconstructionConfigurations); + ReconstructionConfigurations, + provider); /// /// Verifies the complete compound sequence through a constrained allocator. @@ -801,7 +871,7 @@ public class Av1ReconstructionConformanceTests Configuration configuration = Configuration.Default.Clone(); configuration.MemoryAllocator = allocator; - ValidateAverageCompoundSequence(configuration, null); + ValidateAverageCompoundSequence(configuration); Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "RetainedMotionFieldEntry"); Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "TemporalMotionFieldEntry"); @@ -816,22 +886,18 @@ public class Av1ReconstructionConformanceTests /// /// Runs the exact compound-sequence comparisons with the default configuration. /// - private static void ValidateAverageCompoundSequenceWithDefaultConfiguration() + /// The serialized input provider and reference-output naming context. + private static void ValidateAverageCompoundSequenceWithDefaultConfiguration(string providerDump) { - byte[] presentationBytes = TestFile.Create(TestImages.Heif.Av1AverageCompoundSequencePresentationReference).Bytes; - using Image presentationReference = Image.Load(presentationBytes); - - ValidateAverageCompoundSequence(Configuration.Default, presentationReference.Frames.RootFrame); + ValidateAverageCompoundSequence(Configuration.Default); + ValidateFinalSequencePresentation(providerDump); } /// - /// Validates the complete compound sequence with the requested allocator and optional presentation reference. + /// Validates the complete compound sequence with the requested allocator. /// /// The decoder configuration. - /// The exact final presented frame, or . - private static void ValidateAverageCompoundSequence( - Configuration configuration, - ImageFrame presentationReference) + private static void ValidateAverageCompoundSequence(Configuration configuration) { byte[] fileBytes = TestFile.Create(TestImages.Heif.Av1AverageCompoundSequenceAvif).Bytes; byte[] referenceBytes = TestFile.Create(TestImages.Heif.Av1AverageCompoundSequenceNativeReference).Bytes; @@ -852,7 +918,6 @@ public class Av1ReconstructionConformanceTests int compoundBlockCount = 0; int visibleFrameCount = 0; bool nativeCompared = false; - bool presentationCompared = false; using Av1Decoder decoder = new(configuration); for (int sampleIndex = 0; sampleIndex < track.Samples.Length; sampleIndex++) @@ -925,15 +990,6 @@ public class Av1ReconstructionConformanceTests Assert.Equal(Av1ColorFormat.Yuv444, frameBuffer.ColorFormat); AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); nativeCompared = true; - - if (presentationReference is not null) - { - ImageSimilarityReport report = - ImageComparer.Exact.CompareImagesOrFrames(visibleFrameCount, presentationReference, frame); - - Assert.True(report.IsEmpty, report.ToString()); - presentationCompared = true; - } } visibleFrameCount++; @@ -942,17 +998,23 @@ public class Av1ReconstructionConformanceTests Assert.Equal(AverageCompoundFixtureFrameCount, visibleFrameCount); Assert.NotEqual(0, compoundBlockCount); Assert.True(nativeCompared); - Assert.Equal(presentationReference is not null, presentationCompared); } /// /// Verifies every selectable compound and inter-intra production branch against pinned native and presentation references. /// - [Fact] - public void DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences() + [Theory] + [WithFile(TestImages.Heif.Av1DistanceWeightedCompoundSequenceAvif, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.Av1WedgeCompoundSequenceAvif, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.Av1DifferenceWeightedCompoundSequenceAvif, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.Av1InterIntraSequenceAvif, PixelTypes.Rgba32)] + public void DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences( + TestImageProvider provider) + => FeatureTestRunner.RunWithHwIntrinsicsFeature( - ValidateSelectableCompoundSequencesWithDefaultConfiguration, - ReconstructionConfigurations); + ValidateSelectableCompoundSequenceWithDefaultConfiguration, + ReconstructionConfigurations, + provider); /// /// Verifies selectable compound and inter-intra reconstruction through a constrained allocator. @@ -964,36 +1026,42 @@ public class Av1ReconstructionConformanceTests ValidateInterPredictionSequenceWithConstrainedAllocator( TestImages.Heif.Av1DistanceWeightedCompoundSequenceAvif, TestImages.Heif.Av1DistanceWeightedCompoundSequenceNativeReference, - TestImages.Heif.Av1DistanceWeightedCompoundSequencePresentationReference, - DistanceWeightedCompoundCoverage); + DistanceWeightedCompoundCoverage, + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); ValidateInterPredictionSequenceWithConstrainedAllocator( TestImages.Heif.Av1WedgeCompoundSequenceAvif, TestImages.Heif.Av1WedgeCompoundSequenceNativeReference, - TestImages.Heif.Av1WedgeCompoundSequencePresentationReference, - WedgeCompoundCoverage | InvertedWedgeCompoundCoverage); + WedgeCompoundCoverage | InvertedWedgeCompoundCoverage, + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); ValidateInterPredictionSequenceWithConstrainedAllocator( TestImages.Heif.Av1DifferenceWeightedCompoundSequenceAvif, TestImages.Heif.Av1DifferenceWeightedCompoundSequenceNativeReference, - TestImages.Heif.Av1DifferenceWeightedCompoundSequencePresentationReference, - DifferenceWeightedCompoundCoverage | InvertedDifferenceWeightedCompoundCoverage); + DifferenceWeightedCompoundCoverage | InvertedDifferenceWeightedCompoundCoverage, + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); ValidateInterPredictionSequenceWithConstrainedAllocator( TestImages.Heif.Av1InterIntraSequenceAvif, TestImages.Heif.Av1InterIntraSequenceNativeReference, - TestImages.Heif.Av1InterIntraSequencePresentationReference, - SmoothInterIntraCoverage | WedgeInterIntraCoverage); + SmoothInterIntraCoverage | WedgeInterIntraCoverage, + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); } /// /// Verifies production OBMC reconstruction against pinned native and presentation references. /// - [Fact] - public void DecodeRealLibavifObmcSequenceMatchesPinnedReferences() + [Theory] + [WithFile(TestImages.Heif.Av1ObmcSequenceAvif, PixelTypes.Rgba32)] + public void DecodeRealLibavifObmcSequenceMatchesPinnedReferences(TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateObmcSequenceWithDefaultConfiguration, - ReconstructionConfigurations); + ReconstructionConfigurations, + provider); /// /// Verifies production OBMC reconstruction through a constrained allocator. @@ -1004,17 +1072,20 @@ public class Av1ReconstructionConformanceTests => ValidateInterPredictionSequenceWithConstrainedAllocator( TestImages.Heif.Av1ObmcSequenceAvif, TestImages.Heif.Av1ObmcSequenceNativeReference, - TestImages.Heif.Av1ObmcSequencePresentationReference, - ObmcCoverage); + ObmcCoverage, + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); /// /// Verifies production local warped-motion reconstruction against pinned native and presentation references. /// - [Fact] - public void DecodeRealLibavifLocalWarpSequenceMatchesPinnedReferences() + [Theory] + [WithFile(TestImages.Heif.Av1LocalWarpSequenceAvif, PixelTypes.Rgba32)] + public void DecodeRealLibavifLocalWarpSequenceMatchesPinnedReferences(TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateLocalWarpSequenceWithDefaultConfiguration, - ReconstructionConfigurations); + ReconstructionConfigurations, + provider); /// /// Verifies production local warped-motion reconstruction through a constrained allocator. @@ -1032,11 +1103,9 @@ public class Av1ReconstructionConformanceTests configuration, TestImages.Heif.Av1LocalWarpSequenceAvif, TestImages.Heif.Av1LocalWarpSequenceNativeReference, - TestImages.Heif.Av1LocalWarpSequencePresentationReference, LocalWarpCoverage, - comparePresentation: false, - fixtureSize: 256, - visibleFrameCount: 2); + 256, + 2); Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "RetainedMotionFieldEntry"); Assert.Contains(allocator.AllocationLog, request => request.ElementType.Name == "TemporalMotionFieldEntry"); @@ -1051,11 +1120,13 @@ public class Av1ReconstructionConformanceTests /// /// Verifies production non-translational global-motion reconstruction against pinned native and presentation references. /// - [Fact] - public void DecodeRealLibavifGlobalWarpSequenceMatchesPinnedReferences() + [Theory] + [WithFile(TestImages.Heif.Av1GlobalWarpSequenceAvif, PixelTypes.Rgba32)] + public void DecodeRealLibavifGlobalWarpSequenceMatchesPinnedReferences(TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateGlobalWarpSequenceWithDefaultConfiguration, - ReconstructionConfigurations); + ReconstructionConfigurations, + provider); /// /// Verifies production non-translational global-motion reconstruction through a constrained allocator. @@ -1066,10 +1137,9 @@ public class Av1ReconstructionConformanceTests => ValidateInterPredictionSequenceWithConstrainedAllocator( TestImages.Heif.Av1GlobalWarpSequenceAvif, TestImages.Heif.Av1GlobalWarpSequenceNativeReference, - TestImages.Heif.Av1GlobalWarpSequencePresentationReference, GlobalWarpCoverage, - fixtureSize: 256, - visibleFrameCount: 2); + 256, + 2); /// /// Verifies every intra prediction mode and the fixture's seven transform types against the official @@ -2103,10 +2173,9 @@ public class Av1ReconstructionConformanceTests private static void ValidateInterPredictionSequenceWithConstrainedAllocator( string imagePath, string nativeReferencePath, - string presentationReferencePath, int requiredCoverage, - int fixtureSize = AverageCompoundFixtureSize, - int visibleFrameCount = AverageCompoundFixtureFrameCount) + int fixtureSize, + int visibleFrameCount) { TestMemoryAllocator allocator = new() { BufferCapacityInBytes = 1_024 }; allocator.EnableNonThreadSafeLogging(); @@ -2117,9 +2186,7 @@ public class Av1ReconstructionConformanceTests configuration, imagePath, nativeReferencePath, - presentationReferencePath, requiredCoverage, - comparePresentation: false, fixtureSize, visibleFrameCount); @@ -2134,103 +2201,100 @@ public class Av1ReconstructionConformanceTests } /// - /// Runs every selectable compound fixture with exact final presentation comparison. + /// Runs one selectable compound fixture with exact native and final presentation comparisons. /// - private static void ValidateSelectableCompoundSequencesWithDefaultConfiguration() - => ValidateSelectableCompoundSequences(Configuration.Default, comparePresentation: true); + /// The serialized input provider and reference-output naming context. + private static void ValidateSelectableCompoundSequenceWithDefaultConfiguration(string providerDump) + { + TestImageProvider provider = + FeatureTestRunner.DeserializeForXunit>(providerDump); + + (string NativeReferencePath, int RequiredCoverage) expected = + provider.SourceFileOrDescription switch + { + TestImages.Heif.Av1DistanceWeightedCompoundSequenceAvif => + (TestImages.Heif.Av1DistanceWeightedCompoundSequenceNativeReference, DistanceWeightedCompoundCoverage), + TestImages.Heif.Av1WedgeCompoundSequenceAvif => + (TestImages.Heif.Av1WedgeCompoundSequenceNativeReference, WedgeCompoundCoverage | InvertedWedgeCompoundCoverage), + TestImages.Heif.Av1DifferenceWeightedCompoundSequenceAvif => + (TestImages.Heif.Av1DifferenceWeightedCompoundSequenceNativeReference, DifferenceWeightedCompoundCoverage | InvertedDifferenceWeightedCompoundCoverage), + TestImages.Heif.Av1InterIntraSequenceAvif => + (TestImages.Heif.Av1InterIntraSequenceNativeReference, SmoothInterIntraCoverage | WedgeInterIntraCoverage), + _ => throw new InvalidOperationException($"Unexpected selectable-compound fixture: {provider.SourceFileOrDescription}.") + }; + + ValidateInterPredictionSequence( + Configuration.Default, + provider.SourceFileOrDescription, + expected.NativeReferencePath, + expected.RequiredCoverage, + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); + + ValidateFinalSequencePresentation(providerDump); + } /// /// Runs the OBMC sequence with exact final presentation comparison. /// - private static void ValidateObmcSequenceWithDefaultConfiguration() - => ValidateInterPredictionSequence( + /// The serialized input provider and reference-output naming context. + private static void ValidateObmcSequenceWithDefaultConfiguration(string providerDump) + { + ValidateInterPredictionSequence( Configuration.Default, TestImages.Heif.Av1ObmcSequenceAvif, TestImages.Heif.Av1ObmcSequenceNativeReference, - TestImages.Heif.Av1ObmcSequencePresentationReference, ObmcCoverage, - comparePresentation: true); + AverageCompoundFixtureSize, + AverageCompoundFixtureFrameCount); + + ValidateFinalSequencePresentation(providerDump); + } /// /// Runs the local warped-motion sequence with exact final presentation comparison. /// - private static void ValidateLocalWarpSequenceWithDefaultConfiguration() - => ValidateInterPredictionSequence( + /// The serialized input provider and reference-output naming context. + private static void ValidateLocalWarpSequenceWithDefaultConfiguration(string providerDump) + { + ValidateInterPredictionSequence( Configuration.Default, TestImages.Heif.Av1LocalWarpSequenceAvif, TestImages.Heif.Av1LocalWarpSequenceNativeReference, - TestImages.Heif.Av1LocalWarpSequencePresentationReference, LocalWarpCoverage, - comparePresentation: true, - fixtureSize: 256, - visibleFrameCount: 2); + 256, + 2); + + ValidateFinalSequencePresentation(providerDump); + } /// /// Runs the non-translational global-motion sequence with exact final presentation comparison. /// - private static void ValidateGlobalWarpSequenceWithDefaultConfiguration() - => ValidateInterPredictionSequence( + /// The serialized input provider and reference-output naming context. + private static void ValidateGlobalWarpSequenceWithDefaultConfiguration(string providerDump) + { + ValidateInterPredictionSequence( Configuration.Default, TestImages.Heif.Av1GlobalWarpSequenceAvif, TestImages.Heif.Av1GlobalWarpSequenceNativeReference, - TestImages.Heif.Av1GlobalWarpSequencePresentationReference, GlobalWarpCoverage, - comparePresentation: true, - fixtureSize: 256, - visibleFrameCount: 2); - - /// - /// Validates every selectable compound fixture with the requested decoder configuration. - /// - /// The decoder configuration. - /// Whether to compare the final presented frame. - private static void ValidateSelectableCompoundSequences(Configuration configuration, bool comparePresentation) - { - ValidateInterPredictionSequence( - configuration, - TestImages.Heif.Av1DistanceWeightedCompoundSequenceAvif, - TestImages.Heif.Av1DistanceWeightedCompoundSequenceNativeReference, - TestImages.Heif.Av1DistanceWeightedCompoundSequencePresentationReference, - DistanceWeightedCompoundCoverage, - comparePresentation); - - ValidateInterPredictionSequence( - configuration, - TestImages.Heif.Av1WedgeCompoundSequenceAvif, - TestImages.Heif.Av1WedgeCompoundSequenceNativeReference, - TestImages.Heif.Av1WedgeCompoundSequencePresentationReference, - WedgeCompoundCoverage | InvertedWedgeCompoundCoverage, - comparePresentation); - - ValidateInterPredictionSequence( - configuration, - TestImages.Heif.Av1DifferenceWeightedCompoundSequenceAvif, - TestImages.Heif.Av1DifferenceWeightedCompoundSequenceNativeReference, - TestImages.Heif.Av1DifferenceWeightedCompoundSequencePresentationReference, - DifferenceWeightedCompoundCoverage | InvertedDifferenceWeightedCompoundCoverage, - comparePresentation); + 256, + 2); - ValidateInterPredictionSequence( - configuration, - TestImages.Heif.Av1InterIntraSequenceAvif, - TestImages.Heif.Av1InterIntraSequenceNativeReference, - TestImages.Heif.Av1InterIntraSequencePresentationReference, - SmoothInterIntraCoverage | WedgeInterIntraCoverage, - comparePresentation); + ValidateFinalSequencePresentation(providerDump); } /// - /// Decodes one complete retained-reference sequence and compares its final native and presented samples exactly. + /// Decodes one complete retained-reference sequence and compares its final native samples exactly. /// private static void ValidateInterPredictionSequence( Configuration configuration, string imagePath, string nativeReferencePath, - string presentationReferencePath, int requiredCoverage, - bool comparePresentation, - int fixtureSize = AverageCompoundFixtureSize, - int visibleFrameCount = AverageCompoundFixtureFrameCount) + int fixtureSize, + int visibleFrameCount) { byte[] fileBytes = TestFile.Create(imagePath).Bytes; byte[] referenceBytes = TestFile.Create(nativeReferencePath).Bytes; @@ -2248,15 +2312,11 @@ public class Av1ReconstructionConformanceTests nativeReference = nativeReference[frameHeader.Length..]; Assert.Equal(fixtureSize * fixtureSize * 3, nativeReference.Length); - using Image presentationReference = - Image.Load(TestFile.Create(presentationReferencePath).Bytes); - HeifSequence sequence = ParseImageSequence(fileBytes); HeifSequenceTrack track = sequence.ColorTrack; int coverage = 0; int decodedVisibleFrameCount = 0; bool nativeCompared = false; - bool presentationCompared = false; using Av1Decoder decoder = new(configuration); for (int sampleIndex = 0; sampleIndex < track.Samples.Length; sampleIndex++) @@ -2291,18 +2351,6 @@ public class Av1ReconstructionConformanceTests { AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); nativeCompared = true; - - if (comparePresentation) - { - ImageSimilarityReport report = - ImageComparer.Exact.CompareImagesOrFrames( - decodedVisibleFrameCount, - presentationReference.Frames.RootFrame, - frame); - - Assert.True(report.IsEmpty, report.ToString()); - presentationCompared = true; - } } decodedVisibleFrameCount++; @@ -2311,7 +2359,6 @@ public class Av1ReconstructionConformanceTests Assert.Equal(visibleFrameCount, decodedVisibleFrameCount); Assert.Equal(requiredCoverage, coverage & requiredCoverage); Assert.True(nativeCompared); - Assert.Equal(comparePresentation, presentationCompared); } /// @@ -2404,9 +2451,23 @@ public class Av1ReconstructionConformanceTests /// Verifies exact presented pixels for independently encoded lossless eight-, ten-, and twelve-bit AVIF images /// across the available vector widths and the scalar fallback. /// - [Fact] - public void DecodeLosslessMatchesPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateLosslessPresentedFixtures, PresentationConfigurations); + /// The AVIF input and matching reference-output naming context. + /// The expected public sample precision. + [Theory] + [WithFile(TestImages.Heif.Av1Lossless8BitAvif, PixelTypes.Rgba32, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Lossless10BitAvif, PixelTypes.Rgba32, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Lossless12BitAvif, PixelTypes.Rgba32, HeifBitDepth.Bit12)] + public void DecodeLosslessMatchesPinnedLibavifPresentation( + TestImageProvider provider, + HeifBitDepth bitDepth) + { + AssertPresentedMetadata(provider, LosslessFixtureWidth, LosslessFixtureHeight, bitDepth); + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); + } /// /// Verifies active normative super-resolution, chroma-width rounding, replicated edges, and exact native samples @@ -2420,9 +2481,27 @@ public class Av1ReconstructionConformanceTests /// Verifies exact presented pixels and public metadata for independently packaged eight-, ten-, and twelve-bit /// active-super-resolution AVIF images across the available vector widths and the scalar fallback. /// - [Fact] - public void DecodeWithSuperResolutionMatchesPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateSuperResolutionPresentedFixtures, PresentationConfigurations); + /// The AVIF input and matching reference-output naming context. + /// The expected presented width. + /// The expected presented height. + /// The expected public sample precision. + [Theory] + [WithFile(TestImages.Heif.Av1SuperResolution8BitAvif, PixelTypes.Rgba32, 768, 512, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1SuperResolution10BitAvif, PixelTypes.Rgba32, 1024, 428, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1SuperResolution12BitAvif, PixelTypes.Rgba32, 1024, 428, HeifBitDepth.Bit12)] + public void DecodeWithSuperResolutionMatchesPinnedLibavifPresentation( + TestImageProvider provider, + int width, + int height, + HeifBitDepth bitDepth) + { + AssertPresentedMetadata(provider, width, height, bitDepth); + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); + } /// /// Verifies active normative loop restoration and exact native samples against scalar libaom for independently @@ -2463,9 +2542,27 @@ public class Av1ReconstructionConformanceTests /// Verifies exact presented pixels and public metadata for independently encoded eight-, ten-, and twelve-bit /// active-restoration AVIF images across the available vector widths and the scalar fallback. /// - [Fact] - public void DecodeWithLoopRestorationMatchesPinnedLibavifPresentation() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(ValidateRestorationPresentedFixtures, PresentationConfigurations); + /// The AVIF input and matching reference-output naming context. + /// The expected presented width. + /// The expected presented height. + /// The expected public sample precision. + [Theory] + [WithFile(TestImages.Heif.Av1Restoration8BitAvif, PixelTypes.Rgba32, 768, 512, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.Av1Restoration10BitAvif, PixelTypes.Rgba32, 1024, 428, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Av1Restoration12BitAvif, PixelTypes.Rgba32, 1024, 428, HeifBitDepth.Bit12)] + public void DecodeWithLoopRestorationMatchesPinnedLibavifPresentation( + TestImageProvider provider, + int width, + int height, + HeifBitDepth bitDepth) + { + AssertPresentedMetadata(provider, width, height, bitDepth); + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidatePresentedFixture, + PresentationConfigurations, + provider); + } /// /// Verifies that the independently encoded AVIF presentation fixtures collectively select both restoration algorithms. @@ -2593,73 +2690,6 @@ public class Av1ReconstructionConformanceTests ObuSequenceProfile.Professional); } - /// - /// Validates every presented profile fixture under the hardware configuration selected by - /// . - /// - private static void ValidateProfilePresentedFixtures() - { - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile8BitMonochromeAvif, - TestImages.Heif.Av1Profile8BitMonochromePresentationReference, - HeifBitDepth.Bit8); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile8Bit420Avif, - TestImages.Heif.Av1Profile8Bit420PresentationReference, - HeifBitDepth.Bit8); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile8Bit422Avif, - TestImages.Heif.Av1Profile8Bit422PresentationReference, - HeifBitDepth.Bit8); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile8Bit444Avif, - TestImages.Heif.Av1Profile8Bit444PresentationReference, - HeifBitDepth.Bit8); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile10BitMonochromeAvif, - TestImages.Heif.Av1Profile10BitMonochromePresentationReference, - HeifBitDepth.Bit10); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile10Bit420Avif, - TestImages.Heif.Av1Profile10Bit420PresentationReference, - HeifBitDepth.Bit10); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile10Bit422Avif, - TestImages.Heif.Av1Profile10Bit422PresentationReference, - HeifBitDepth.Bit10); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile10Bit444Avif, - TestImages.Heif.Av1Profile10Bit444PresentationReference, - HeifBitDepth.Bit10); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile12BitMonochromeAvif, - TestImages.Heif.Av1Profile12BitMonochromePresentationReference, - HeifBitDepth.Bit12); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile12Bit420Avif, - TestImages.Heif.Av1Profile12Bit420PresentationReference, - HeifBitDepth.Bit12); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile12Bit422Avif, - TestImages.Heif.Av1Profile12Bit422PresentationReference, - HeifBitDepth.Bit12); - - ValidateProfilePresentedFixture( - TestImages.Heif.Av1Profile12Bit444Avif, - TestImages.Heif.Av1Profile12Bit444PresentationReference, - HeifBitDepth.Bit12); - } - /// /// Validates one independently encoded AVIF against its native Y4M reference and signaled sequence profile. /// @@ -2714,36 +2744,6 @@ public class Av1ReconstructionConformanceTests AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); } - /// - /// Validates the exact public presentation and metadata of one independently encoded AVIF profile fixture. - /// - /// The complete AVIF container. - /// The eight-bit RGBA output produced by the pinned scalar libavif decoder. - /// The expected public HEIF sample precision. - private static void ValidateProfilePresentedFixture(string imagePath, string referencePath, HeifBitDepth metadataBitDepth) - { - DecoderOptions options = new() { MaxFrames = 1 }; - byte[] imageBytes = TestFile.Create(imagePath).Bytes; - byte[] referenceBytes = TestFile.Create(referencePath).Bytes; - using Image image = Image.Load(options, imageBytes); - using Image reference = Image.Load(referenceBytes); - - Assert.Equal(ProfileFixtureWidth, image.Width); - Assert.Equal(ProfileFixtureHeight, image.Height); - Assert.Single(image.Frames); - - HeifMetadata metadata = image.Metadata.GetHeifMetadata(); - Assert.Equal(HeifCompressionMethod.Av1, metadata.CompressionMethod); - Assert.Equal(metadataBitDepth, metadata.BitDepth); - - CicpProfile colorProfile = Assert.IsType(image.Metadata.CicpProfile); - Assert.Equal(CicpColorPrimaries.ItuRBt709_6, colorProfile.ColorPrimaries); - Assert.Equal(CicpTransferCharacteristics.Iec61966_2_1, colorProfile.TransferCharacteristics); - Assert.Equal(CicpMatrixCoefficients.ItuRBt601_7_525, colorProfile.MatrixCoefficients); - Assert.True(colorProfile.FullRange); - ImageComparer.Exact.VerifySimilarity(reference, image); - } - /// /// Gets the Y4M chroma tags that encode one AV1 bit-depth and sampling-layout combination. /// @@ -2801,47 +2801,6 @@ public class Av1ReconstructionConformanceTests Av1ColorFormat.Yuv444); } - /// - /// Validates every active-CDEF presentation fixture under the hardware configuration selected by - /// . - /// - private static void ValidatePresentedFixtures() - { - ValidatePresentedFixture( - TestImages.Heif.Av1Cdef8BitAvif, - TestImages.Heif.Av1Cdef8BitPresentationReference, - 768, - 512, - HeifBitDepth.Bit8); - - ValidatePresentedFixture( - TestImages.Heif.Av1Cdef10BitAvif, - TestImages.Heif.Av1Cdef10BitPresentationReference, - 1024, - 428, - HeifBitDepth.Bit10); - - ValidatePresentedFixture( - TestImages.Heif.Av1Cdef12BitAvif, - TestImages.Heif.Av1Cdef12BitPresentationReference, - 1024, - 428, - HeifBitDepth.Bit12); - } - - /// - /// Validates the active-palette presentation fixture under the hardware configuration selected by - /// . - /// - private static void ValidatePalettePresentedFixture() - => ValidatePresentedFixture( - TestImages.Heif.Av1Palette8BitAvif, - TestImages.Heif.Av1Palette8BitPresentationReference, - 33, - 11, - HeifBitDepth.Bit8, - requirePalette: true); - /// /// Validates the active-palette native fixture under the hardware configuration selected by /// . @@ -2922,60 +2881,40 @@ public class Av1ReconstructionConformanceTests } /// - /// Validates every active intra-block-copy presentation fixture under the hardware configuration selected by - /// . + /// Runs the exact final-layer native and presentation comparisons with the default configuration. /// - private static void ValidateIntraBlockCopyPresentedFixtures() + /// The serialized AVIF input provider and reference-output naming context. + private static void ValidateProgressiveSingleReferenceFixtureWithDefaultConfiguration(string providerDump) { - ValidatePresentedFixture( - TestImages.Heif.Av1IntraBlockCopy8BitAvif, - TestImages.Heif.Av1IntraBlockCopy8BitPresentationReference, - 512, - 256, - HeifBitDepth.Bit8, - requireIntraBlockCopy: true); - - ValidatePresentedFixture( - TestImages.Heif.Av1IntraBlockCopy10BitAvif, - TestImages.Heif.Av1IntraBlockCopy10BitPresentationReference, - 512, - 256, - HeifBitDepth.Bit10, - requireIntraBlockCopy: true); - - ValidatePresentedFixture( - TestImages.Heif.Av1IntraBlockCopy12BitAvif, - TestImages.Heif.Av1IntraBlockCopy12BitPresentationReference, - 512, - 256, - HeifBitDepth.Bit12, - requireIntraBlockCopy: true); + ValidateProgressiveSingleReferenceFixture(Configuration.Default); + ValidatePresentedFixture(providerDump); } - /// - /// Runs the exact final-layer native and presentation comparisons with the default configuration. - /// - private static void ValidateProgressiveSingleReferenceFixtureWithDefaultConfiguration() - => ValidateProgressiveSingleReferenceFixture(Configuration.Default, verifyPresentation: true); - /// /// Runs the selected-spatial-layer native and presentation comparisons with the default configuration. /// - private static void ValidateSelectedProgressiveSpatialLayerWithDefaultConfiguration() - => ValidateSelectedProgressiveSpatialLayer(Configuration.Default); + /// The serialized selected-layer provider and reference-output naming context. + private static void ValidateSelectedProgressiveSpatialLayerWithDefaultConfiguration(string providerDump) + { + ValidateSelectedProgressiveSpatialLayer(Configuration.Default); + ValidatePresentedFixture(providerDump); + } /// /// Runs the exact scaled-reference native and presentation comparison with the default configuration. /// - private static void ValidateScaledReferenceFixtureWithDefaultConfiguration() - => ValidateScaledReferenceFixture(Configuration.Default, verifyPresentation: true); + /// The serialized AVIF input provider and reference-output naming context. + private static void ValidateScaledReferenceFixtureWithDefaultConfiguration(string providerDump) + { + ValidateScaledReferenceFixture(Configuration.Default); + ValidatePresentedFixture(providerDump); + } /// /// Verifies the genuine size-changing layered fixture with the requested allocator. /// /// The decoder configuration. - /// Whether to verify the public RGBA presentation. - private static void ValidateScaledReferenceFixture(Configuration configuration, bool verifyPresentation) + private static void ValidateScaledReferenceFixture(Configuration configuration) { byte[] payload = TestFile.Create(TestImages.Heif.Av1ScaledReferencePayload).Bytes; byte[] baseReferenceBytes = TestFile.Create(TestImages.Heif.Av1ScaledReferenceBaseNativeReference).Bytes; @@ -3085,23 +3024,6 @@ public class Av1ReconstructionConformanceTests Assert.NotEqual(0, intraBlockCount); Assert.NotEqual(0, skippedInterBlockCount); AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); - - if (!verifyPresentation) - { - return; - } - - DecoderOptions options = new() { Configuration = configuration, MaxFrames = 1 }; - byte[] imageBytes = TestFile.Create(TestImages.Heif.Av1ScaledReferenceAvif).Bytes; - byte[] presentationBytes = TestFile.Create(TestImages.Heif.Av1ScaledReferencePresentationReference).Bytes; - using Image image = Image.Load(options, imageBytes); - using Image presentationReference = Image.Load(presentationBytes); - - Assert.Equal(ScaledReferenceFixtureSize, image.Width); - Assert.Equal(ScaledReferenceFixtureSize, image.Height); - Assert.Single(image.Frames); - Assert.Equal(HeifBitDepth.Bit8, image.Metadata.GetHeifMetadata().BitDepth); - ImageComparer.Exact.VerifySimilarity(presentationReference, image); } /// @@ -3137,37 +3059,13 @@ public class Av1ReconstructionConformanceTests Assert.Equal(Av1ColorFormat.Yuv444, frameBuffer.ColorFormat); Assert.Equal(ObuFrameType.KeyFrame, Assert.IsType(decoder.FrameHeader).FrameType); AssertNativePlanesEqual(decoder, frameBuffer, nativeReference); - - DecoderOptions options = new() { Configuration = configuration, MaxFrames = 1 }; - byte[] imageBytes = TestFile.Create(TestImages.Heif.Av1ScaledReferenceSelectedLayerAvif).Bytes; - byte[] presentationBytes = - TestFile.Create(TestImages.Heif.Av1ScaledReferenceSelectedLayerPresentationReference).Bytes; - - byte[] finalPresentationBytes = - TestFile.Create(TestImages.Heif.Av1ScaledReferencePresentationReference).Bytes; - - using Image image = Image.Load(options, imageBytes); - using Image presentationReference = Image.Load(presentationBytes); - using Image finalPresentationReference = Image.Load(finalPresentationBytes); - - // HEIF presents a selected lower-resolution spatial layer at the item's ispe extent. Exact comparison with - // libavif therefore proves both layer selection and the required 40x40-to-80x80 presentation scaling. - Assert.Equal(ScaledReferenceFixtureSize, image.Width); - Assert.Equal(ScaledReferenceFixtureSize, image.Height); - Assert.Single(image.Frames); - Assert.Equal(HeifBitDepth.Bit8, image.Metadata.GetHeifMetadata().BitDepth); - ImageComparer.Exact.VerifySimilarity(presentationReference, image); - Assert.NotEmpty(ImageComparer.Exact.CompareImages(finalPresentationReference, image)); } /// /// Verifies the final dependent layer with the requested allocator. /// /// The decoder configuration. - /// Whether to verify the final public RGBA presentation. - private static void ValidateProgressiveSingleReferenceFixture( - Configuration configuration, - bool verifyPresentation) + private static void ValidateProgressiveSingleReferenceFixture(Configuration configuration) { byte[] payload = TestFile.Create(TestImages.Heif.Av1Progressive8BitPayload).Bytes; byte[] referenceBytes = TestFile.Create(TestImages.Heif.Av1Progressive8BitReference).Bytes; @@ -3249,25 +3147,17 @@ public class Av1ReconstructionConformanceTests Assert.NotEqual(0, interBlockCount); AssertNativePlanesEqual(decoder, frameBuffer, colorReference); - if (!verifyPresentation) - { - return; - } - DecoderOptions options = new() { Configuration = configuration, MaxFrames = 1 }; byte[] imageBytes = TestFile.Create(TestImages.Heif.Av1Progressive8BitAvif).Bytes; - byte[] presentationBytes = TestFile.Create(TestImages.Heif.Av1Progressive8BitPresentationReference).Bytes; using Image image = Image.Load(options, imageBytes); - using Image presentationReference = Image.Load(presentationBytes); Assert.Equal(ProgressiveFixtureWidth, image.Width); Assert.Equal(ProgressiveFixtureHeight, image.Height); Assert.Single(image.Frames); Assert.Equal(HeifBitDepth.Bit8, image.Metadata.GetHeifMetadata().BitDepth); - ImageComparer.Exact.VerifySimilarity(presentationReference, image); - // The complete PNG comparison already covers alpha, but compare the composed channel with the independent - // native auxiliary plane as well so a color-path agreement cannot conceal an alpha-item regression. + // The feature-runner wrapper compares the complete RGBA image through CompareToReferenceOutput. Bind the + // composed alpha channel to the independent native auxiliary plane here as separate codec evidence. for (int y = 0; y < ProgressiveFixtureHeight; y++) { Span imageRow = image.Frames.RootFrame.PixelBuffer.DangerousGetRowSpan(y); @@ -3332,34 +3222,6 @@ public class Av1ReconstructionConformanceTests Av1BitDepth.TwelveBit); } - /// - /// Validates every lossless presentation fixture under the hardware configuration selected by - /// . - /// - private static void ValidateLosslessPresentedFixtures() - { - ValidatePresentedFixture( - TestImages.Heif.Av1Lossless8BitAvif, - TestImages.Heif.Av1Lossless8BitPresentationReference, - LosslessFixtureWidth, - LosslessFixtureHeight, - HeifBitDepth.Bit8); - - ValidatePresentedFixture( - TestImages.Heif.Av1Lossless10BitAvif, - TestImages.Heif.Av1Lossless10BitPresentationReference, - LosslessFixtureWidth, - LosslessFixtureHeight, - HeifBitDepth.Bit10); - - ValidatePresentedFixture( - TestImages.Heif.Av1Lossless12BitAvif, - TestImages.Heif.Av1Lossless12BitPresentationReference, - LosslessFixtureWidth, - LosslessFixtureHeight, - HeifBitDepth.Bit12); - } - /// /// Validates every active super-resolution fixture under the hardware configuration selected by /// . @@ -3391,37 +3253,6 @@ public class Av1ReconstructionConformanceTests Av1ColorFormat.Yuv444); } - /// - /// Validates every active-super-resolution presentation fixture under the hardware configuration selected by - /// . - /// - private static void ValidateSuperResolutionPresentedFixtures() - { - ValidatePresentedFixture( - TestImages.Heif.Av1SuperResolution8BitAvif, - TestImages.Heif.Av1SuperResolution8BitPresentationReference, - 768, - 512, - HeifBitDepth.Bit8, - requireSuperResolution: true); - - ValidatePresentedFixture( - TestImages.Heif.Av1SuperResolution10BitAvif, - TestImages.Heif.Av1SuperResolution10BitPresentationReference, - 1024, - 428, - HeifBitDepth.Bit10, - requireSuperResolution: true); - - ValidatePresentedFixture( - TestImages.Heif.Av1SuperResolution12BitAvif, - TestImages.Heif.Av1SuperResolution12BitPresentationReference, - 1024, - 428, - HeifBitDepth.Bit12, - requireSuperResolution: true); - } - /// /// Validates every active loop-restoration fixture under the hardware configuration selected by /// . @@ -3497,34 +3328,6 @@ public class Av1ReconstructionConformanceTests Av1ColorFormat.Yuv444, requireSuperResolution: true); - /// - /// Validates every active-restoration presentation fixture under the hardware configuration selected by - /// . - /// - private static void ValidateRestorationPresentedFixtures() - { - ValidatePresentedFixture( - TestImages.Heif.Av1Restoration8BitAvif, - TestImages.Heif.Av1Restoration8BitPresentationReference, - 768, - 512, - HeifBitDepth.Bit8); - - ValidatePresentedFixture( - TestImages.Heif.Av1Restoration10BitAvif, - TestImages.Heif.Av1Restoration10BitPresentationReference, - 1024, - 428, - HeifBitDepth.Bit10); - - ValidatePresentedFixture( - TestImages.Heif.Av1Restoration12BitAvif, - TestImages.Heif.Av1Restoration12BitPresentationReference, - 1024, - 428, - HeifBitDepth.Bit12); - } - /// /// Validates every active film-grain fixture under the hardware configuration selected by /// . @@ -3954,55 +3757,57 @@ public class Av1ReconstructionConformanceTests } /// - /// Validates the exact public presentation of one independently encoded AVIF image against pinned scalar-libavif output. + /// Verifies the public dimensions, frame count, compression method, and sample precision of one AVIF input. /// - /// The complete AVIF container. - /// The eight-bit RGBA output produced by the pinned scalar libavif decoder. + /// The AVIF input provider. /// The expected displayed width. /// The expected displayed height. - /// The expected public HEIF sample precision. - /// Whether the AV1 item must upscale from a narrower coded frame. - /// Whether the AV1 item must select palette prediction for luma and chroma. - /// Whether the AV1 item must select intra-block-copy prediction. - private static void ValidatePresentedFixture( - string imagePath, - string referencePath, + /// The expected public HEIF sample precision. + private static void AssertPresentedMetadata( + TestImageProvider provider, int width, int height, - HeifBitDepth metadataBitDepth, - bool requireSuperResolution = false, - bool requirePalette = false, - bool requireIntraBlockCopy = false) + HeifBitDepth bitDepth) { - DecoderOptions options = new() { MaxFrames = 1 }; - byte[] imageBytes = TestFile.Create(imagePath).Bytes; - byte[] referenceBytes = TestFile.Create(referencePath).Bytes; - - if (requireSuperResolution) - { - AssertUsesSuperResolution(imageBytes); - } - - if (requirePalette) - { - AssertUsesPalette(imageBytes); - } - - if (requireIntraBlockCopy) - { - AssertUsesIntraBlockCopy(imageBytes); - } - - using Image image = Image.Load(options, imageBytes); - using Image reference = Image.Load(referenceBytes); - + using Image image = provider.GetImage(); Assert.Equal(width, image.Width); Assert.Equal(height, image.Height); Assert.Single(image.Frames); + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); Assert.Equal(HeifCompressionMethod.Av1, metadata.CompressionMethod); - Assert.Equal(metadataBitDepth, metadata.BitDepth); - ImageComparer.Exact.VerifySimilarity(reference, image); + Assert.Equal(bitDepth, metadata.BitDepth); + } + + /// + /// Compares one AVIF presentation with its retained output through the repository reference-image contract. + /// + /// The serialized input provider and reference-output naming context. + private static void ValidatePresentedFixture(string providerDump) + { + TestImageProvider provider = + FeatureTestRunner.DeserializeForXunit>(providerDump); + + using Image image = provider.GetImage(); + image.DebugSave(provider); + + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + + /// + /// Compares the final visible frame of one AVIF sequence through the repository reference-image contract. + /// + /// The serialized input provider and reference-output naming context. + private static void ValidateFinalSequencePresentation(string providerDump) + { + TestImageProvider provider = + FeatureTestRunner.DeserializeForXunit>(providerDump); + + using Image sequence = provider.GetImage(); + using Image finalFrame = sequence.Frames.CloneFrame(sequence.Frames.Count - 1); + finalFrame.DebugSave(provider); + + finalFrame.CompareToReferenceOutput(ImageComparer.Exact, provider); } /// diff --git a/tests/ImageSharp.Tests/Formats/Heif/HeifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Heif/HeifDecoderTests.cs index eb1ecaa6e..5c4f6cc05 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/HeifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/HeifDecoderTests.cs @@ -99,135 +99,142 @@ public class HeifDecoderTests /// /// Verifies genuine HEIC presentation for the official HEVC profile and Range Extensions matrix against - /// independently decoded FFmpeg output. + /// independently pinned presentation references. /// - /// The retained official elementary-stream path used to derive the HEIC and reference paths. + /// The genuine HEIC input and matching reference-output naming context. /// The independently reported presented width. /// The independently reported presented height. /// The maximum coded component precision. [Theory] - [InlineData(TestImages.Heif.General8Bit420, 400, 384, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.General8Bit444, 400, 384, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.General10Bit420, 400, 384, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.General10Bit422, 400, 384, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.General10Bit444, 400, 384, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.General12Bit420, 400, 384, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.General12Bit422, 400, 384, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.General12Bit444, 400, 384, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.RangeExtensionChromaAngle422, 1920, 1080, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.RangeExtensionCrossComponent8Bit444, 1280, 720, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.RangeExtensionCrossComponent10Bit444, 1920, 1080, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.RangeExtensionCrossComponent12Bit444, 2560, 1600, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.ExtendedPrecision8Bit444, 400, 384, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.ExtendedPrecision10Bit444, 400, 384, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.ExtendedPrecision12Bit444, 400, 384, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.RangeExtensionPcm10Bit422, 416, 240, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.RangeExtensionPcm12Bit444, 416, 240, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.PersistentRice12Bit444, 400, 384, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.TransformSkipContext8Bit444, 1920, 1080, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.TransformSkipContext10Bit444, 1920, 1080, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.TransformSkipContext12Bit444, 2560, 1600, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.Main42210A, 1920, 1080, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.Main42210B, 2560, 1600, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.HighThroughput8Bit420Wavefront, 1024, 768, HeifBitDepth.Bit8)] - public void DecodeHevcRangeExtensionStillImageMatchesFfmpeg( - string bitstreamPath, + [WithFile(TestImages.Heif.General8Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.General10Bit420Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.General10Bit422Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.General10Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.General12Bit420Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.General12Bit422Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.General12Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.RangeExtensionChromaAngle422Heic, PixelTypes.Rgba32, 1920, 1080, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.RangeExtensionCrossComponent8Bit444Heic, PixelTypes.Rgba32, 1280, 720, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.RangeExtensionCrossComponent10Bit444Heic, PixelTypes.Rgba32, 1920, 1080, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.RangeExtensionCrossComponent12Bit444Heic, PixelTypes.Rgba32, 2560, 1600, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.ExtendedPrecision8Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.ExtendedPrecision10Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.ExtendedPrecision12Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.RangeExtensionPcm10Bit422Heic, PixelTypes.Rgba32, 416, 240, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.RangeExtensionPcm12Bit444Heic, PixelTypes.Rgba32, 416, 240, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.PersistentRice12Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.TransformSkipContext8Bit444Heic, PixelTypes.Rgba32, 1920, 1080, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.TransformSkipContext10Bit444Heic, PixelTypes.Rgba32, 1920, 1080, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.TransformSkipContext12Bit444Heic, PixelTypes.Rgba32, 2560, 1600, HeifBitDepth.Bit12)] + [WithFile(TestImages.Heif.Main42210AHeic, PixelTypes.Rgba32, 1920, 1080, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.Main42210BHeic, PixelTypes.Rgba32, 2560, 1600, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.HighThroughput8Bit420WavefrontHeic, PixelTypes.Rgba32, 1024, 768, HeifBitDepth.Bit8)] + public void DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation( + TestImageProvider provider, int width, int height, HeifBitDepth bitDepth) { - string heicPath = $"{bitstreamPath[..^4]}.heic"; - string referencePath = $"{bitstreamPath[..^4]}-ffmpeg.png"; - using Image expected = TestFile.Create(referencePath).CreateRgba32Image(); - using Image actual = TestFile.Create(heicPath).CreateRgba32Image(); - HeifMetadata metadata = actual.Metadata.GetHeifMetadata(); + using Image image = provider.GetImage(); + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); + image.DebugSave(provider); - // HEVC leaves the chroma upsampling filter implementation-defined. The per-pixel threshold absorbs - // rounding-scale filter differences while the exact native-plane tests continue to prove reconstruction. - ImageComparer.TolerantPercentage(1F, 20).VerifySimilarity(expected, actual); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); - Assert.Equal(new Size(width, height), actual.Size); + Assert.Equal(new Size(width, height), image.Size); Assert.Equal(HeifCompressionMethod.Hevc, metadata.CompressionMethod); Assert.Equal(bitDepth, metadata.BitDepth); - Assert.Null(actual.Metadata.IccProfile); + Assert.Null(image.Metadata.IccProfile); } /// - /// Verifies genuine monochrome HEIC presentation against FFmpeg presentation derived from official native output. + /// Verifies genuine monochrome HEIC presentation against pinned libheif output. /// - /// The retained official elementary-stream path used to derive the HEIC and reference paths. + /// The image provider. /// The coded luma precision. [Theory] - [InlineData(TestImages.Heif.General8BitMonochrome, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.General12BitMonochrome, HeifBitDepth.Bit12)] - public void DecodeHevcMonochromeStillImageMatchesHmFfmpeg(string bitstreamPath, HeifBitDepth bitDepth) + [WithFile(TestImages.Heif.General8BitMonochromeHeic, PixelTypes.Rgba32, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.General12BitMonochromeHeic, PixelTypes.Rgba32, HeifBitDepth.Bit12)] + public void DecodeHevcMonochromeStillImageMatchesPinnedLibheif( + TestImageProvider provider, + HeifBitDepth bitDepth) { - string heicPath = $"{bitstreamPath[..^4]}.heic"; - string referencePath = $"{bitstreamPath[..^4]}-hm-ffmpeg.png"; - using Image expected = TestFile.Create(referencePath).CreateRgba32Image(); - using Image actual = TestFile.Create(heicPath).CreateRgba32Image(); - HeifMetadata metadata = actual.Metadata.GetHeifMetadata(); + using Image image = provider.GetImage(); + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); + image.DebugSave(provider); - // The reference explicitly expands the limited-range official luma samples before RGB packing. The exact - // published luma-plane comparison remains responsible for proving HEVC reconstruction. - ImageComparer.TolerantPercentage(1F, 20).VerifySimilarity(expected, actual); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); - Assert.Equal(new Size(400, 384), actual.Size); + Assert.Equal(new Size(400, 384), image.Size); Assert.Equal(HeifCompressionMethod.Hevc, metadata.CompressionMethod); Assert.Equal(bitDepth, metadata.BitDepth); - Assert.Null(actual.Metadata.IccProfile); + Assert.Null(image.Metadata.IccProfile); + } + + /// + /// Verifies that high-bit-depth monochrome HEIC presentation preserves its source precision. + /// + /// The image provider. + [Theory] + [WithFile(TestImages.Heif.General12BitMonochromeHeic, PixelTypes.Rgba64)] + public void DecodeHevcMonochromeHighBitDepthPreservesSourcePrecision(TestImageProvider provider) + { + using Image image = provider.GetImage(); + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); + image.DebugSave(provider); + + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + + Assert.Equal(new Size(400, 384), image.Size); + Assert.Equal(HeifCompressionMethod.Hevc, metadata.CompressionMethod); + Assert.Equal(HeifBitDepth.Bit12, metadata.BitDepth); + Assert.Null(image.Metadata.IccProfile); } /// /// Verifies genuine HEIC presentation for the official high-throughput Range Extensions streams against - /// FFmpeg presentation derived from pinned HM reference-decoder output. + /// independently pinned presentation references. /// - /// The retained official elementary-stream path used to derive the HEIC and reference paths. + /// The genuine HEIC input and matching reference-output naming context. /// The independently reported presented width. /// The independently reported presented height. /// The maximum coded component precision. [Theory] - [InlineData(TestImages.Heif.HighThroughputExtendedPrecision8Bit444, 400, 384, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.HighThroughputExtendedPrecision10Bit444, 400, 384, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.HighThroughputExtendedPrecision12Bit444, 400, 384, HeifBitDepth.Bit12)] - [InlineData(TestImages.Heif.HighThroughput10Bit422TilesWavefront, 1920, 1080, HeifBitDepth.Bit10)] - [InlineData(TestImages.Heif.HighThroughput8Bit420TilesWavefront, 1024, 768, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.HighThroughput8Bit420CabacBypassAlignment, 1024, 768, HeifBitDepth.Bit8)] - [InlineData(TestImages.Heif.HighThroughput8Bit420ExtendedPrecision, 1024, 768, HeifBitDepth.Bit8)] - public void DecodeHevcHighThroughputStillImageMatchesHmFfmpeg( - string bitstreamPath, + [WithFile(TestImages.Heif.HighThroughputExtendedPrecision8Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.HighThroughputExtendedPrecision10Bit444Heic, PixelTypes.Rgba32, 400, 384, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.HighThroughput10Bit422TilesWavefrontHeic, PixelTypes.Rgba32, 1920, 1080, HeifBitDepth.Bit10)] + [WithFile(TestImages.Heif.HighThroughput8Bit420TilesWavefrontHeic, PixelTypes.Rgba32, 1024, 768, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.HighThroughput8Bit420CabacBypassAlignmentHeic, PixelTypes.Rgba32, 1024, 768, HeifBitDepth.Bit8)] + [WithFile(TestImages.Heif.HighThroughput8Bit420ExtendedPrecisionHeic, PixelTypes.Rgba32, 1024, 768, HeifBitDepth.Bit8)] + public void DecodeHevcHighThroughputStillImageMatchesPinnedPresentation( + TestImageProvider provider, int width, int height, HeifBitDepth bitDepth) { - string heicPath = $"{bitstreamPath[..^4]}.heic"; - string referencePath = $"{bitstreamPath[..^4]}-hm-ffmpeg.png"; - using Image expected = TestFile.Create(referencePath).CreateRgba32Image(); - using Image actual = TestFile.Create(heicPath).CreateRgba32Image(); - HeifMetadata metadata = actual.Metadata.GetHeifMetadata(); + using Image image = provider.GetImage(); + HeifMetadata metadata = image.Metadata.GetHeifMetadata(); + image.DebugSave(provider); - // The HM native outputs match the published plane digests, and the matching ImageSharp tests prove exact - // reconstruction. This comparison therefore isolates the shared color-presentation path. - ImageComparer.TolerantPercentage(1F, 20).VerifySimilarity(expected, actual); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); - Assert.Equal(new Size(width, height), actual.Size); + Assert.Equal(new Size(width, height), image.Size); Assert.Equal(HeifCompressionMethod.Hevc, metadata.CompressionMethod); Assert.Equal(bitDepth, metadata.BitDepth); - Assert.Null(actual.Metadata.IccProfile); + Assert.Null(image.Metadata.IccProfile); } /// /// Verifies genuine HEIC presentation for unequal luma and chroma precision, which independent HEIF decoders /// currently reject after reconstructing the native planes. /// - /// The retained official elementary-stream path used to derive the HEIC path. + /// The retained genuine HEIC input. [Theory] - [InlineData(TestImages.Heif.RangeExtensionLuma12Chroma8)] - [InlineData(TestImages.Heif.RangeExtensionLuma8Chroma12)] - public void DecodeHevcRangeExtensionUnequalBitDepthStillImage(string bitstreamPath) + [WithFile(TestImages.Heif.RangeExtensionLuma12Chroma8Heic, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.RangeExtensionLuma8Chroma12Heic, PixelTypes.Rgba32)] + public void DecodeHevcRangeExtensionUnequalBitDepthStillImage(TestImageProvider provider) { - string heicPath = $"{bitstreamPath[..^4]}.heic"; - using Image image = TestFile.Create(heicPath).CreateRgba32Image(); + using Image image = provider.GetImage(); HeifMetadata metadata = image.Metadata.GetHeifMetadata(); Assert.Equal(new Size(1920, 1080), image.Size); @@ -240,36 +247,29 @@ public class HeifDecoderTests /// Verifies representative genuine HEIC Range Extensions presentation with allocator-split buffers and /// exactly-once final disposal. /// - /// The retained official elementary-stream path used to derive the HEIC and reference paths. - /// The suffix identifying the independently produced presentation reference. + /// The genuine HEIC input and allocator configuration. /// The independently reported presented width. /// The independently reported presented height. [Theory] - [InlineData(TestImages.Heif.General8Bit420, "-ffmpeg.png", 400, 384)] - [InlineData(TestImages.Heif.General10Bit422, "-ffmpeg.png", 400, 384)] - [InlineData(TestImages.Heif.General12Bit444, "-ffmpeg.png", 400, 384)] - [InlineData(TestImages.Heif.General12BitMonochrome, "-hm-ffmpeg.png", 400, 384)] - [InlineData(TestImages.Heif.HighThroughput8Bit420ExtendedPrecision, "-hm-ffmpeg.png", 1024, 768)] + [WithFile(TestImages.Heif.General8Bit420Heic, PixelTypes.Rgba32, 400, 384)] + [WithFile(TestImages.Heif.General10Bit422Heic, PixelTypes.Rgba32, 400, 384)] + [WithFile(TestImages.Heif.General12Bit444Heic, PixelTypes.Rgba32, 400, 384)] + [WithFile(TestImages.Heif.General12BitMonochromeHeic, PixelTypes.Rgba32, 400, 384)] + [WithFile(TestImages.Heif.HighThroughput8Bit420ExtendedPrecisionHeic, PixelTypes.Rgba32, 1024, 768)] public void DecodeHevcRangeExtensionStillImageWithConstrainedAllocator( - string bitstreamPath, - string referenceSuffix, + TestImageProvider provider, int width, int height) { - string heicPath = $"{bitstreamPath[..^4]}.heic"; - string referencePath = $"{bitstreamPath[..^4]}{referenceSuffix}"; - byte[] imageBytes = TestFile.Create(heicPath).Bytes; TestMemoryAllocator allocator = new() { BufferCapacityInBytes = 4_096 }; allocator.EnableNonThreadSafeLogging(); Configuration configuration = Configuration.Default.Clone(); configuration.MemoryAllocator = allocator; - DecoderOptions options = new() { Configuration = configuration }; + provider.Configuration = configuration; - using (Image expected = TestFile.Create(referencePath).CreateRgba32Image()) - using (Image actual = Image.Load(options, imageBytes)) + using (Image image = provider.GetImage()) { - Assert.Equal(new Size(width, height), actual.Size); - ImageComparer.TolerantPercentage(1F, 20).VerifySimilarity(expected, actual); + Assert.Equal(new Size(width, height), image.Size); } Assert.NotEmpty(allocator.AllocationLog); @@ -286,25 +286,63 @@ public class HeifDecoderTests /// Verifies representative eight-bit subsampled and high-bit-depth full-resolution presentation through every /// available vector width and the scalar fallback. /// - [Fact] - public void DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths() + /// The genuine HEIC input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.General8Bit420Heic, PixelTypes.Rgba32)] + [WithFile(TestImages.Heif.HighThroughputExtendedPrecision12Bit444Heic, PixelTypes.Rgba32)] + public void DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths( + TestImageProvider provider) => FeatureTestRunner.RunWithHwIntrinsicsFeature( ValidateHevcRangeExtensionPresentation, - HevcPresentationConfigurations); + HevcPresentationConfigurations, + provider); + + /// + /// Verifies high-bit-depth HEVC presentation precision through every available vector width and the scalar fallback. + /// + /// The genuine HEIC input and matching reference-output naming context. + [Theory] + [WithFile(TestImages.Heif.General12Bit444Heic, PixelTypes.Rgba64)] + public void DecodeHevcHighBitDepthPresentationPreservesPrecisionAcrossIntrinsicWidths( + TestImageProvider provider) + { + using Image image = provider.GetImage(); + image.DebugSave(provider); + + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + ValidateHevcHighBitDepthPresentation, + HevcPresentationConfigurations, + provider); + } - private static void ValidateHevcRangeExtensionPresentation() + /// + /// Verifies one HEVC presentation with the feature-runner configuration and the repository reference API. + /// + /// The serialized input provider and reference-output naming context. + private static void ValidateHevcRangeExtensionPresentation(string providerDump) { - string subsampledPath = TestImages.Heif.General8Bit420[..^4]; - using Image subsampledExpected = TestFile.Create($"{subsampledPath}-ffmpeg.png").CreateRgba32Image(); - using Image subsampledActual = TestFile.Create($"{subsampledPath}.heic").CreateRgba32Image(); + TestImageProvider provider = + FeatureTestRunner.DeserializeForXunit>(providerDump); - ImageComparer.TolerantPercentage(1F, 20).VerifySimilarity(subsampledExpected, subsampledActual); + using Image image = provider.GetImage(); + image.DebugSave(provider); - string fullResolutionPath = TestImages.Heif.HighThroughputExtendedPrecision12Bit444[..^4]; - using Image fullResolutionExpected = TestFile.Create($"{fullResolutionPath}-hm-ffmpeg.png").CreateRgba32Image(); - using Image fullResolutionActual = TestFile.Create($"{fullResolutionPath}.heic").CreateRgba32Image(); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + + /// + /// Verifies one high-bit-depth HEVC presentation with the feature-runner configuration and the repository reference API. + /// + /// The serialized input provider and reference-output naming context. + private static void ValidateHevcHighBitDepthPresentation(string providerDump) + { + TestImageProvider provider = + FeatureTestRunner.DeserializeForXunit>(providerDump); - ImageComparer.TolerantPercentage(1F, 20).VerifySimilarity(fullResolutionExpected, fullResolutionActual); + using Image image = provider.GetImage(); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } /// diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index af2b51da4..ba4d6a84d 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1304,12 +1304,28 @@ public static class TestImages public const string General12Bit420 = "Heif/Hevc/Conformance/GENERAL_12b_420_RExt_Sony_1.bit"; public const string General12Bit422 = "Heif/Hevc/Conformance/GENERAL_12b_422_RExt_Sony_1.bit"; public const string General12Bit444 = "Heif/Hevc/Conformance/GENERAL_12b_444_RExt_Sony_2.bit"; + public const string General8BitMonochromeHeic = "Heif/Hevc/Conformance/GENERAL_8b_400_RExt_Sony_1.heic"; + public const string General8Bit420Heic = "Heif/Hevc/Conformance/GENERAL_8b_420_RExt_Sony_1.heic"; + public const string General8Bit444Heic = "Heif/Hevc/Conformance/GENERAL_8b_444_RExt_Sony_2.heic"; + public const string General10Bit420Heic = "Heif/Hevc/Conformance/GENERAL_10b_420_RExt_Sony_1.heic"; + public const string General10Bit422Heic = "Heif/Hevc/Conformance/GENERAL_10b_422_RExt_Sony_1.heic"; + public const string General10Bit444Heic = "Heif/Hevc/Conformance/GENERAL_10b_444_RExt_Sony_2.heic"; + public const string General12BitMonochromeHeic = "Heif/Hevc/Conformance/GENERAL_12b_400_RExt_Sony_1.heic"; + public const string General12Bit420Heic = "Heif/Hevc/Conformance/GENERAL_12b_420_RExt_Sony_1.heic"; + public const string General12Bit422Heic = "Heif/Hevc/Conformance/GENERAL_12b_422_RExt_Sony_1.heic"; + public const string General12Bit444Heic = "Heif/Hevc/Conformance/GENERAL_12b_444_RExt_Sony_2.heic"; public const string RangeExtensionChromaAngle422 = "Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.bit"; public const string RangeExtensionCrossComponent8Bit444 = "Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0.bit"; public const string RangeExtensionCrossComponent10Bit444 = "Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0.bit"; public const string RangeExtensionCrossComponent12Bit444 = "Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0.bit"; public const string RangeExtensionLuma12Chroma8 = "Heif/Hevc/Conformance/Bitdepth_A_RExt_Sony_1_frame0.bit"; public const string RangeExtensionLuma8Chroma12 = "Heif/Hevc/Conformance/Bitdepth_B_RExt_Sony_1_frame0.bit"; + public const string RangeExtensionChromaAngle422Heic = "Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.heic"; + public const string RangeExtensionCrossComponent8Bit444Heic = "Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0.heic"; + public const string RangeExtensionCrossComponent10Bit444Heic = "Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0.heic"; + public const string RangeExtensionCrossComponent12Bit444Heic = "Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0.heic"; + public const string RangeExtensionLuma12Chroma8Heic = "Heif/Hevc/Conformance/Bitdepth_A_RExt_Sony_1_frame0.heic"; + public const string RangeExtensionLuma8Chroma12Heic = "Heif/Hevc/Conformance/Bitdepth_B_RExt_Sony_1_frame0.heic"; public const string ExtendedPrecision8Bit444 = "Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit"; public const string ExtendedPrecision10Bit444 = "Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit"; public const string HighThroughputExtendedPrecision8Bit444 = "Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit"; @@ -1328,11 +1344,30 @@ public static class TestImages public const string HighThroughput8Bit420Wavefront = "Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit"; public const string HighThroughput8Bit420CabacBypassAlignment = "Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit"; public const string HighThroughput8Bit420ExtendedPrecision = "Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit"; + public const string ExtendedPrecision8Bit444Heic = "Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.heic"; + public const string ExtendedPrecision10Bit444Heic = "Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.heic"; + public const string HighThroughputExtendedPrecision8Bit444Heic = "Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.heic"; + public const string HighThroughputExtendedPrecision10Bit444Heic = "Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.heic"; + public const string HighThroughputExtendedPrecision12Bit444Heic = "Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.heic"; + public const string RangeExtensionPcm10Bit422Heic = "Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0.heic"; + public const string RangeExtensionPcm12Bit444Heic = "Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0.heic"; + public const string PersistentRice12Bit444Heic = "Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0.heic"; + public const string TransformSkipContext8Bit444Heic = "Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0.heic"; + public const string TransformSkipContext10Bit444Heic = "Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0.heic"; + public const string TransformSkipContext12Bit444Heic = "Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0.heic"; + public const string Main42210AHeic = "Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0.heic"; + public const string Main42210BHeic = "Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0.heic"; + public const string HighThroughput10Bit422TilesWavefrontHeic = "Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.heic"; + public const string HighThroughput8Bit420TilesWavefrontHeic = "Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.heic"; + public const string HighThroughput8Bit420WavefrontHeic = "Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.heic"; + public const string HighThroughput8Bit420CabacBypassAlignmentHeic = "Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.heic"; + public const string HighThroughput8Bit420ExtendedPrecisionHeic = "Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.heic"; public const string IntraPredictionB = "Heif/Hevc/Conformance/IPRED_B_Nokia_3.bit"; public const string IntraPredictionBReference = "Heif/Hevc/Conformance/IPRED_B_Nokia_3.yuv"; public const string ConstrainedIntraPredictionA = "Heif/Hevc/Conformance/CIP_A_Panasonic_3.bit"; public const string DeltaQuantizationParameterA = "Heif/Hevc/Conformance/DELTAQP_A_BRCM_4_frame0.bit"; public const string ExtendedPrecision12Bit444 = "Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.bit"; + public const string ExtendedPrecision12Bit444Heic = "Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.heic"; public const string ChromaQuantizationAdjustment12Bit444 = "Heif/Hevc/Conformance/GENERAL_12b_444_RExt_Sony_2_idr7.bit"; public const string LosslessA = "Heif/Hevc/Conformance/LS_A_Orange_2.bit"; public const string QuantizationMatrixA = "Heif/Hevc/Conformance/QMATRIX_A_RExt_Sony_1.bit"; @@ -1413,38 +1448,27 @@ public static class TestImages public const string Av1Progressive8BitAvif = "Heif/Av1/Conformance/libavif-progressive-draw-points-8b.avif"; public const string Av1Progressive8BitPayload = "Heif/Av1/Conformance/libavif-progressive-draw-points-8b.bit"; public const string Av1Progressive8BitReference = "Heif/Av1/Conformance/libavif-progressive-draw-points-8b-libaom-y4m.yuv"; - public const string Av1Progressive8BitPresentationReference = "Heif/Av1/Conformance/libavif-progressive-draw-points-8b.png"; public const string Av1ScaledReferenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference.avif"; public const string Av1ScaledReferenceSelectedLayerAvif = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference-lsel0.avif"; public const string Av1ScaledReferencePayload = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference.bit"; public const string Av1ScaledReferenceBaseNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference-base-libaom.yuv"; public const string Av1ScaledReferenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference-libaom.y4m"; - public const string Av1ScaledReferencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference.png"; - public const string Av1ScaledReferenceSelectedLayerPresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-scaled-reference-lsel0-libavif.png"; public const string Av1AverageCompoundSequenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-average-compound.avif"; public const string Av1AverageCompoundSequenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-average-compound-libaom.y4m"; - public const string Av1AverageCompoundSequencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-average-compound-libavif.png"; public const string Av1DistanceWeightedCompoundSequenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-distance-weighted-compound.avif"; public const string Av1DistanceWeightedCompoundSequenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-distance-weighted-compound-libaom.y4m"; - public const string Av1DistanceWeightedCompoundSequencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-distance-weighted-compound-libavif.png"; public const string Av1WedgeCompoundSequenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-wedge-compound.avif"; public const string Av1WedgeCompoundSequenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-wedge-compound-libaom.y4m"; - public const string Av1WedgeCompoundSequencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-wedge-compound-libavif.png"; public const string Av1DifferenceWeightedCompoundSequenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-difference-weighted-compound.avif"; public const string Av1DifferenceWeightedCompoundSequenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-difference-weighted-compound-libaom.y4m"; - public const string Av1DifferenceWeightedCompoundSequencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-difference-weighted-compound-libavif.png"; public const string Av1InterIntraSequenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-inter-intra.avif"; public const string Av1InterIntraSequenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-inter-intra-libaom.y4m"; - public const string Av1InterIntraSequencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-inter-intra-libavif.png"; public const string Av1ObmcSequenceAvif = "Heif/Av1/Conformance/libavif-webp-logo-obmc.avif"; public const string Av1ObmcSequenceNativeReference = "Heif/Av1/Conformance/libavif-webp-logo-obmc-libaom.y4m"; - public const string Av1ObmcSequencePresentationReference = "Heif/Av1/Conformance/libavif-webp-logo-obmc-libavif.png"; 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 Av1OfficialAllIntraSequence = "Heif/Av1/Conformance/libaom-av1-1-b8-02-allintra.ivf"; public const string Av1OfficialAllIntraSequenceNativeReference = "Heif/Av1/Conformance/libaom-av1-1-b8-02-allintra-libaom.y4m"; public const string Av1OfficialEightBitMinimumQuantizerSequence = "Heif/Av1/Conformance/libaom-av1-1-b8-00-quantizer-00.ivf"; @@ -1488,97 +1512,69 @@ public static class TestImages 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"; - public const string Av1Cdef8BitPresentationReference = "Heif/Av1/Conformance/libavif-cdef-kodim23-8b.png"; public const string Av1Cdef10BitPayload = "Heif/Av1/Conformance/libaom-cdef-cosmos-10b.bit"; public const string Av1Cdef10BitReference = "Heif/Av1/Conformance/libaom-cdef-cosmos-10b-libaom.yuv"; public const string Av1Cdef10BitAvif = "Heif/Av1/Conformance/libavif-cdef-cosmos-10b.avif"; - public const string Av1Cdef10BitPresentationReference = "Heif/Av1/Conformance/libavif-cdef-cosmos-10b.png"; public const string Av1Cdef12BitPayload = "Heif/Av1/Conformance/libaom-cdef-cosmos-12b.bit"; public const string Av1Cdef12BitReference = "Heif/Av1/Conformance/libaom-cdef-cosmos-12b-libaom.yuv"; public const string Av1Cdef12BitAvif = "Heif/Av1/Conformance/libavif-cdef-cosmos-12b.avif"; - public const string Av1Cdef12BitPresentationReference = "Heif/Av1/Conformance/libavif-cdef-cosmos-12b.png"; public const string Av1Profile8BitMonochromeAvif = "Heif/Av1/Conformance/libavif-profile-8b-400.avif"; public const string Av1Profile8BitMonochromeReference = "Heif/Av1/Conformance/libavif-profile-8b-400-libaom-y4m.yuv"; - public const string Av1Profile8BitMonochromePresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-400.png"; public const string Av1Profile8Bit420Avif = "Heif/Av1/Conformance/libavif-profile-8b-420.avif"; public const string Av1Profile8Bit420Reference = "Heif/Av1/Conformance/libavif-profile-8b-420-libaom-y4m.yuv"; - public const string Av1Profile8Bit420PresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-420.png"; public const string Av1Profile8Bit422Avif = "Heif/Av1/Conformance/libavif-profile-8b-422.avif"; public const string Av1Profile8Bit422Reference = "Heif/Av1/Conformance/libavif-profile-8b-422-libaom-y4m.yuv"; - public const string Av1Profile8Bit422PresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-422.png"; public const string Av1Profile8Bit444Avif = "Heif/Av1/Conformance/libavif-profile-8b-444.avif"; public const string Av1Profile8Bit444Reference = "Heif/Av1/Conformance/libavif-profile-8b-444-libaom-y4m.yuv"; - public const string Av1Profile8Bit444PresentationReference = "Heif/Av1/Conformance/libavif-profile-8b-444.png"; public const string Av1Profile10BitMonochromeAvif = "Heif/Av1/Conformance/libavif-profile-10b-400.avif"; public const string Av1Profile10BitMonochromeReference = "Heif/Av1/Conformance/libavif-profile-10b-400-libaom-y4m.yuv"; - public const string Av1Profile10BitMonochromePresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-400.png"; public const string Av1Profile10Bit420Avif = "Heif/Av1/Conformance/libavif-profile-10b-420.avif"; public const string Av1Profile10Bit420Reference = "Heif/Av1/Conformance/libavif-profile-10b-420-libaom-y4m.yuv"; - public const string Av1Profile10Bit420PresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-420.png"; public const string Av1Profile10Bit422Avif = "Heif/Av1/Conformance/libavif-profile-10b-422.avif"; public const string Av1Profile10Bit422Reference = "Heif/Av1/Conformance/libavif-profile-10b-422-libaom-y4m.yuv"; - public const string Av1Profile10Bit422PresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-422.png"; public const string Av1Profile10Bit444Avif = "Heif/Av1/Conformance/libavif-profile-10b-444.avif"; public const string Av1Profile10Bit444Reference = "Heif/Av1/Conformance/libavif-profile-10b-444-libaom-y4m.yuv"; - public const string Av1Profile10Bit444PresentationReference = "Heif/Av1/Conformance/libavif-profile-10b-444.png"; public const string Av1Profile12BitMonochromeAvif = "Heif/Av1/Conformance/libavif-profile-12b-400.avif"; public const string Av1Profile12BitMonochromeReference = "Heif/Av1/Conformance/libavif-profile-12b-400-libaom-y4m.yuv"; - public const string Av1Profile12BitMonochromePresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-400.png"; public const string Av1Profile12Bit420Avif = "Heif/Av1/Conformance/libavif-profile-12b-420.avif"; public const string Av1Profile12Bit420Reference = "Heif/Av1/Conformance/libavif-profile-12b-420-libaom-y4m.yuv"; - public const string Av1Profile12Bit420PresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-420.png"; public const string Av1Profile12Bit422Avif = "Heif/Av1/Conformance/libavif-profile-12b-422.avif"; public const string Av1Profile12Bit422Reference = "Heif/Av1/Conformance/libavif-profile-12b-422-libaom-y4m.yuv"; - public const string Av1Profile12Bit422PresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-422.png"; public const string Av1Profile12Bit444Avif = "Heif/Av1/Conformance/libavif-profile-12b-444.avif"; public const string Av1Profile12Bit444Reference = "Heif/Av1/Conformance/libavif-profile-12b-444-libaom-y4m.yuv"; - public const string Av1Profile12Bit444PresentationReference = "Heif/Av1/Conformance/libavif-profile-12b-444.png"; public const string Av1Palette8BitPayload = "Heif/Av1/Conformance/libaom-palette-draw-points-8b-444.bit"; public const string Av1Palette8BitReference = "Heif/Av1/Conformance/libaom-palette-draw-points-8b-444-libaom.yuv"; public const string Av1Palette8BitAvif = "Heif/Av1/Conformance/libavif-palette-draw-points-8b.avif"; - public const string Av1Palette8BitPresentationReference = "Heif/Av1/Conformance/libavif-palette-draw-points-8b.png"; public const string Av1IntraBlockCopy8BitAvif = "Heif/Av1/Conformance/libavif-intrabc-abc-8b-444.avif"; public const string Av1IntraBlockCopy8BitReference = "Heif/Av1/Conformance/libavif-intrabc-abc-8b-444-libaom-y4m.yuv"; - public const string Av1IntraBlockCopy8BitPresentationReference = "Heif/Av1/Conformance/libavif-intrabc-abc-8b-444.png"; public const string Av1IntraBlockCopy10BitAvif = "Heif/Av1/Conformance/libavif-intrabc-abc-10b-444.avif"; public const string Av1IntraBlockCopy10BitReference = "Heif/Av1/Conformance/libavif-intrabc-abc-10b-444-libaom-y4m.yuv"; - public const string Av1IntraBlockCopy10BitPresentationReference = "Heif/Av1/Conformance/libavif-intrabc-abc-10b-444.png"; public const string Av1IntraBlockCopy12BitAvif = "Heif/Av1/Conformance/libavif-intrabc-abc-12b-444.avif"; public const string Av1IntraBlockCopy12BitReference = "Heif/Av1/Conformance/libavif-intrabc-abc-12b-444-libaom-y4m.yuv"; - public const string Av1IntraBlockCopy12BitPresentationReference = "Heif/Av1/Conformance/libavif-intrabc-abc-12b-444.png"; public const string Av1Lossless8BitAvif = "Heif/Av1/Conformance/libavif-lossless-circle-8b-444.avif"; public const string Av1Lossless8BitReference = "Heif/Av1/Conformance/libavif-lossless-circle-8b-444-libaom.yuv"; - public const string Av1Lossless8BitPresentationReference = "Heif/Av1/Conformance/libavif-lossless-circle-8b-444.png"; public const string Av1Lossless10BitAvif = "Heif/Av1/Conformance/libavif-lossless-circle-10b-444.avif"; public const string Av1Lossless10BitReference = "Heif/Av1/Conformance/libavif-lossless-circle-10b-444-libaom.yuv"; - public const string Av1Lossless10BitPresentationReference = "Heif/Av1/Conformance/libavif-lossless-circle-10b-444.png"; public const string Av1Lossless12BitAvif = "Heif/Av1/Conformance/libavif-lossless-circle-12b-444.avif"; public const string Av1Lossless12BitReference = "Heif/Av1/Conformance/libavif-lossless-circle-12b-444-libaom.yuv"; - public const string Av1Lossless12BitPresentationReference = "Heif/Av1/Conformance/libavif-lossless-circle-12b-444.png"; public const string Av1SuperResolution8BitPayload = "Heif/Av1/Conformance/libaom-superres-kodim23-8b.bit"; public const string Av1SuperResolution8BitReference = "Heif/Av1/Conformance/libaom-superres-kodim23-8b-libaom.yuv"; public const string Av1SuperResolution8BitAvif = "Heif/Av1/Conformance/libavif-superres-kodim23-8b.avif"; - public const string Av1SuperResolution8BitPresentationReference = "Heif/Av1/Conformance/libavif-superres-kodim23-8b.png"; public const string Av1SuperResolution10BitPayload = "Heif/Av1/Conformance/libaom-superres-cosmos-10b.bit"; public const string Av1SuperResolution10BitReference = "Heif/Av1/Conformance/libaom-superres-cosmos-10b-libaom.yuv"; public const string Av1SuperResolution10BitAvif = "Heif/Av1/Conformance/libavif-superres-cosmos-10b.avif"; - public const string Av1SuperResolution10BitPresentationReference = "Heif/Av1/Conformance/libavif-superres-cosmos-10b.png"; public const string Av1SuperResolution12BitPayload = "Heif/Av1/Conformance/libaom-superres-cosmos-12b.bit"; public const string Av1SuperResolution12BitReference = "Heif/Av1/Conformance/libaom-superres-cosmos-12b-libaom.yuv"; public const string Av1SuperResolution12BitAvif = "Heif/Av1/Conformance/libavif-superres-cosmos-12b.avif"; - public const string Av1SuperResolution12BitPresentationReference = "Heif/Av1/Conformance/libavif-superres-cosmos-12b.png"; public const string Av1Restoration8BitPayload = "Heif/Av1/Conformance/libaom-restoration-kodim23-8b.bit"; public const string Av1Restoration8BitReference = "Heif/Av1/Conformance/libaom-restoration-kodim23-8b-libaom.yuv"; public const string Av1Restoration8BitAvif = "Heif/Av1/Conformance/libavif-restoration-kodim23-8b.avif"; - public const string Av1Restoration8BitPresentationReference = "Heif/Av1/Conformance/libavif-restoration-kodim23-8b.png"; public const string Av1Restoration10BitPayload = "Heif/Av1/Conformance/libaom-restoration-cosmos-10b.bit"; public const string Av1Restoration10BitReference = "Heif/Av1/Conformance/libaom-restoration-cosmos-10b-libaom.yuv"; public const string Av1Restoration10BitAvif = "Heif/Av1/Conformance/libavif-restoration-cosmos-10b.avif"; - public const string Av1Restoration10BitPresentationReference = "Heif/Av1/Conformance/libavif-restoration-cosmos-10b.png"; public const string Av1Restoration12BitPayload = "Heif/Av1/Conformance/libaom-restoration-cosmos-12b.bit"; public const string Av1Restoration12BitReference = "Heif/Av1/Conformance/libaom-restoration-cosmos-12b-libaom.yuv"; public const string Av1Restoration12BitAvif = "Heif/Av1/Conformance/libavif-restoration-cosmos-12b.avif"; - public const string Av1Restoration12BitPresentationReference = "Heif/Av1/Conformance/libavif-restoration-cosmos-12b.png"; public const string Av1RestorationSuperResolution8BitPayload = "Heif/Av1/Conformance/libaom-restoration-superres-kodim23-8b.bit"; public const string Av1RestorationSuperResolution8BitReference = "Heif/Av1/Conformance/libaom-restoration-superres-kodim23-8b-libaom.yuv"; public const string Av1RestorationSuperResolution10BitPayload = "Heif/Av1/Conformance/libaom-restoration-superres-abc-10b-422.bit"; diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeLosslessMatchesPinnedLibavifPresentation_Rgba32_libavif-lossless-circle-10b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-10b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeLosslessMatchesPinnedLibavifPresentation_Rgba32_libavif-lossless-circle-10b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeLosslessMatchesPinnedLibavifPresentation_Rgba32_libavif-lossless-circle-12b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-12b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeLosslessMatchesPinnedLibavifPresentation_Rgba32_libavif-lossless-circle-12b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeLosslessMatchesPinnedLibavifPresentation_Rgba32_libavif-lossless-circle-8b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-lossless-circle-8b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeLosslessMatchesPinnedLibavifPresentation_Rgba32_libavif-lossless-circle-8b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-400.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-400.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-400.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-420.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-420.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-420.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-422.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-422.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-422.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-10b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-10b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-400.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-400.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-400.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-420.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-420.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-420.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-422.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-422.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-422.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-12b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-12b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-400.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-400.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-400.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-420.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-420.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-420.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-422.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-422.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-422.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-profile-8b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProfileMatrixMatchesPinnedLibavifPresentation_Rgba32_libavif-profile-8b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-progressive-draw-points-8b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProgressiveSingleReferenceMatchesPinnedReferences_Rgba32_libavif-progressive-draw-points-8b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-progressive-draw-points-8b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeProgressiveSingleReferenceMatchesPinnedReferences_Rgba32_libavif-progressive-draw-points-8b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifGlobalWarpSequenceMatchesPinnedReferences_Rgba32_libavif-rotating-grid-global-warp.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-global-warp-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifGlobalWarpSequenceMatchesPinnedReferences_Rgba32_libavif-rotating-grid-global-warp.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-local-warp-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifLocalWarpSequenceMatchesPinnedReferences_Rgba32_libavif-rotating-grid-local-warp.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-rotating-grid-local-warp-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifLocalWarpSequenceMatchesPinnedReferences_Rgba32_libavif-rotating-grid-local-warp.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-difference-weighted-compound-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifObmcSequenceMatchesPinnedReferences_Rgba32_libavif-webp-logo-obmc.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-difference-weighted-compound-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifObmcSequenceMatchesPinnedReferences_Rgba32_libavif-webp-logo-obmc.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-average-compound-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequenceWithEqualAverageCompoundMatchesPinnedReferences_Rgba32_libavif-webp-logo-average-compound.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-average-compound-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequenceWithEqualAverageCompoundMatchesPinnedReferences_Rgba32_libavif-webp-logo-average-compound.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-distance-weighted-compound-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-difference-weighted-compound.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-distance-weighted-compound-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-difference-weighted-compound.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-obmc-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-distance-weighted-compound.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-obmc-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-distance-weighted-compound.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-inter-intra-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-inter-intra.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-inter-intra-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-inter-intra.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-wedge-compound-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-wedge-compound.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-wedge-compound-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeRealLibavifSequencesWithSelectableCompoundAndInterIntraMatchesPinnedReferences_Rgba32_libavif-webp-logo-wedge-compound.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-scaled-reference.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeScaledReferenceMatchesPinnedReferences_Rgba32_libavif-webp-logo-scaled-reference.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-scaled-reference.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeScaledReferenceMatchesPinnedReferences_Rgba32_libavif-webp-logo-scaled-reference.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-scaled-reference-lsel0-libavif.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeSelectedProgressiveSpatialLayerMatchesPinnedReferences_Rgba32_libavif-webp-logo-scaled-reference-lsel0.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-webp-logo-scaled-reference-lsel0-libavif.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeSelectedProgressiveSpatialLayerMatchesPinnedReferences_Rgba32_libavif-webp-logo-scaled-reference-lsel0.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-cdef-cosmos-10b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithActiveCdefMatchesPinnedLibavifPresentation_Rgba32_libavif-cdef-cosmos-10b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-cdef-cosmos-10b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithActiveCdefMatchesPinnedLibavifPresentation_Rgba32_libavif-cdef-cosmos-10b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-cdef-cosmos-12b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithActiveCdefMatchesPinnedLibavifPresentation_Rgba32_libavif-cdef-cosmos-12b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-cdef-cosmos-12b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithActiveCdefMatchesPinnedLibavifPresentation_Rgba32_libavif-cdef-cosmos-12b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-cdef-kodim23-8b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithActiveCdefMatchesPinnedLibavifPresentation_Rgba32_libavif-cdef-kodim23-8b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-cdef-kodim23-8b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithActiveCdefMatchesPinnedLibavifPresentation_Rgba32_libavif-cdef-kodim23-8b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-intrabc-abc-10b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation_Rgba32_libavif-intrabc-abc-10b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-intrabc-abc-10b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation_Rgba32_libavif-intrabc-abc-10b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-intrabc-abc-12b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation_Rgba32_libavif-intrabc-abc-12b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-intrabc-abc-12b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation_Rgba32_libavif-intrabc-abc-12b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-intrabc-abc-8b-444.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation_Rgba32_libavif-intrabc-abc-8b-444.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-intrabc-abc-8b-444.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithIntraBlockCopyMatchesPinnedLibavifPresentation_Rgba32_libavif-intrabc-abc-8b-444.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-restoration-cosmos-10b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithLoopRestorationMatchesPinnedLibavifPresentation_Rgba32_libavif-restoration-cosmos-10b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-restoration-cosmos-10b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithLoopRestorationMatchesPinnedLibavifPresentation_Rgba32_libavif-restoration-cosmos-10b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-restoration-cosmos-12b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithLoopRestorationMatchesPinnedLibavifPresentation_Rgba32_libavif-restoration-cosmos-12b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-restoration-cosmos-12b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithLoopRestorationMatchesPinnedLibavifPresentation_Rgba32_libavif-restoration-cosmos-12b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-restoration-kodim23-8b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithLoopRestorationMatchesPinnedLibavifPresentation_Rgba32_libavif-restoration-kodim23-8b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-restoration-kodim23-8b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithLoopRestorationMatchesPinnedLibavifPresentation_Rgba32_libavif-restoration-kodim23-8b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-palette-draw-points-8b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithPaletteMatchesPinnedLibavifPresentation_Rgba32_libavif-palette-draw-points-8b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-palette-draw-points-8b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithPaletteMatchesPinnedLibavifPresentation_Rgba32_libavif-palette-draw-points-8b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-superres-cosmos-10b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithSuperResolutionMatchesPinnedLibavifPresentation_Rgba32_libavif-superres-cosmos-10b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-superres-cosmos-10b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithSuperResolutionMatchesPinnedLibavifPresentation_Rgba32_libavif-superres-cosmos-10b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-superres-cosmos-12b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithSuperResolutionMatchesPinnedLibavifPresentation_Rgba32_libavif-superres-cosmos-12b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-superres-cosmos-12b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithSuperResolutionMatchesPinnedLibavifPresentation_Rgba32_libavif-superres-cosmos-12b.png diff --git a/tests/Images/Input/Heif/Av1/Conformance/libavif-superres-kodim23-8b.png b/tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithSuperResolutionMatchesPinnedLibavifPresentation_Rgba32_libavif-superres-kodim23-8b.png similarity index 100% rename from tests/Images/Input/Heif/Av1/Conformance/libavif-superres-kodim23-8b.png rename to tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests/DecodeWithSuperResolutionMatchesPinnedLibavifPresentation_Rgba32_libavif-superres-kodim23-8b.png diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighBitDepthPresentationPreservesPrecisionAcrossIntrinsicWidths_Rgba64_GENERAL_12b_444_RExt_Sony_2.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighBitDepthPresentationPreservesPrecisionAcrossIntrinsicWidths_Rgba64_GENERAL_12b_444_RExt_Sony_2.png new file mode 100644 index 000000000..a4e906042 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighBitDepthPresentationPreservesPrecisionAcrossIntrinsicWidths_Rgba64_GENERAL_12b_444_RExt_Sony_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03ccce9838ce1914b644b9f439eeebfa687488690e2dc2a5fdae4cba3225213a +size 445507 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.png new file mode 100644 index 000000000..b130f64d8 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42c898b491383da95bf01676a8e8f7aa221a171f4b211f08ce5fa6a1c313bfb1 +size 254922 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.png new file mode 100644 index 000000000..340348343 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5752cc38c38054018850157c1b11805cae28048a58f422389de7a37240af3593 +size 259024 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.png new file mode 100644 index 000000000..c256c779d --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb558d383a95d9dcbcf39637e7295f69881aa75b99134c84e98b02405849f956 +size 2270060 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.png new file mode 100644 index 000000000..4d27ce953 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:988480de65a19b98f7df3d3298bd432beb324b7e7fd4a67370d37bba13526a53 +size 599400 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.png new file mode 100644 index 000000000..a734b6970 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:704acdf5dabe6d6550373d9f32216fdd0ff17549a6bafba870fab353a0138150 +size 597546 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.png new file mode 100644 index 000000000..9fdb2ad64 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcHighThroughputStillImageMatchesPinnedPresentation_Rgba32_WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82e48bd7d67c6d6bf724f1dd4a07d4ba5ba3532ebab387bd152aca2e54354fa7 +size 596229 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeHighBitDepthPreservesSourcePrecision_Rgba64_GENERAL_12b_400_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeHighBitDepthPreservesSourcePrecision_Rgba64_GENERAL_12b_400_RExt_Sony_1.png new file mode 100644 index 000000000..e0a8a0297 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeHighBitDepthPreservesSourcePrecision_Rgba64_GENERAL_12b_400_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f7926906a68d1b0e4813b738ec085e050c358d66b2e5879515db6803e7e9137 +size 263001 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeStillImageMatchesPinnedLibheif_Rgba32_GENERAL_12b_400_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeStillImageMatchesPinnedLibheif_Rgba32_GENERAL_12b_400_RExt_Sony_1.png new file mode 100644 index 000000000..e0a8a0297 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeStillImageMatchesPinnedLibheif_Rgba32_GENERAL_12b_400_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f7926906a68d1b0e4813b738ec085e050c358d66b2e5879515db6803e7e9137 +size 263001 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeStillImageMatchesPinnedLibheif_Rgba32_GENERAL_8b_400_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeStillImageMatchesPinnedLibheif_Rgba32_GENERAL_8b_400_RExt_Sony_1.png new file mode 100644 index 000000000..def52f84b --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcMonochromeStillImageMatchesPinnedLibheif_Rgba32_GENERAL_8b_400_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:490756396b21f4aeacc40634483f40c0c42f77d8f70005449e09682729f6e52a +size 83380 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.png new file mode 100644 index 000000000..0369d8ad6 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths_Rgba32_EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a974be508d2f5122ea7e7182da0c4b5313049b5229e1cd4fec77bb57c2b759f +size 249788 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths_Rgba32_GENERAL_8b_420_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths_Rgba32_GENERAL_8b_420_RExt_Sony_1.png new file mode 100644 index 000000000..8a37e56da --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionPresentationMatchesAcrossIntrinsicWidths_Rgba32_GENERAL_8b_420_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b4e6e260ffe16dc728d0064cfa4852730426f14ed6ee16ae074272deee3cff9 +size 157543 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.png new file mode 100644 index 000000000..c1c3ef9c8 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b38aee5d910a934868a8ddba5756363ac2f6155c756912f310d2e1a7ef2ccf5 +size 4683537 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_10bit_RExt_QCOM_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_10bit_RExt_QCOM_frame0.png new file mode 100644 index 000000000..378f39e65 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_10bit_RExt_QCOM_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5af1901f1bbd30d2dd98f437cad37b458f2b2defad5b0948959952daf7a48511 +size 2422557 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_12bit_RExt_QCOM_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_12bit_RExt_QCOM_frame0.png new file mode 100644 index 000000000..5ba5e57df --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_12bit_RExt_QCOM_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c77bdce5adbf111756bd6f07d5e8550384cb9327e5326dca6a704085a662757 +size 5152549 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_8bit_RExt_QCOM_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_8bit_RExt_QCOM_frame0.png new file mode 100644 index 000000000..d6dec42a6 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_CCP_8bit_RExt_QCOM_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ccb446aec97dc88379861345dd6066b121341c63d0f5fb2ef9a4b5211266e795 +size 952927 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.png new file mode 100644 index 000000000..4adc2572f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8fbc99537fa7e121f41a217a196875f95053662ef3ff21c453b8c203e64eb2ba +size 255982 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.png new file mode 100644 index 000000000..1a154e992 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b2eaee6ec269a2658d6a7e7e3be47d2cba8b2d158478606b40cd266efbecfd3 +size 250386 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.png new file mode 100644 index 000000000..144666160 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b5d91da29e9ad97cfd64d0b32023e770f7035b51ca37da1825294928d3a2030 +size 221441 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_420_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_420_RExt_Sony_1.png new file mode 100644 index 000000000..bef135aaf --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_420_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93b25daf35a51c5d06e13260406d6206cc7fda532812a43c7c2c7fcdcee2ee8 +size 337393 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_422_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_422_RExt_Sony_1.png new file mode 100644 index 000000000..eb94e6bfd --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_422_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60beaf4ceb7ee35e356225783e04734b8b5e364f93448f716f8ade10f92e2ac4 +size 339585 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_444_RExt_Sony_2.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_444_RExt_Sony_2.png new file mode 100644 index 000000000..21a418a46 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_10b_444_RExt_Sony_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9f72db003768c465aae57bd4414cf0a7ca844ac0989a7065ba1f423e131b8a8 +size 327991 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_420_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_420_RExt_Sony_1.png new file mode 100644 index 000000000..bdea9013a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_420_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52d44eea9a312d6dfc38ff0f52172e6ccd2aa7ee11ec4427c8dc22a223a12830 +size 455775 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_422_RExt_Sony_1.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_422_RExt_Sony_1.png new file mode 100644 index 000000000..74b92c41d --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_422_RExt_Sony_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3951b586abcbcc5522f574cbeca8aeb4ab96e6da848b8b2a46823bb6fb51f43e +size 476713 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_444_RExt_Sony_2.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_444_RExt_Sony_2.png new file mode 100644 index 000000000..a4e906042 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_12b_444_RExt_Sony_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03ccce9838ce1914b644b9f439eeebfa687488690e2dc2a5fdae4cba3225213a +size 445507 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_8b_444_RExt_Sony_2.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_8b_444_RExt_Sony_2.png new file mode 100644 index 000000000..52b26aa22 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_GENERAL_8b_444_RExt_Sony_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a06102b72c546060d1693244e5a9f6de9f5924a634e27450dbde189ca46da4f +size 159244 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_IPCM_A_RExt_NEC_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_IPCM_A_RExt_NEC_2_frame0.png new file mode 100644 index 000000000..7886b689e --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_IPCM_A_RExt_NEC_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e57731b800d6a7c0e34d3b07ab7ba5690f2b66141c2865c64dc3fdc5afecbcb7 +size 247858 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_IPCM_B_RExt_NEC_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_IPCM_B_RExt_NEC_frame0.png new file mode 100644 index 000000000..d51e0ab22 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_IPCM_B_RExt_NEC_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b8b3953335f607c9691c626452dabdf68595017a7eeb94e9bee96c340bf9b0a +size 313388 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_Main_422_10_A_RExt_Sony_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_Main_422_10_A_RExt_Sony_2_frame0.png new file mode 100644 index 000000000..d778ee4c2 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_Main_422_10_A_RExt_Sony_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21614e3259ce3ff3565d729600e8aa268691f3450bc91eb2bfb0900864576cf3 +size 5872698 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_Main_422_10_B_RExt_Sony_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_Main_422_10_B_RExt_Sony_2_frame0.png new file mode 100644 index 000000000..f26a32f38 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_Main_422_10_B_RExt_Sony_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:007694be6991762d3b7637fa2b6215191a470888695d9fbc098b21058f66a949 +size 10716965 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_PERSIST_RPARAM_A_RExt_Sony_3_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_PERSIST_RPARAM_A_RExt_Sony_3_frame0.png new file mode 100644 index 000000000..49289abb0 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_PERSIST_RPARAM_A_RExt_Sony_3_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d1d7749d15635514d824d7f52aeb92ac7933feaa98d2c59db9eaebbfd17b183 +size 246199 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_10bit_I_RExt_SHARP_1_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_10bit_I_RExt_SHARP_1_frame0.png new file mode 100644 index 000000000..ee6e06eb5 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_10bit_I_RExt_SHARP_1_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b525da1d3cbc0fede549913eed0f721baf85a4a2c2bc56a1a6d42e326b2ef9ef +size 6251753 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_12bit_I_RExt_SHARP_1_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_12bit_I_RExt_SHARP_1_frame0.png new file mode 100644 index 000000000..9924fb149 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_12bit_I_RExt_SHARP_1_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a96601049c2e6dc5808d30297a5c1fcc7060a3c0bae1ce0c13f7d4d8ae7c2b9e +size 10856528 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_8bit_I_RExt_SHARP_1_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_8bit_I_RExt_SHARP_1_frame0.png new file mode 100644 index 000000000..1a17e9fdd --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_TSCTX_8bit_I_RExt_SHARP_1_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de182fc4852448839fc9090ace49fe375401408aed131c632dcd9b28f42b3dcd +size 3486224 diff --git a/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.png b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.png new file mode 100644 index 000000000..e52b5b0fd --- /dev/null +++ b/tests/Images/External/ReferenceOutput/HeifDecoderTests/DecodeHevcRangeExtensionStillImageMatchesPinnedPresentation_Rgba32_WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19a83def25a4deea548a1328c69fd8f1c771d32d5bf86c9571c5368cafad80c1 +size 552593 diff --git a/tests/Images/Input/Heif/Av1/Conformance/README.md b/tests/Images/Input/Heif/Av1/Conformance/README.md index 401661026..82a6d487b 100644 --- a/tests/Images/Input/Heif/Av1/Conformance/README.md +++ b/tests/Images/Input/Heif/Av1/Conformance/README.md @@ -1,6 +1,6 @@ # AV1 reconstruction conformance fixtures -These fixtures provide independent reference output for AV1 reconstruction and AVIF presentation tests. ImageSharp output is compared exactly with the retained native YUV planes and presented PNG files; the tests do not use a tolerance. +These fixtures provide independent reference output for AV1 reconstruction and AVIF presentation tests. ImageSharp output is compared exactly with the retained native YUV planes and presented PNG files; the tests do not use a tolerance. Native fixtures remain beside their inputs here, while the PNG files use the repository reference-output naming contract under `tests/Images/External/ReferenceOutput/Av1ReconstructionConformanceTests`. ## Provenance @@ -20,7 +20,7 @@ The reference builds use `AOM_TARGET_CPU=generic` and disable libyuv. Native rec - `-libaom.yuv` files contain headerless planar Y, U, and V reference samples. Samples above eight bits are stored as little-endian 16-bit values. - `-libaom-y4m.yuv` files retain the Y4M header together with the native planar frame. - `-libaom.y4m` files retain the Y4M header together with the native sequence frames selected for comparison. -- `.png` files contain the eight-bit RGBA presentation reference produced by the pinned scalar libavif build. +- Reference-output `.png` files contain the eight-bit RGBA presentation produced by the pinned scalar libavif build. Their names combine the public test method, `Rgba32`, and the input AVIF basename so `CompareToReferenceOutput` resolves them directly. ## Coverage diff --git a/tests/Images/Input/Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0-ffmpeg.png deleted file mode 100644 index 6cce68c2f..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3d467add4b0a41575228af86011a4f0d003003df267c639ca7dab4a290997a2 -size 2729225 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0-ffmpeg.png deleted file mode 100644 index fa7a35602..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d94be2ff029467ba3f0cc6e48c735966edf9c57424c0175fceed14a5d9434dbb -size 2427308 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0-ffmpeg.png deleted file mode 100644 index 930d4178a..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f27738eb42338db6db0ab3e8b392ac5407e51473ffceefd00f318b06b124d249 -size 5167261 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0-ffmpeg.png deleted file mode 100644 index d091c039b..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e4b107ab968f826a9d710be90255842af0315e475516b3b5cf3361dcd226fd81 -size 953520 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended-hm-ffmpeg.png deleted file mode 100644 index 0cfcd1e11..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bf61f91cbc21d8172d4000dcffb2e5a6e1d56877cc354465548f00bf106b8923 -size 255832 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended-hm-ffmpeg.png deleted file mode 100644 index d51c6445b..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:66d5e15924db6ca2b7344edc8e200a6cc00674369105d23ebe67b03b39e782f8 -size 250554 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended-hm-ffmpeg.png deleted file mode 100644 index eeba679b5..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bae712cbd64ba5eb491780509b483b2d83ea531a630a9913b2a9af649a70b096 -size 259753 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended-ffmpeg.png deleted file mode 100644 index da15aed06..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27fafaa241c530ee7c4b0b22cdbcac13414b2a5bd742c61f31d9857e1ea52f3f -size 256815 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1-ffmpeg.png deleted file mode 100644 index 9288ec980..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35c73148eb3eeff74890086d82514d9419e9c2d672a6e0eb5a25ac97752422a8 -size 251208 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended-ffmpeg.png deleted file mode 100644 index 32bcf7840..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:70b46a41052be1727ee286c84b71e6952e363ce9ff1af35b7c571280d40c59d2 -size 260306 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_420_RExt_Sony_1-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_420_RExt_Sony_1-ffmpeg.png deleted file mode 100644 index d05cd4cd8..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_420_RExt_Sony_1-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9196dfaaaf4fc256e663b2b6974671bed9dfb19b26211af936ccf389cb7de156 -size 195771 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_422_RExt_Sony_1-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_422_RExt_Sony_1-ffmpeg.png deleted file mode 100644 index 2866f9f4b..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_422_RExt_Sony_1-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d865c89c8ed3a0315ed37ecae3a8738d0abdac92fb890b94024bbd6e6c0a981 -size 208613 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_444_RExt_Sony_2-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_444_RExt_Sony_2-ffmpeg.png deleted file mode 100644 index 20fffad0f..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_10b_444_RExt_Sony_2-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bbdb9ac98e1a65f6b0f9f6d4e8d3d3128179f330f9160862755204f01bf15670 -size 205100 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_400_RExt_Sony_1-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_400_RExt_Sony_1-hm-ffmpeg.png deleted file mode 100644 index 58347e181..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_400_RExt_Sony_1-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:90ec0f69b33f264b98a07885815d2b5e1bb8dfb2cdcef61ecbc06bc47ec36eb9 -size 87886 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_420_RExt_Sony_1-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_420_RExt_Sony_1-ffmpeg.png deleted file mode 100644 index f24188d8b..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_420_RExt_Sony_1-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51fe712b737f62227437fcd33c02aa223b618d051a6da300637bbf7e3cca92f2 -size 204265 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_422_RExt_Sony_1-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_422_RExt_Sony_1-ffmpeg.png deleted file mode 100644 index 8ff90507c..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_422_RExt_Sony_1-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3e365ce81652df437b699d4e4a438be7cc3b48b64488600e5bfb133299da59f5 -size 216345 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_444_RExt_Sony_2-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_444_RExt_Sony_2-ffmpeg.png deleted file mode 100644 index 5b14f909f..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_12b_444_RExt_Sony_2-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09f1244f554076b1452fa1a8c280f87d876d7eaee6b81fda23448648c8749a8f -size 210526 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_400_RExt_Sony_1-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_400_RExt_Sony_1-hm-ffmpeg.png deleted file mode 100644 index 2400d3ede..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_400_RExt_Sony_1-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2dab4ae93efc085770d811887e171d7b8de0c41aa670cb945429f7b198b0ffd9 -size 85162 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_420_RExt_Sony_1-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_420_RExt_Sony_1-ffmpeg.png deleted file mode 100644 index 01ca19289..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_420_RExt_Sony_1-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ea750b757fec4eb5650ac28454a98a0117a810b01bdeb29b0c91aab5ccaa5e44 -size 161043 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_444_RExt_Sony_2-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_444_RExt_Sony_2-ffmpeg.png deleted file mode 100644 index f519ab3b4..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/GENERAL_8b_444_RExt_Sony_2-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad14c2742160a9fc9443833d16822de1231b253e50a8eef9cf325bdfc7b0686a -size 189475 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0-ffmpeg.png deleted file mode 100644 index b242252b1..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dd910cd903aebb550143f498e25cfec9505c63181116499f6693985fb332c5e6 -size 149133 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0-ffmpeg.png deleted file mode 100644 index 21a75af14..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:068d8a89a8cae39d87c3768f8a2894387159557433d57aacda5115a27869c9ba -size 149637 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0-ffmpeg.png deleted file mode 100644 index a6593d28c..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d56d487a16836ac7d4016bc57eedcbf586e401962c5740879f7760e63ba6788e -size 3728772 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0-ffmpeg.png deleted file mode 100644 index 6865f838c..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:acdde43497ae13edc07a74ae182877dd1cc9b98da81fc9c3b5ac1cb02210186a -size 6566287 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0-ffmpeg.png deleted file mode 100644 index b77efdc2f..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:11758488f57cdcf97ece9dfcc35b467c349ac79cb3b8855a6e3fa7753052e59f -size 246886 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/PRESENTATION_SHA256.md b/tests/Images/Input/Heif/Hevc/Conformance/PRESENTATION_SHA256.md deleted file mode 100644 index 4b7d3618e..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/PRESENTATION_SHA256.md +++ /dev/null @@ -1,74 +0,0 @@ -# Genuine HEIC presentation fixture SHA-256 - -These hashes cover every retained genuine HEIC container and independent PNG presentation reference used by the HEVC Range Extensions presentation matrix. - -| File | SHA-256 | -| --- | --- | -| `ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0-ffmpeg.png` | `B3D467ADD4B0A41575228AF86011A4F0D003003DF267C639CA7DAB4A290997A2` | -| `ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.heic` | `0B36E994059522739E53EEDBACAE7CCCA5EDFE67934FE841FBB400388B926ABC` | -| `Bitdepth_A_RExt_Sony_1_frame0.heic` | `83A143499278C1950F191FFE84D04D6AAF6CFB41077F52A78DD686DE0E4A9CD2` | -| `Bitdepth_B_RExt_Sony_1_frame0.heic` | `1DD4464942006D50126B6A79DB8E7E1AB6C53833CF1802ECA047803086F4BC4B` | -| `CCP_10bit_RExt_QCOM_frame0-ffmpeg.png` | `D94BE2FF029467BA3F0CC6E48C735966EDF9C57424C0175FCEED14A5D9434DBB` | -| `CCP_10bit_RExt_QCOM_frame0.heic` | `F3C9F9ADCE22F14FA9F9FE6CF566A0CB3336E0CE71DC98D763B49F268C19B425` | -| `CCP_12bit_RExt_QCOM_frame0-ffmpeg.png` | `F27738EB42338DB6DB0AB3E8B392AC5407E51473FFCEEFD00F318B06B124D249` | -| `CCP_12bit_RExt_QCOM_frame0.heic` | `D42FC1B58C55A4D1AB7F385A4479A7DD029C0F3A4FD4244EAB11F3147A90270A` | -| `CCP_8bit_RExt_QCOM_frame0-ffmpeg.png` | `E4B107AB968F826A9D710BE90255842AF0315E475516B3B5CF3361DCD226FD81` | -| `CCP_8bit_RExt_QCOM_frame0.heic` | `D4B6BA7EC0EDC57E4AE3A50369D83A53382801DD413412C5224896C8F71CAFD6` | -| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended-hm-ffmpeg.png` | `BF61F91CBC21D8172D4000DCFFB2E5A6E1D56877CC354465548F00BF106B8923` | -| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.heic` | `F9B828DA68543A5A8724BF317CEC4B7C63289322338A98E8164C3A51668A749B` | -| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended-hm-ffmpeg.png` | `66D5E15924DB6CA2B7344EDC8E200A6CC00674369105D23EBE67B03B39E782F8` | -| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.heic` | `B50903B1CD8BEF1CA9A7128A09C11FE29A0CCA4BFA76D9FD5360A81D3093F216` | -| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended-hm-ffmpeg.png` | `BAE712CBD64BA5EB491780509B483B2D83EA531A630A9913B2A9AF649A70B096` | -| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.heic` | `6FF37E993F514BECBF9CCC055863FB105C0E506F99CAEB2A0F576C27F4A9CF67` | -| `EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended-ffmpeg.png` | `27FAFAA241C530EE7C4B0B22CDBCAC13414B2A5BD742C61F31D9857E1EA52F3F` | -| `EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.heic` | `E05C498ECCF1C6FA5F273A8A61441B703DF82EB6267BA6ADD646F22A328EE8B1` | -| `EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1-ffmpeg.png` | `35C73148EB3EEFF74890086D82514D9419E9C2D672A6E0EB5A25AC97752422A8` | -| `EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.heic` | `63BB00619CB2DEB4986DF6D42EC805BA0C1895E7AB0534E4A81CA43ADA140861` | -| `EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended-ffmpeg.png` | `70B46A41052BE1727EE286C84B71E6952E363CE9FF1AF35B7C571280D40C59D2` | -| `EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.heic` | `72E84F04F278D7A3BD02E215A2FD7D0BBE5DFC6D1AC2048DCA57EC4EF36B6A73` | -| `GENERAL_10b_420_RExt_Sony_1-ffmpeg.png` | `9196DFAAAF4FC256E663B2B6974671BED9DFB19B26211AF936CCF389CB7DE156` | -| `GENERAL_10b_420_RExt_Sony_1.heic` | `091A1DC8AAF44706B153D61C35F4EB93E27C458704A41F3F2E645B81E5E7D845` | -| `GENERAL_10b_422_RExt_Sony_1-ffmpeg.png` | `8D865C89C8ED3A0315ED37ECAE3A8738D0ABDAC92FB890B94024BBD6E6C0A981` | -| `GENERAL_10b_422_RExt_Sony_1.heic` | `18644CA5CFE89C4A50145D4A9CE5E5CD9EF240B6BEA134F13020E2194889B538` | -| `GENERAL_10b_444_RExt_Sony_2-ffmpeg.png` | `BBDB9AC98E1A65F6B0F9F6D4E8D3D3128179F330F9160862755204F01BF15670` | -| `GENERAL_10b_444_RExt_Sony_2.heic` | `7070B0A6368CA02FE33310DCF54B7F5DA61A4413444308CF99B1A8E49DAB43B4` | -| `GENERAL_12b_400_RExt_Sony_1-hm-ffmpeg.png` | `90EC0F69B33F264B98A07885815D2B5E1BB8DFB2CDCEF61ECBC06BC47EC36EB9` | -| `GENERAL_12b_400_RExt_Sony_1.heic` | `AF534C6238E9FB7C2B4F2A97F053B232D073EB31BD175B4D32E83E2128BB4D67` | -| `GENERAL_12b_420_RExt_Sony_1-ffmpeg.png` | `51FE712B737F62227437FCD33C02AA223B618D051A6DA300637BBF7E3CCA92F2` | -| `GENERAL_12b_420_RExt_Sony_1.heic` | `814433B3109B2FA1F2408F424F6AA38E17F92B4E50F4996D2CA59A2BAA84A30A` | -| `GENERAL_12b_422_RExt_Sony_1-ffmpeg.png` | `3E365CE81652DF437B699D4E4A438BE7CC3B48B64488600E5BFB133299DA59F5` | -| `GENERAL_12b_422_RExt_Sony_1.heic` | `D88D5F0225061EEF053BFC193D83334624EC80A6653A8E15792BC320973D25F5` | -| `GENERAL_12b_444_RExt_Sony_2-ffmpeg.png` | `09F1244F554076B1452FA1A8C280F87D876D7EAEE6B81FDA23448648C8749A8F` | -| `GENERAL_12b_444_RExt_Sony_2.heic` | `DA264470C99586D99280FB861273C69B982A2AC6D962BD7408751C8BFE186332` | -| `GENERAL_8b_400_RExt_Sony_1-hm-ffmpeg.png` | `2DAB4AE93EFC085770D811887E171D7B8DE0C41AA670CB945429F7B198B0FFD9` | -| `GENERAL_8b_400_RExt_Sony_1.heic` | `0DFCE3B603A81C253D0A70827D1EDEA45554ADC405068A4A277EEA2286AF8304` | -| `GENERAL_8b_420_RExt_Sony_1-ffmpeg.png` | `EA750B757FEC4EB5650AC28454A98A0117A810B01BDEB29B0C91AAB5CCAA5E44` | -| `GENERAL_8b_420_RExt_Sony_1.heic` | `68BCD1FA5E8FFCFA7E9FB4A7C9B091B9096DB4E7BE27B8BD6C336439DF217F1D` | -| `GENERAL_8b_444_RExt_Sony_2-ffmpeg.png` | `AD14C2742160A9FC9443833D16822DE1231B253E50A8EEF9CF325BDFC7B0686A` | -| `GENERAL_8b_444_RExt_Sony_2.heic` | `CACDE3604855B57280977DAA9ECC4073F4AC30973AA530A30727B88D3395763F` | -| `IPCM_A_RExt_NEC_2_frame0-ffmpeg.png` | `DD910CD903AEBB550143F498E25CFEC9505C63181116499F6693985FB332C5E6` | -| `IPCM_A_RExt_NEC_2_frame0.heic` | `6575BD13224E8C48DB8EA3B2FFEA9CFDB4B2444C84193F43A1EABEF2C6F76342` | -| `IPCM_B_RExt_NEC_frame0-ffmpeg.png` | `068D8A89A8CAE39D87C3768F8A2894387159557433D57AACDA5115A27869C9BA` | -| `IPCM_B_RExt_NEC_frame0.heic` | `20B2814C29AE04ACD57718AB75FD8FC32B49975A08AF9ACE98918AF1DFF814FE` | -| `Main_422_10_A_RExt_Sony_2_frame0-ffmpeg.png` | `D56D487A16836AC7D4016BC57EEDCBF586E401962C5740879F7760E63BA6788E` | -| `Main_422_10_A_RExt_Sony_2_frame0.heic` | `5EE8360A7400DB49F7D9CA790E73EED7947B3A267E115714D2581BDEA628F04E` | -| `Main_422_10_B_RExt_Sony_2_frame0-ffmpeg.png` | `ACDDE43497AE13EDC07A74AE182877DD1CC9B98DA81FC9C3B5AC1CB02210186A` | -| `Main_422_10_B_RExt_Sony_2_frame0.heic` | `EFEFF0451CCE627BBD73FEC725CC38C759CF3DE07010050642E6DEBCC3F57448` | -| `PERSIST_RPARAM_A_RExt_Sony_3_frame0-ffmpeg.png` | `11758488F57CDCF97ECE9DFCC35B467C349AC79CB3B8855A6E3FA7753052E59F` | -| `PERSIST_RPARAM_A_RExt_Sony_3_frame0.heic` | `9FC9C32108DD3EE8B37F138428F39CAF6A1701F161778C1258100C754ED9378B` | -| `TSCTX_10bit_I_RExt_SHARP_1_frame0-ffmpeg.png` | `F6C36D8FF915D65405C3D5705C9525FBA76B751ECD50BD64AD1470BA0BA42035` | -| `TSCTX_10bit_I_RExt_SHARP_1_frame0.heic` | `FF99931C1DA27FB150F17B67DC1BF8F167439E78EF5611F51AF5ECDDFBA5B720` | -| `TSCTX_12bit_I_RExt_SHARP_1_frame0-ffmpeg.png` | `0BCB4BBB62CAAA7D8F24BE3FDB0EECAE26EA66CD55E23D683AEBC0FBBEABEDD4` | -| `TSCTX_12bit_I_RExt_SHARP_1_frame0.heic` | `B3031636E37F8534F28FA54304287208784476AE709F52F64C54CBF5E55A3773` | -| `TSCTX_8bit_I_RExt_SHARP_1_frame0-ffmpeg.png` | `991D37D4476D2A87BA5465A96462D84B40E5CAF234F38B00A7E90215DA7F68DC` | -| `TSCTX_8bit_I_RExt_SHARP_1_frame0.heic` | `C4A1653681D5DCDE1E0B9F35C7BA6E6D546CF237F4C8D724123DA631E2C57148` | -| `WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0-hm-ffmpeg.png` | `1BBE3271FDEF0AE1328E7196D9841476C75A5865BDC40EB4D417FDFBA17B6A07` | -| `WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.heic` | `E7C9278743E5CF8B964953FB15AC0590A9FB476959C995A8089E730D0D531D29` | -| `WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png` | `C1E85593BBB0523EC5D8E3DC2F97895355B9CB8D468898AC32E7622158FFFFBC` | -| `WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.heic` | `BE215D5A7AB4A91B99080ED3E80BF48C93F921003A6642C2D4C92C779B8211DF` | -| `WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png` | `D7359C4CA58001556C3F0DA0277919BD832551C706DF8B91EC3FCA6D52E6AE9F` | -| `WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.heic` | `9A685B86DD0B6A7EEFDF268F8D908E61A0FB6154AAAA86BB640B04B3E7D6FD14` | -| `WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-hm-ffmpeg.png` | `98737664EA21735A32BAC4DD3A8D8606AEB9DE2752418682FE3C91EBD4EDDA72` | -| `WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.heic` | `099E54D9B44702A852B9C6C37F70BD2EB31D3A0BD9BA16767E09E6CE2904FC33` | -| `WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-ffmpeg.png` | `8A52D404EB5B4E82443B97FC11FCCEECC2886E48D651A577CDCA5E858A871CCD` | -| `WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.heic` | `000C9E50DA7654FC76374A42A8EA3EAD12890B02E26FEDD103E42FD57D28AAE5` | diff --git a/tests/Images/Input/Heif/Hevc/Conformance/README.md b/tests/Images/Input/Heif/Hevc/Conformance/README.md index 6ed265df7..0e4dc3950 100644 --- a/tests/Images/Input/Heif/Hevc/Conformance/README.md +++ b/tests/Images/Input/Heif/Hevc/Conformance/README.md @@ -48,13 +48,13 @@ MP4Box -add-image frame0.hevc:primary -new output.heic The monochrome files add `image-pixi=8` or `image-pixi=12` to the `-add-image` argument so their `pixi` property contains exactly one channel. No `colr` property is added; the decoder must retain the HEVC VUI color description. -Twenty-four `*-ffmpeg.png` files are FFmpeg 9.0.1 presentations decoded directly from the resulting HEIC files. Nine `*-hm-ffmpeg.png` files use native samples from pinned HM commit `9c1f298659ab0cee9dc13d23d0304221575410b9`, built with `HIGH_BITDEPTH=ON`, followed by FFmpeg raw-video color conversion. Every HM plane used by those references matches the official decoded-picture-hash values. This split is intentional: FFmpeg does not reconstruct seven of the retained high-throughput pictures to their published plane digests, and its direct monochrome-to-PNG path does not expand the signaled limited luma range. The monochrome references therefore apply the exact 8- or 12-bit limited-range scale before RGB packing. +Presentation references under `tests/Images/External/ReferenceOutput/HeifDecoderTests` come from pinned libheif 1.23.1 when its HEVC backend reproduces the native reference planes. Profiles that libheif rejects or reconstructs incorrectly instead use native samples from pinned HM commit `9c1f298659ab0cee9dc13d23d0304221575410b9`, built with `HIGH_BITDEPTH=ON`, followed by libheif's independently reproduced color-conversion operation. That operation retains libheif's literal float32 Rec.601 fallback coefficients, limited-range factors, nearest native chroma sample, separate multiply/add order, half-unit rounding, source-precision clipping, and 16-bit RGB storage for high-bit-depth input. -The two unequal-precision HEIC files have no PNG reference because FFmpeg and libheif reject that HEVC profile combination. Their public tests require successful bounded HEIC presentation and correct metadata, while the companion native tests compare all three planes with the published digests. +FFmpeg 9.0.1 raw output is a reconstruction cross-check only where every Y, Cb, and Cr byte matches pinned HM. Its PNG color-conversion rounding is not a presentation oracle. Every HM plane used to generate a reference matches the selected picture's official decoded-picture-hash values or the independently verified complete-output digest described above. -`HeifDecoderTests` covers all 35 genuine HEIC files. The 33 independently presentable cases use the repository's narrow `TolerantPercentage(1F, 20)` public-pixel contract because HEVC does not prescribe one chroma upsampling filter. Exact native-plane tests remain the reconstruction oracle. Representative 8/10/12-bit, monochrome, 4:2:0, 4:2:2, 4:4:4, and high-throughput files also pass with 4 KiB allocator groups and exactly-once returns. Eight-bit subsampled and 12-bit full-resolution presentation repeat through AVX-512, AVX, narrower vector, and scalar `FeatureTestRunner` configurations. +The two unequal-precision HEIC files have no PNG reference because FFmpeg and libheif reject that HEVC profile combination. Their public tests require successful bounded HEIC presentation and correct metadata, while the companion native tests compare all three planes with the published digests. -[`PRESENTATION_SHA256.md`](PRESENTATION_SHA256.md) records every retained HEIC and PNG SHA-256. +`HeifDecoderTests` covers all 35 genuine HEIC files. The 33 independently presentable cases use `DebugSave` and `CompareToReferenceOutput(ImageComparer.Exact, provider)`; no presentation tolerance is permitted. Exact native-plane tests remain the reconstruction oracle. Representative 8/10/12-bit, monochrome, 4:2:0, 4:2:2, 4:4:4, and high-throughput files also run with 4 KiB allocator groups and exactly-once returns. Eight-bit subsampled, 12-bit full-resolution, and 12-bit `Rgba64` presentation repeat through AVX-512, AVX, narrower vector, and scalar `FeatureTestRunner` configurations. The SHA-256 columns below identify the downloaded archive, its original Annex B payload, and the retained bounded picture: diff --git a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0-ffmpeg.png deleted file mode 100644 index e3dd49b6b..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f6c36d8ff915d65405c3d5705c9525fba76b751ecd50bd64ad1470ba0ba42035 -size 4139230 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0-ffmpeg.png deleted file mode 100644 index 3d1d95953..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0bcb4bbb62caaa7d8f24be3fdb0eecae26ea66cd55e23d683aebc0fbbeabedd4 -size 5038948 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0-ffmpeg.png deleted file mode 100644 index 90dd677f7..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:991d37d4476d2a87ba5465a96462d84b40e5caf234f38b00a7e90215da7f68dc -size 4113423 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0-hm-ffmpeg.png deleted file mode 100644 index ef8ad6ec1..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1bbe3271fdef0ae1328e7196d9841476c75a5865bdc40eb4d417fdfba17b6a07 -size 2225212 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png deleted file mode 100644 index 860e5566e..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c1e85593bbb0523ec5d8e3dc2f97895355b9cb8d468898ac32e7622158ffffbc -size 535609 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png deleted file mode 100644 index aad31cd2e..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d7359c4ca58001556c3f0da0277919bd832551c706df8b91ec3fca6d52e6ae9f -size 534581 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-hm-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-hm-ffmpeg.png deleted file mode 100644 index f1055c46d..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-hm-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98737664ea21735a32bac4dd3a8d8606aeb9de2752418682fe3c91ebd4edda72 -size 533914 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-ffmpeg.png b/tests/Images/Input/Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-ffmpeg.png deleted file mode 100644 index ab39bf637..000000000 --- a/tests/Images/Input/Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0-ffmpeg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8a52d404eb5b4e82443b97fc11fcceecc2886e48d651a577cdca5e858a871ccd -size 532122