Browse Source

Complete HEVC parallel slice decoding

pull/2633/head
James Jackson-South 4 days ago
parent
commit
b337bce1a6
  1. 58
      src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Traversal.cs
  2. 18
      src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.cs
  3. 4
      src/ImageSharp/Formats/Heif/Hevc/HevcSliceSegmentHeader.cs
  4. 183
      tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs
  5. 13
      tests/ImageSharp.Tests/TestImages.cs
  6. 3
      tests/Images/Input/Heif/Hevc/Conformance/DSLICE_A_HHI_5.bit
  7. 3
      tests/Images/Input/Heif/Hevc/Conformance/DSLICE_B_HHI_5.bit
  8. 3
      tests/Images/Input/Heif/Hevc/Conformance/DSLICE_C_HHI_5.bit
  9. 3
      tests/Images/Input/Heif/Hevc/Conformance/ENTP_A_Qualcomm_1.bit
  10. 3
      tests/Images/Input/Heif/Hevc/Conformance/ENTP_C_Qualcomm_1.bit
  11. 20
      tests/Images/Input/Heif/Hevc/Conformance/README.md
  12. 3
      tests/Images/Input/Heif/Hevc/Conformance/TILES_A_Cisco_2.bit
  13. 3
      tests/Images/Input/Heif/Hevc/Conformance/TILES_B_Cisco_1.bit
  14. 3
      tests/Images/Input/Heif/Hevc/Conformance/WPP_A_ericsson_MAIN_2.bit
  15. 3
      tests/Images/Input/Heif/Hevc/Conformance/WPP_B_ericsson_MAIN_2.bit
  16. 3
      tests/Images/Input/Heif/Hevc/Conformance/WPP_C_ericsson_MAIN_2.bit
  17. 3
      tests/Images/Input/Heif/Hevc/Conformance/WPP_D_ericsson_MAIN_2.bit
  18. 3
      tests/Images/Input/Heif/Hevc/Conformance/WPP_E_ericsson_MAIN_2.bit
  19. 3
      tests/Images/Input/Heif/Hevc/Conformance/WPP_F_ericsson_MAIN_2.bit

58
src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Traversal.cs

