Browse Source

Verify HEVC coding-tree traversal

pull/2633/head
James Jackson-South 4 days ago
parent
commit
66d1f3c41b
  1. 59
      tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs
  2. 8
      tests/ImageSharp.Tests/TestImages.cs
  3. 12
      tests/Images/Input/Heif/Hevc/Conformance/README.md
  4. 3
      tests/Images/Input/Heif/Hevc/Conformance/RQT_A_HHI_4.bit
  5. 3
      tests/Images/Input/Heif/Hevc/Conformance/RQT_B_HHI_4.bit
  6. 3
      tests/Images/Input/Heif/Hevc/Conformance/RQT_C_HHI_4.bit
  7. 3
      tests/Images/Input/Heif/Hevc/Conformance/RQT_D_HHI_4.bit
  8. 3
      tests/Images/Input/Heif/Hevc/Conformance/RQT_E_HHI_4.bit
  9. 3
      tests/Images/Input/Heif/Hevc/Conformance/STRUCT_A_Samsung_7.bit
  10. 3
      tests/Images/Input/Heif/Hevc/Conformance/STRUCT_B_Samsung_7.bit
  11. 3
      tests/Images/Input/Heif/Hevc/Conformance/TUSIZE_A_Samsung_1.bit

59
tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs

@ -80,6 +80,57 @@ public class HevcPictureDecoderTests
}
}
/// <summary>
/// Verifies coding-tree and transform-tree conformance streams against native-plane digests produced by the
/// pinned HM decoder from output that matches each archive's published checksum.
/// </summary>
/// <param name="path">The official Annex B conformance stream.</param>
/// <param name="expectedCodingTreeBlockLog2">The expected coding-tree-block size logarithm.</param>
/// <param name="expectedMinCodingBlockLog2">The expected minimum coding-block size logarithm.</param>
/// <param name="expectedMinTransformBlockLog2">The expected minimum transform-block size logarithm.</param>
/// <param name="expectedMaxTransformHierarchyDepthIntra">The expected internal intra transform-depth limit.</param>
/// <param name="lumaDigest">The reference luma-plane MD5 digest.</param>
/// <param name="chromaBlueDigest">The reference blue-difference-plane MD5 digest.</param>
/// <param name="chromaRedDigest">The reference red-difference-plane MD5 digest.</param>
[Theory]
[InlineData(TestImages.Heif.RqtA, 6, 3, 2, 1, "adf2bfab6de808840c82f48eee31a0a5", "4b29b1d2699b77e42a4e22fb0d70993e", "8ada6d784647329a4f0da232176914f4")]
[InlineData(TestImages.Heif.RqtB, 6, 3, 2, 2, "797f41be9a4d53b640332f9d03b1f304", "ef67e5ceff912f7aeb14f2e00ddd5cbf", "e2af5fa6f3c4bcc96dfa95cb8947a7db")]
[InlineData(TestImages.Heif.RqtC, 6, 3, 2, 3, "5d431346cd0b3f52846fc20fc0afdcc4", "ff9355b8cc72d77edbad6f5bd4938df1", "24f8aae8c00f418af487be29d2a5a126")]
[InlineData(TestImages.Heif.RqtD, 6, 3, 2, 4, "30138fa13664590d16355be8f7362eb2", "6198b3d1e990baadcaa533b4c44a5be2", "45f5427aec28b4f4655240812387607b")]
[InlineData(TestImages.Heif.RqtE, 6, 3, 2, 5, "e9e182380f3209ef877b75199b546c00", "f555fd054855dc5a1cb82cb8f3393b5a", "baed53765a5424fbc38aa541917d0625")]
[InlineData(TestImages.Heif.StructA, 4, 3, 2, 2, "bf47fb8ff96a225c2646c0539744ac93", "c105b60fd0e8740574fb76972bbc3b1a", "f9e2d8327da50734b54771df29b343bb")]
[InlineData(TestImages.Heif.StructB, 5, 4, 2, 2, "61e13729a4e3d6fd96f5002a501d1d60", "fee8312ceaccb1f254ef21449f104e4e", "dbe684d5fffbbc2f5ca90b205018060c")]
[InlineData(TestImages.Heif.TuSizeA, 6, 5, 4, 3, "17a84e6f516dbcb8810c7548bf6e216c", "edd3085f7a152d7ffaabae816f4942ac", "e8b47494064c1a730aca3c6ee23572c8")]
public void DecodeOfficialTraversalPictureMatchesPinnedHmDigest(
string path,
int expectedCodingTreeBlockLog2,
int expectedMinCodingBlockLog2,
int expectedMinTransformBlockLog2,
int expectedMaxTransformHierarchyDepthIntra,
string lumaDigest,
string chromaBlueDigest,
string chromaRedDigest)
{
byte[] annexB = TestFile.Create(path).Bytes;
ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData);
HevcCodecConfiguration configuration = new(configurationData);
HevcImageItemBitstream bitstream = new(itemData, configuration);
HevcSequenceParameterSet sequenceParameterSet = bitstream.SliceSegments[0].PictureParameterSet.SequenceParameterSet;
using HevcPictureDecoder decoder = new(Configuration.Default, bitstream.SliceSegments[0].PictureParameterSet);
decoder.Decode(bitstream);
Assert.Equal(8, decoder.Picture.BitDepthLuma);
Assert.Equal(1, decoder.Picture.ChromaFormat);
Assert.Equal(expectedCodingTreeBlockLog2, sequenceParameterSet.CodingTreeBlockLog2);
Assert.Equal(expectedMinCodingBlockLog2, sequenceParameterSet.MinCodingBlockLog2);
Assert.Equal(expectedMinTransformBlockLog2, sequenceParameterSet.MinTransformBlockLog2);
Assert.Equal(expectedMaxTransformHierarchyDepthIntra, sequenceParameterSet.MaxTransformHierarchyDepthIntra);
Assert.Equal(lumaDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Y));
Assert.Equal(chromaBlueDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cb));
Assert.Equal(chromaRedDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cr));
}
/// <summary>
/// Verifies all reconstructed samples from a real HEIC grid tile against the HM reference decoder.
/// </summary>
@ -290,11 +341,12 @@ public class HevcPictureDecoderTests
}
}
Assert.True(
mismatchCount == 0,
string message =
$"{plane} contained {mismatchCount} differing samples. The maximum difference was {maximumDifference}; " +
$"the mismatches span ({minimumMismatchX}, {minimumMismatchY}) through ({maximumMismatchX}, {maximumMismatchY}), " +
$"and the first mismatch at ({firstMismatchX}, {firstMismatchY}) was {firstActual}, expected {firstExpected}.");
$"and the first mismatch at ({firstMismatchX}, {firstMismatchY}) was {firstActual}, expected {firstExpected}.";
Assert.True(mismatchCount == 0, message);
}
/// <summary>
@ -593,7 +645,6 @@ public class HevcPictureDecoderTests
Assert.Single(
allocator.ReturnLog,
returned => returned.AllocationId == allocation.AllocationId);
}
}