@ -41,16 +41,54 @@ internal sealed partial class HevcPictureDecoder
int contextOffset = colorPlaneIndex * HevcCabacContexts.ContextCount;
int riceOffset = colorPlaneIndex * 4;
if (slice.DependentSliceSegment && this.hasSliceSegmentContexts[colorPlaneIndex])
int startRasterAddress = tileLayout.GetRasterAddress(startAddressInTileScan);
tileLayout.GetTilePosition(
startRasterAddress,
out int startTileIndex,
out int startColumnInTile,
out int startRowInTile,
out int startTileWidth,
out _);
bool startsAtTileOrigin = startColumnInTile == 0 && startRowInTile == 0;
bool canInheritSliceSegmentContexts = !startsAtTileOrigin
&& (startTileWidth >= 2 || !this.pictureParameterSet.EntropyCodingSynchronizationEnabled);
// A dependent segment normally resumes the preceding CABAC state. Tile origins and one-CTB-wide WPP
// rows are initialization boundaries instead, matching the availability rules used by the reference decoder.
if (slice.DependentSliceSegment
&& canInheritSliceSegmentContexts
&& this.hasSliceSegmentContexts[colorPlaneIndex])
{
reader.CopyContextsFrom(this.sliceSegmentContexts.AsSpan(contextOffset, HevcCabacContexts.ContextCount));
this.coefficientDecoder.CopyRiceAdaptationFrom(this.sliceSegmentRiceAdaptation.AsSpan(riceOffset, 4));
}
if (!slice.DependentSliceSegment)
{
// An independent slice starts a new prediction region, so an upper-right CTB from the preceding
// independent slice cannot supply wavefront contexts to its first row.
this.hasWavefrontContexts[colorPlaneIndex] = false;
}
bool startsAtWavefrontRow = this.pictureParameterSet.EntropyCodingSynchronizationEnabled
&& startColumnInTile == 0
&& startRowInTile > 0;
if (startsAtWavefrontRow
&& startTileWidth > 1
&& this.hasWavefrontContexts[colorPlaneIndex]
&& this.wavefrontContextTileIndices[colorPlaneIndex] == startTileIndex)
{
// A dependent segment can begin exactly at a wavefront row boundary. Its first substream still uses
// the upper-right state captured from the preceding row; no substream transition occurs inside this call.
reader.CopyContextsFrom(this.wavefrontContexts.AsSpan(contextOffset, HevcCabacContexts.ContextCount));
this.coefficientDecoder.CopyRiceAdaptationFrom(this.wavefrontRiceAdaptation.AsSpan(riceOffset, 4));
}
int codingTreeBlockSize = 1 << this.sequenceParameterSet.CodingTreeBlockLog2;
int tileScanAddress = startAddressInTileScan;
bool firstCodingTreeBlock = true;
bool wavefrontStateAvailable = false;
while (tileScanAddress < tileLayout.Width * tileLayout.Height)
{
int rasterAddress = tileLayout.GetRasterAddress(tileScanAddress);
@ -81,10 +119,13 @@ internal sealed partial class HevcPictureDecoder
reader = new HevcCabacSyntaxReader(slice.GetEntropySubstream(substreamIndex).Span, sliceQuantizationParameter);
this.coefficientDecoder.ResetRiceAdaptation();
this.lastCodedQuantizationParameter = sliceQuantizationParameter;
if (startsWavefrontRow && tileWidth > 1 && wavefrontStateAvailable)
if (startsWavefrontRow
&& tileWidth > 1
&& this.hasWavefrontContexts[colorPlaneIndex]
&& this.wavefrontContextTileIndices[colorPlaneIndex] == tileIndex)
{
reader.CopyContextsFrom(this.wavefrontContexts);
this.coefficientDecoder.CopyRiceAdaptationFrom(this.wavefrontRiceAdaptation[..4]);
reader.CopyContextsFrom(this.wavefrontContexts.AsSpan(contextOffset, HevcCabacContexts.ContextCount));
this.coefficientDecoder.CopyRiceAdaptationFrom(this.wavefrontRiceAdaptation.AsSpan(riceOffset, 4));
}
}
@ -121,9 +162,10 @@ internal sealed partial class HevcPictureDecoder
// row. The next row starts with those contexts but a newly initialized arithmetic register.
if (this.pictureParameterSet.EntropyCodingSynchronizationEnabled && columnInTile == 1)
{
reader.CopyContextsTo(this.wavefrontContexts);
this.coefficientDecoder.CopyRiceAdaptationTo(this.wavefrontRiceAdaptation[..4]);
wavefrontStateAvailable = true;
reader.CopyContextsTo(this.wavefrontContexts.AsSpan(contextOffset, HevcCabacContexts.ContextCount));
this.coefficientDecoder.CopyRiceAdaptationTo(this.wavefrontRiceAdaptation.AsSpan(riceOffset, 4));
this.hasWavefrontContexts[colorPlaneIndex] = true;
this.wavefrontContextTileIndices[colorPlaneIndex] = tileIndex;
}
tileScanAddress++;

18
src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.cs

@ -82,14 +82,24 @@ internal sealed partial class HevcPictureDecoder : IDisposable
private readonly IMemoryOwner<bool> availabilityScratch;
/// <summary>
/// The adaptive contexts captured after the second coding-tree block of a wavefront row.
/// The per-color-plane adaptive contexts captured after the second coding-tree block of a wavefront row.
/// </summary>
private readonly HevcCabacContext[] wavefrontContexts = new HevcCabacContext[HevcCabacContexts.ContextCount];
private readonly HevcCabacContext[] wavefrontContexts = new HevcCabacContext[HevcCabacContexts.ContextCount * 3];
/// <summary>
/// The persistent Rice statistics captured with the wavefront probability contexts.
/// The per-color-plane persistent Rice statistics captured with the wavefront probability contexts.
/// </summary>
private InlineArray4<int> wavefrontRiceAdaptation;
private readonly int[] wavefrontRiceAdaptation = new int[12];
/// <summary>
/// Whether retained wavefront contexts are available for each color plane.
/// </summary>
private InlineArray4<bool> hasWavefrontContexts;
/// <summary>
/// The tile that owns each color plane's retained wavefront contexts.
/// </summary>
private InlineArray4<int> wavefrontContextTileIndices;
/// <summary>
/// The adaptive contexts retained at the end of a dependent-slice prediction region.