8
tests/ImageSharp.Tests/TestImages.cs

@ -1304,6 +1304,14 @@ 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 RqtA = "Heif/Hevc/Conformance/RQT_A_HHI_4.bit";
public const string RqtB = "Heif/Hevc/Conformance/RQT_B_HHI_4.bit";
public const string RqtC = "Heif/Hevc/Conformance/RQT_C_HHI_4.bit";
public const string RqtD = "Heif/Hevc/Conformance/RQT_D_HHI_4.bit";
public const string RqtE = "Heif/Hevc/Conformance/RQT_E_HHI_4.bit";
public const string StructA = "Heif/Hevc/Conformance/STRUCT_A_Samsung_7.bit";
public const string StructB = "Heif/Hevc/Conformance/STRUCT_B_Samsung_7.bit";
public const string TuSizeA = "Heif/Hevc/Conformance/TUSIZE_A_Samsung_1.bit";
public const string Image1 = "Heif/image1.heic";
public const string Image2 = "Heif/image2.heic";
public const string Image3 = "Heif/image3.heic";

12
tests/Images/Input/Heif/Hevc/Conformance/README.md

@ -1,9 +1,17 @@
# HEVC Range Extensions conformance fixtures
# HEVC conformance fixtures
These fixtures come from the electronic attachment to [ITU-T H.265.1 (10/2018)](https://www.itu.int/rec/T-REC-H.265.1-201810-I/en), the conformance specification aligned with ISO/IEC 23008-8. Table 4 identifies the Sony `GENERAL_*_RExt` streams and their required profiles.
The `.bit` files are the original Annex B conformance streams. Each `_frame0.yuv` file contains the first decoded picture extracted byte-for-byte from the corresponding published planar reference output; it was not generated by ImageSharp.
The `.bit` files are the original Annex B conformance streams. The Samsung archives name their payloads `.bin`; the repository stores those unchanged bytes with the common `.bit` extension. Each `GENERAL_*_frame0.yuv` file contains the first decoded picture extracted byte-for-byte from the corresponding published planar reference output; it was not generated by ImageSharp.
`HevcPictureDecoderTests.DecodeOfficialRangeExtensionsPictureMatchesPublishedDigest` limits each stream to its first independently coded picture, adapts that picture to the bounded `hvc1` item contract, compares every reconstructed sample with `_frame0.yuv`, and verifies the published decoded-picture MD5 value for every present plane.
The retained matrix covers the ImageSharp 8, 10, and 12-bit still-image precision boundary across monochrome, 4:2:0, 4:2:2, and 4:4:4. Tool-specific H.265.1 streams remain necessary before every exposed Range Extensions tool can be marked complete.
The Main-profile traversal matrix comes from the official `RQT_A_HHI_4` through `RQT_E_HHI_4`, `STRUCT_A_Samsung_7`, `STRUCT_B_Samsung_7`, and `TUSIZE_A_Samsung_1` archives. Their published descriptions target residual-quadtree intra hierarchy depths zero through four, coding-tree and minimum-coding-unit structure, and a 64x64 coding-tree block with 32x32 minimum coding units and 16x16 minimum luma transforms, respectively.
`HevcPictureDecoderTests.DecodeOfficialTraversalPictureMatchesPinnedHmDigest` decodes each first independently coded picture through the production still-item path and compares all three native planes with fixed MD5 digests. The RQT values are the streams' decoded-picture-hash SEI values. For STRUCT and TUSIZE, the plane values were calculated from the first picture written by the [HM reference decoder at commit `9c1f298659ab0cee9dc13d23d0304221575410b9`](https://vcgit.hhi.fraunhofer.de/jvet/HM/-/commit/9c1f298659ab0cee9dc13d23d0304221575410b9); the complete HM output also matched each archive's published file MD5:
- `STRUCT_A_Samsung_7`: `02f02cc9a67222004ae18ee6bebd475a`
- `STRUCT_B_Samsung_7`: `1f472e014aff120681e8482c8a04ef93`
- `TUSIZE_A_Samsung_1`: `5e6c198c852e92cdcca0e137fc2610c4`

3
tests/Images/Input/Heif/Hevc/Conformance/RQT_A_HHI_4.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/RQT_B_HHI_4.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/RQT_C_HHI_4.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/RQT_D_HHI_4.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/RQT_E_HHI_4.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/STRUCT_A_Samsung_7.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/STRUCT_B_Samsung_7.bit

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

3
tests/Images/Input/Heif/Hevc/Conformance/TUSIZE_A_Samsung_1.bit

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