4
src/ImageSharp/Formats/Heif/Hevc/HevcSliceSegmentHeader.cs

@ -450,7 +450,7 @@ internal sealed class HevcSliceSegmentHeader
/// <param name="rbspOffset">The decoded raw-byte-sequence payload offset.</param>
/// <param name="emulationPreventionBytePositions">The removed encoded-payload byte positions.</param>
/// <returns>The encoded byte-sequence payload offset at the same syntax boundary.</returns>
private static int GetEncodedPayloadOffset(
internal static int GetEncodedPayloadOffset(
int rbspOffset,
ReadOnlySpan<int> emulationPreventionBytePositions)
{
@ -474,7 +474,7 @@ internal sealed class HevcSliceSegmentHeader
/// <param name="encodedOffset">The encoded byte-sequence payload offset.</param>
/// <param name="emulationPreventionBytePositions">The removed encoded-payload byte positions.</param>
/// <returns>The decoded raw-byte-sequence payload offset at the same syntax boundary.</returns>
private static int GetDecodedPayloadOffset(
internal static int GetDecodedPayloadOffset(
int encodedOffset,
ReadOnlySpan<int> emulationPreventionBytePositions)
{

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

@ -64,6 +64,43 @@ public class HevcPictureDecoderTests
ChromaQuantizationAdjustment = 32,
}
/// <summary>
/// Identifies parallelization syntax that an official independently decoded picture must exercise.
/// </summary>
[Flags]
public enum ParallelizationTools
{
/// <summary>
/// No parallelization syntax is signaled.
/// </summary>
None = 0,
/// <summary>
/// Dependent slice segments are signaled.
/// </summary>
DependentSliceSegments = 1,
/// <summary>
/// Tile boundaries are signaled.
/// </summary>
Tiles = 2,
/// <summary>
/// Wavefront row entry points are signaled.
/// </summary>
Wavefront = 4,
/// <summary>
/// Slice-header extension bytes are signaled.
/// </summary>
SliceHeaderExtensions = 8,
/// <summary>
/// One or more entropy entry points are signaled.
/// </summary>
EntryPoints = 16,
}
/// <summary>
/// Verifies the first independently coded picture from official ITU RExt conformance streams against its
/// published decoded-picture hashes.
@ -466,6 +503,152 @@ public class HevcPictureDecoderTests
Assert.Equal(chromaRedDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cr));
}
/// <summary>
/// Verifies the complete sequential decoder path for HEVC tiles, wavefront entry points, dependent slice
/// segments, and slice-header extensions against native-plane digests from published or pinned-HM output.
/// </summary>
/// <param name="path">The official Annex B conformance stream.</param>
/// <param name="expectedTools">The parallelization syntax that the retained picture signals.</param>
/// <param name="expectedCodingTreeBlockLog2">The expected coding-tree-block size logarithm.</param>
/// <param name="expectedCodingTreeBlockWidth">The expected picture width in coding-tree blocks.</param>
/// <param name="expectedTileColumns">The exact tile-column count, or zero when only a multi-tile assertion applies.</param>
/// <param name="expectedTileRows">The exact tile-row count, or zero when only a multi-tile assertion applies.</param>
/// <param name="lumaDigest">The pinned-HM or published luma-plane MD5 digest.</param>
/// <param name="chromaBlueDigest">The pinned-HM or published blue-difference-plane MD5 digest.</param>
/// <param name="chromaRedDigest">The pinned-HM or published red-difference-plane MD5 digest.</param>
[Theory]
[InlineData(TestImages.Heif.DependentSlicesA, ParallelizationTools.DependentSliceSegments, 6, 30, 1, 1, "00dc01343ab9dc53c078344d7f77dab1", "899538536f2b327d84894c947f87bbc2", "a1bc8421c5a72ce2792b40847e95d438")]
[InlineData(TestImages.Heif.DependentSlicesB, ParallelizationTools.DependentSliceSegments | ParallelizationTools.Wavefront, 6, 30, 1, 1, "d048cfe1b7f0e6a6e3689733914caa19", "d7400a314011173564516b81407c3f42", "7bddfaa6d440f8490ec88b94fdbac706")]
[InlineData(TestImages.Heif.DependentSlicesC, ParallelizationTools.DependentSliceSegments | ParallelizationTools.Tiles, 6, 30, 0, 0, "a8c96c581d9de294a4fe798cede17817", "afb4cdebbbb31edfeab504d64c779895", "e593a80b1f17724f930728068993c06c")]
[InlineData(TestImages.Heif.TilesA, ParallelizationTools.Tiles | ParallelizationTools.EntryPoints, 6, 30, 5, 5, "6828e4b27ab4fda31fe3b8bcdb3bccef", "1f899aff0a453d133de048232d3ee1c0", "87ca938e4a19cd289bdaa85023c704c5")]
[InlineData(TestImages.Heif.TilesB, ParallelizationTools.Tiles | ParallelizationTools.EntryPoints, 6, 30, 5, 5, "aa44a1bf0f77f5a78e514eab3621aab2", "53a29305bb7b60dcd3a0082ce5aed9f4", "0e7ad4ea85eedf8fa06ac9b366323175")]
[InlineData(TestImages.Heif.WavefrontA, ParallelizationTools.Wavefront | ParallelizationTools.SliceHeaderExtensions | ParallelizationTools.EntryPoints, 6, 7, 1, 1, "69bd520cd6b017b49144275f1c3b498c", "33bb1c6216561f30fbefb89ce87c0956", "1f88fd804c87d8f5c8c72cee4043d140")]
[InlineData(TestImages.Heif.WavefrontB, ParallelizationTools.Wavefront | ParallelizationTools.SliceHeaderExtensions | ParallelizationTools.EntryPoints, 5, 13, 1, 1, "ff78fcf56cf449c195708626a975e870", "b230844124f07aad4102aa21e2fc0f15", "e10c05f8c4007b14ddc6a7cf858f374e")]
[InlineData(TestImages.Heif.WavefrontC, ParallelizationTools.Wavefront | ParallelizationTools.SliceHeaderExtensions | ParallelizationTools.EntryPoints, 4, 26, 1, 1, "d55877b038bbe2af6a4b35eeff27b26f", "4e1145cc891c295543407b6c62c7ad55", "8fa9c17216a9b02a65582c322206216b")]
[InlineData(TestImages.Heif.WavefrontD, ParallelizationTools.Wavefront | ParallelizationTools.SliceHeaderExtensions | ParallelizationTools.EntryPoints, 6, 1, 1, 1, "ab7c74b80340e5bde0858276f11a37ed", "4fe6b63cfe5656bf88912ccf9caeb85a", "3dbb149d5b90a49cf72d4e2d5fbb0511")]
[InlineData(TestImages.Heif.WavefrontE, ParallelizationTools.Wavefront | ParallelizationTools.SliceHeaderExtensions | ParallelizationTools.EntryPoints, 6, 2, 1, 1, "d2b8cd7d9e7baf4dd3e383ba8fef3c22", "315f19843d4e637dc41f964c4adff626", "07f619c6aedd51a04ba99d2bfc0ecb2c")]
[InlineData(TestImages.Heif.WavefrontF, ParallelizationTools.Wavefront | ParallelizationTools.SliceHeaderExtensions | ParallelizationTools.EntryPoints, 6, 3, 1, 1, "797335a8e293c6ce6dd87fde6f797f07", "77f74454394860093d4b18ae9ae793fe", "e99ff04282a3457a44685378008ff86a")]
[InlineData(TestImages.Heif.EntryPointsA, ParallelizationTools.Tiles | ParallelizationTools.EntryPoints, 6, 30, 2, 2, "ea26d532556e6b71b369b41def35af93", "295a5552a8152035a1cae2405a690251", "1d81ff340ac8a37d75f7782ca140cae3")]
[InlineData(TestImages.Heif.EntryPointsC, ParallelizationTools.Wavefront | ParallelizationTools.EntryPoints, 6, 30, 1, 1, "81b087fcf7df2626c7592ec5d39ec1fc", "93bd06e1a216a388568c069ead14f98e", "f0446d71e2061a8c3a6281fede767d81")]
public void DecodeOfficialParallelizationPictureMatchesPublishedReference(
string path,
ParallelizationTools expectedTools,
int expectedCodingTreeBlockLog2,
int expectedCodingTreeBlockWidth,
int expectedTileColumns,
int expectedTileRows,
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);
HevcPictureParameterSet pictureParameterSet = bitstream.SliceSegments[0].PictureParameterSet;
HevcSequenceParameterSet sequenceParameterSet = pictureParameterSet.SequenceParameterSet;
using HevcPictureDecoder decoder = new(Configuration.Default, pictureParameterSet);
decoder.Decode(bitstream);
bool hasDependentSliceSegments = false;
bool hasEntryPoints = false;
foreach (HevcSliceSegmentHeader sliceSegment in bitstream.SliceSegments)
{
hasDependentSliceSegments |= sliceSegment.DependentSliceSegment;
hasEntryPoints |= sliceSegment.EntryPointOffsets.Count != 0;
}
bool expectsTiles = (expectedTools & ParallelizationTools.Tiles) != 0;
bool expectsWavefront = (expectedTools & ParallelizationTools.Wavefront) != 0;
int codingTreeBlockSize = 1 << sequenceParameterSet.CodingTreeBlockLog2;
int codingTreeBlockWidth = (sequenceParameterSet.Width + codingTreeBlockSize - 1) / codingTreeBlockSize;
Assert.Equal((expectedTools & ParallelizationTools.DependentSliceSegments) != 0, hasDependentSliceSegments);
Assert.Equal(expectsTiles, pictureParameterSet.TilesEnabled);
Assert.Equal(expectsWavefront, pictureParameterSet.EntropyCodingSynchronizationEnabled);
Assert.Equal((expectedTools & ParallelizationTools.SliceHeaderExtensions) != 0, pictureParameterSet.SliceSegmentHeaderExtensionPresent);
Assert.Equal((expectedTools & ParallelizationTools.EntryPoints) != 0, hasEntryPoints);
Assert.Equal(expectedCodingTreeBlockLog2, sequenceParameterSet.CodingTreeBlockLog2);
Assert.Equal(expectedCodingTreeBlockWidth, codingTreeBlockWidth);
if (expectedTileColumns == 0)
{
Assert.True(pictureParameterSet.TileColumnWidths.Count > 1);
Assert.True(pictureParameterSet.TileRowHeights.Count > 1);
}
else
{
Assert.Equal(expectedTileColumns, pictureParameterSet.TileColumnWidths.Count);
Assert.Equal(expectedTileRows, pictureParameterSet.TileRowHeights.Count);
}
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 the dependent-slice tile and wavefront combinations through split allocator groups with balanced
/// final disposal.
/// </summary>
/// <param name="path">The official Annex B conformance stream.</param>
/// <param name="lumaDigest">The pinned-HM luma-plane MD5 digest.</param>
/// <param name="chromaBlueDigest">The pinned-HM blue-difference-plane MD5 digest.</param>
/// <param name="chromaRedDigest">The pinned-HM red-difference-plane MD5 digest.</param>
[Theory]
[InlineData(TestImages.Heif.DependentSlicesB, "d048cfe1b7f0e6a6e3689733914caa19", "d7400a314011173564516b81407c3f42", "7bddfaa6d440f8490ec88b94fdbac706")]
[InlineData(TestImages.Heif.DependentSlicesC, "a8c96c581d9de294a4fe798cede17817", "afb4cdebbbb31edfeab504d64c779895", "e593a80b1f17724f930728068993c06c")]
public void DecodeOfficialParallelizationPicturesWithConstrainedAllocatorMatchPinnedHmDigest(
string path,
string lumaDigest,
string chromaBlueDigest,
string chromaRedDigest)
{
byte[] annexB = TestFile.Create(path).Bytes;
ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData);
HevcCodecConfiguration codecConfiguration = new(configurationData);
HevcImageItemBitstream bitstream = new(itemData, codecConfiguration);
TestMemoryAllocator allocator = new() { BufferCapacityInBytes = 4_096 };
allocator.EnableNonThreadSafeLogging();
Configuration configuration = Configuration.Default.Clone();
configuration.MemoryAllocator = allocator;
using (HevcPictureDecoder decoder = new(configuration, bitstream.SliceSegments[0].PictureParameterSet))
{
decoder.Decode(bitstream);
Assert.Equal(lumaDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Y));
Assert.Equal(chromaBlueDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cb));
Assert.Equal(chromaRedDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cr));
}
Assert.NotEmpty(allocator.AllocationLog);
AssertBalancedAllocations(allocator);
}
/// <summary>
/// Verifies that entry-point byte lengths exclude emulation-prevention bytes from the decoded substream.
/// </summary>
[Fact]
public void EntryPointOffsetsExcludeEmulationPreventionBytes()
{
ReadOnlySpan<int> preventionBytePositions = [3, 8, 14];
const int DecodedHeaderLength = 4;
int encodedHeaderLength = HevcSliceSegmentHeader.GetEncodedPayloadOffset(
DecodedHeaderLength,
preventionBytePositions);
const int EncodedSubstreamLength = 11;
int decodedBoundary = HevcSliceSegmentHeader.GetDecodedPayloadOffset(
encodedHeaderLength + EncodedSubstreamLength,
preventionBytePositions);
Assert.Equal(5, encodedHeaderLength);
Assert.Equal(13, decodedBoundary);
Assert.Equal(9, decodedBoundary - DecodedHeaderLength);
}
/// <summary>
/// Verifies all reconstructed samples from a real HEIC grid tile against the HM reference decoder.
/// </summary>

13
tests/ImageSharp.Tests/TestImages.cs

@ -1324,6 +1324,19 @@ public static class TestImages
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 DependentSlicesA = "Heif/Hevc/Conformance/DSLICE_A_HHI_5.bit";
public const string DependentSlicesB = "Heif/Hevc/Conformance/DSLICE_B_HHI_5.bit";
public const string DependentSlicesC = "Heif/Hevc/Conformance/DSLICE_C_HHI_5.bit";
public const string TilesA = "Heif/Hevc/Conformance/TILES_A_Cisco_2.bit";
public const string TilesB = "Heif/Hevc/Conformance/TILES_B_Cisco_1.bit";
public const string WavefrontA = "Heif/Hevc/Conformance/WPP_A_ericsson_MAIN_2.bit";
public const string WavefrontB = "Heif/Hevc/Conformance/WPP_B_ericsson_MAIN_2.bit";
public const string WavefrontC = "Heif/Hevc/Conformance/WPP_C_ericsson_MAIN_2.bit";
public const string WavefrontD = "Heif/Hevc/Conformance/WPP_D_ericsson_MAIN_2.bit";
public const string WavefrontE = "Heif/Hevc/Conformance/WPP_E_ericsson_MAIN_2.bit";
public const string WavefrontF = "Heif/Hevc/Conformance/WPP_F_ericsson_MAIN_2.bit";
public const string EntryPointsA = "Heif/Hevc/Conformance/ENTP_A_Qualcomm_1.bit";
public const string EntryPointsC = "Heif/Hevc/Conformance/ENTP_C_Qualcomm_1.bit";
public const string Image1 = "Heif/image1.heic";
public const string Image2 = "Heif/image2.heic";
public const string Image3 = "Heif/image3.heic";

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

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

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

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

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

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

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

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

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

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

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

@ -37,3 +37,23 @@ The loop-filter fixtures are the unchanged Annex B payloads from the official HE
- `DBLK_A_MAIN10_VIXS_4.bit` is the Main 10 negative-QP deblocking stream. The archive SHA-256 is `D86EC87F98FCCBCEC3758954A7CF430E8AF8CF021D347DFBBED2F1D5DBB00F25`, and the bitstream SHA-256 is `3A9089207BEDDDB0C8DB28B410441E37D4CFF5DD8301CB8BA7D2F75036E2D50C`. Pinned HM reproduces the published complete-output MD5 `c4594956bb9e8303f1662f9eb1bcdf50`; the retained 10-bit 4:2:0 first picture has plane MD5 values `184a72aab144cb474df3c1a289e8692d`, `d30e750dd70cae163d00f441a75896fd`, and `d253c41f06228df215f4616febbad34f`.
- `SAO_A_MediaTek_4.bit` is the 8-bit 4:2:0 sample-adaptive-offset stream. The archive SHA-256 is `E0B5C8F4AB4FB592971F06469DB630D9E7EF72B4D37D729604E2FDAA9DF706C9`, and the bitstream SHA-256 is `88F693AC4AEC4DEA03CB4BC0CB9D8C98A4023A015905369BB62688064FB58944`. Pinned HM reproduces the published complete-output MD5 `272e694a2262a2b34f6248f787a4431d`; the retained first picture has plane MD5 values `08723eb3fb41af96c87becc4f6973234`, `230778eb7df0ebc009ca92e9697ec4d6`, and `e8e21ed380d2272dc38384ecd6515e53`.
- `SAO_A_RExt_MediaTek_1.bit` is the 12-bit 4:4:4 Range Extensions stream for PPS bit-shift scaling of SAO offsets. The archive SHA-256 is `D0B5646150B35FB8E4C1D51F3D451AEDDF964581132C9C49B253E34556BEEA4D`, and the bitstream SHA-256 is `6B0D45B5CA4D4919EAEC5A98DAF0EB4CEBCC6D8B0A12B30B748386CC9358DF13`. Pinned HM reproduces the published complete GBR-output MD5 `126cd42a185b327d86640a9269044bc8`; the retained first picture has G, B, and R plane MD5 values `fb342158a61b6cb3174b99d2e1167d7d`, `9ff5400aac0380474882acb903f51f89`, and `bb320be3c7905a5a220e0066a5edb991`.
The parallelization fixtures are unchanged Annex B payloads from the official HEVC v1 attachment. Archives that name their payload `.bin` are retained byte-for-byte with the repository's common `.bit` extension. `HevcPictureDecoderTests.DecodeOfficialParallelizationPictureMatchesPublishedReference` adapts every complete first IDR picture to one bounded `hvc1` item, asserts its tile, wavefront, dependent-slice, entry-point, extension, and CTB geometry, and compares all three native planes exactly.
Pinned HM commit `9c1f298659ab0cee9dc13d23d0304221575410b9` reproduces the published complete-output MD5 for every dependent-slice, tile, and entry-point archive below. The WPP first-picture plane hashes come directly from the published YUV files included in their archives. The two combined dependent-slice cases also pass through 4 KiB allocator groups with balanced exactly-once disposal.
- `DSLICE_A_HHI_5.bit`: archive SHA-256 `C41C1A1E1E700AF201EAF4CB0D11D4361B41BA0828E80C78D1835D1DE187F80C`; bitstream SHA-256 `8398FB23C814A197BBA497AD2C6103F81CA8003434FA40EC347D4D0A07C9468A`; published output MD5 `c7caf3164b0a316549ac7244f66f1294`.
- `DSLICE_B_HHI_5.bit`: archive SHA-256 `993B933AC6801899B6F04AE5DD2C20FBC2498FD9710A924611E66DE2F690716B`; bitstream SHA-256 `DB582F1181F3B8ED3BEEB32246A1A99123700DBDC3D3BE4E1797032FCD46C486`; published output MD5 `2e072130f116a4d0f7fc69fa76cfcdfb`.
- `DSLICE_C_HHI_5.bit`: archive SHA-256 `6836566F0A4465775B4757B84D7A89F453B635EBA2B941AE07132F7C7268C116`; bitstream SHA-256 `F162007F604AA0E48229C4153F940FD5F24DB955AD158D11E2BD46C89C49CA76`; published output MD5 `505a47c5ce4bc66ef5661aeb778b0f1f`.
- `TILES_A_Cisco_2.bit`: archive SHA-256 `BD63079966105A3BDAC764979CB82B708F586CC7C34859A1D466E18CC6A5C345`; bitstream SHA-256 `EFF78A401ECCCC21D995345988F1BE60EE76604CF10FA39D421C3E00668A94D6`; published output MD5 `946f0771fa87d49f684f96871c9c3c88`.
- `TILES_B_Cisco_1.bit`: archive SHA-256 `75B3C9B2981CDA59D497750322CDE7CA23D6CEF39FA9A8E11F36926758B7F83B`; bitstream SHA-256 `D2F65167917E42030DB804C60CA7775452445A61930CCEE3FA2AD2CD3830A57A`; published output MD5 `3382291f2b19ee2d760647d4cc756e95`.
- `WPP_A_ericsson_MAIN_2.bit`: archive SHA-256 `81C601E9301BA5F562EBF9918E73D1C7153E0A6FE8FA4509F61035A212188216`; bitstream SHA-256 `54D896D9FBDFA0AAE15629001105C6EE132C8459E152ABB06EFC62CEAD4324AE`; published output MD5 `cd7e815eb47e8138fec2185d4de84304`.
- `WPP_B_ericsson_MAIN_2.bit`: archive SHA-256 `57BFA7DC2417976825187B43829F1E107D87EBE661CFA4A02087EFAE3BD1148E`; bitstream SHA-256 `F1D18F737A9380F6CE58B6AEAE158AF458C5B557E06DD24977B7A5C6E095B9B2`; published output MD5 `e37c7e561a1226640a7bf98e81df78b1`.
- `WPP_C_ericsson_MAIN_2.bit`: archive SHA-256 `4D1F3E7FC1B05E22F2C53FABC670A3DB9A642BB511004C4D785B49582890BDF2`; bitstream SHA-256 `21CF0A7C5F6FBA5A76C7132A2714313D120D1443A0130400FB55AB1E454D5BDA`; published output MD5 `e067aa3a6a12cd5743849ded793c8d3f`.
- `WPP_D_ericsson_MAIN_2.bit`: archive SHA-256 `04C166DF6E6D68584910FCE77055F6C16428FC5C907BB1BEFD10BBF40C16B939`; bitstream SHA-256 `30EEC63F2324AA982FB91BD4C1C551C833C253BA711EE131AA9CC4D322398CAF`; published output MD5 `f710612103f386c415be3e6300693451`.
- `WPP_E_ericsson_MAIN_2.bit`: archive SHA-256 `10F4A50870F763D7CCBD975ADCE20176022A1B9712664244A94C069322534FAF`; bitstream SHA-256 `C8FE49762A13E1CC2B033308BB22AEB35DA0C96F94CA8EF7D87D95BDADAEAA2C`; published output MD5 `485798dbf95ad61232075df2f294aa3f`.
- `WPP_F_ericsson_MAIN_2.bit`: archive SHA-256 `39F5FFAA4C273C800B4E05715E2D4002E31B3BBE39505EA59B08C5FDABE6AF21`; bitstream SHA-256 `E8566E0E48509592DFAF7D314B7E292F51CEDE045559E3C32B447A9822A8B949`; published output MD5 `2aaf16274fe8e799d72fa08a4963850d`.
- `ENTP_A_Qualcomm_1.bit`: archive SHA-256 `66ABDF60455ECE468ACF160274316C51DCA3858D93A8FFCE93646CBB5568FE43`; bitstream SHA-256 `1DC1DFB16F676F59CEBDE3A4732209CE5CE0D0F49EF697970987C0C3E0E087B1`; published output MD5 `25f3c7facf9e7b75e81247206b4fc60d`.
- `ENTP_C_Qualcomm_1.bit`: archive SHA-256 `6CFDFE2F6BA8E1A860909550E5A486E7BF712FED00674869F45C1D82D05833F5`; bitstream SHA-256 `993CD68F0E749CD1D9CE7CC3A368B4DF26DCCF07DED91048100217B9A0C56D28`; published output MD5 `0b607e6e7946e6e8d0f92a1a294d135d`.
The retained `ENTP_A_Qualcomm_1` first picture verifies its uniform 2x2 tile entry points. The archive description places its special entry-point emulation-prevention case at POC 4, which is outside the retained IDR picture. `HevcPictureDecoderTests.EntryPointOffsetsExcludeEmulationPreventionBytes` therefore verifies the same production boundary-conversion methods directly with prevention bytes in both the encoded header and the bounded non-final entropy substream; it does not claim that the later non-IDR picture itself is decoded.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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