diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcCodingTreeState.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcCodingTreeState.cs index 7da3b8d6f..6871cdd3e 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/HevcCodingTreeState.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcCodingTreeState.cs @@ -30,16 +30,6 @@ internal sealed class HevcCodingTreeState : IDisposable /// private readonly Buffer2D quantizationParameters; - /// - /// The combined picture, slice, and coding-unit Cb quantization offsets at minimum-coding-block resolution. - /// - private readonly Buffer2D chromaBlueQuantizationOffsets; - - /// - /// The combined picture, slice, and coding-unit Cr quantization offsets at minimum-coding-block resolution. - /// - private readonly Buffer2D chromaRedQuantizationOffsets; - /// /// The packed bypass and PCM flags at minimum-coding-block resolution. /// @@ -63,8 +53,6 @@ internal sealed class HevcCodingTreeState : IDisposable Buffer2D? depths = null; Buffer2D? quantizationParameters = null; - Buffer2D? chromaBlueQuantizationOffsets = null; - Buffer2D? chromaRedQuantizationOffsets = null; Buffer2D? flags = null; try { @@ -76,29 +64,17 @@ internal sealed class HevcCodingTreeState : IDisposable this.WidthInMinCodingBlocks, this.HeightInMinCodingBlocks); - chromaBlueQuantizationOffsets = configuration.MemoryAllocator.Allocate2D( - this.WidthInMinCodingBlocks, - this.HeightInMinCodingBlocks); - - chromaRedQuantizationOffsets = configuration.MemoryAllocator.Allocate2D( - this.WidthInMinCodingBlocks, - this.HeightInMinCodingBlocks); - flags = configuration.MemoryAllocator.Allocate2D( this.WidthInMinCodingBlocks, this.HeightInMinCodingBlocks); this.depths = depths; this.quantizationParameters = quantizationParameters; - this.chromaBlueQuantizationOffsets = chromaBlueQuantizationOffsets; - this.chromaRedQuantizationOffsets = chromaRedQuantizationOffsets; this.flags = flags; } catch { flags?.Dispose(); - chromaRedQuantizationOffsets?.Dispose(); - chromaBlueQuantizationOffsets?.Dispose(); quantizationParameters?.Dispose(); depths?.Dispose(); throw; @@ -155,8 +131,6 @@ internal sealed class HevcCodingTreeState : IDisposable /// The base-two logarithm of the square coding-unit size. /// The coding-tree depth. /// The effective luma quantization parameter. - /// The combined Cb quantization-parameter offset. - /// The combined Cr quantization-parameter offset. /// A value indicating whether transform and quantization are bypassed. /// A value indicating whether the coding unit contains pulse-code-modulated samples. public void SetCodingUnit( @@ -165,8 +139,6 @@ internal sealed class HevcCodingTreeState : IDisposable int log2Size, int depth, int quantizationParameter, - int chromaBlueQuantizationOffset, - int chromaRedQuantizationOffset, bool transquantBypass, bool pcm) { @@ -183,8 +155,6 @@ internal sealed class HevcCodingTreeState : IDisposable { this.depths.DangerousGetRowSpan(row)[unitX..endX].Fill((byte)depth); this.quantizationParameters.DangerousGetRowSpan(row)[unitX..endX].Fill((sbyte)quantizationParameter); - this.chromaBlueQuantizationOffsets.DangerousGetRowSpan(row)[unitX..endX].Fill((sbyte)chromaBlueQuantizationOffset); - this.chromaRedQuantizationOffsets.DangerousGetRowSpan(row)[unitX..endX].Fill((sbyte)chromaRedQuantizationOffset); this.flags.DangerousGetRowSpan(row)[unitX..endX].Fill(packedFlags); } } @@ -207,18 +177,6 @@ internal sealed class HevcCodingTreeState : IDisposable public int GetQuantizationParameter(int x, int y) => this.quantizationParameters.DangerousGetRowSpan(y >> this.MinCodingBlockLog2)[x >> this.MinCodingBlockLog2]; - /// - /// Gets the combined chroma quantization-parameter offset at a luma sample coordinate. - /// - /// The Cb or Cr reconstruction plane. - /// The luma sample X coordinate. - /// The luma sample Y coordinate. - /// The selected picture, slice, and coding-unit offset. - public int GetChromaQuantizationOffset(HevcPlane plane, int x, int y) - => plane == HevcPlane.Cb - ? this.chromaBlueQuantizationOffsets.DangerousGetRowSpan(y >> this.MinCodingBlockLog2)[x >> this.MinCodingBlockLog2] - : this.chromaRedQuantizationOffsets.DangerousGetRowSpan(y >> this.MinCodingBlockLog2)[x >> this.MinCodingBlockLog2]; - /// /// Gets a value indicating whether the coding unit at a luma sample coordinate bypasses transform and quantization. /// @@ -246,8 +204,6 @@ internal sealed class HevcCodingTreeState : IDisposable { this.depths.Dispose(); this.quantizationParameters.Dispose(); - this.chromaBlueQuantizationOffsets.Dispose(); - this.chromaRedQuantizationOffsets.Dispose(); this.flags.Dispose(); } diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Deblocking.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Deblocking.cs index be2d11f66..1d3970017 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Deblocking.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Deblocking.cs @@ -246,7 +246,13 @@ internal sealed partial class HevcPictureDecoder int quantizationParameterP = codingTreeState.GetQuantizationParameter(pX, pY); int quantizationParameterQ = codingTreeState.GetQuantizationParameter(qX, qY); int averageQuantizationParameter = (quantizationParameterP + quantizationParameterQ + 1) >> 1; - int componentOffset = codingTreeState.GetChromaQuantizationOffset(plane, qX, qY); + + // Chroma deblocking uses only the picture-level component offset. Slice offsets and the RExt + // coding-unit adjustment affect inverse quantization, but H.265 excludes both from tc derivation. + int componentOffset = plane == HevcPlane.Cb + ? this.pictureParameterSet.ChromaCbQuantizationParameterOffset + : this.pictureParameterSet.ChromaCrQuantizationParameterOffset; + int chromaQuantizationParameter = HevcQuantizationParameters.GetChromaQuantizationParameter( averageQuantizationParameter, componentOffset, diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Prediction.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Prediction.cs index 6ebf0900c..754f94305 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Prediction.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Prediction.cs @@ -215,12 +215,15 @@ internal sealed partial class HevcPictureDecoder int bitDepth, int regionId) { + // PCM samples can use fewer bits than the reconstructed component. H.265 places those bits at the + // most-significant end of the component range, so the raw code value must be restored before filtering. + int bitDepthShift = this.Picture.GetBitDepth(plane) - bitDepth; for (int row = 0; row < height; row++) { Span destination = this.Picture.GetRowSpan(plane, y + row).Slice(x, width); for (int column = 0; column < width; column++) { - destination[column] = reader.ReadPcmSample(bitDepth); + destination[column] = (ushort)(reader.ReadPcmSample(bitDepth) << bitDepthShift); } } diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Traversal.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Traversal.cs index 10e242e8d..7e2bd4bef 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Traversal.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Traversal.cs @@ -351,15 +351,12 @@ internal sealed partial class HevcPictureDecoder default); } - HevcQuantizationParameters quantizationParameters = this.CreateQuantizationParameters(); this.codingTreeStates[colorPlaneIndex].SetCodingUnit( x, y, log2Size, depth, this.currentQuantizationParameter, - quantizationParameters.CbOffset, - quantizationParameters.CrOffset, transquantBypass, pcm); diff --git a/tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs index 9ea2832da..a8a5f4012 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs @@ -137,6 +137,68 @@ public class HevcPictureDecoderTests EntryPoints = 16, } + /// + /// Identifies Range Extensions syntax that an official independently decoded picture must exercise. + /// + [Flags] + public enum RangeExtensionTools + { + /// + /// No additional tool assertion is required beyond the profile, precision, chroma layout, and plane hashes. + /// + None = 0, + + /// + /// Cross-component residual prediction is enabled. + /// + CrossComponentPrediction = 1, + + /// + /// Luma and chroma use different sample precisions. + /// + UnequalBitDepth = 2, + + /// + /// Persistent Golomb-Rice adaptation is enabled. + /// + PersistentRice = 4, + + /// + /// Extended-precision transform processing is enabled. + /// + ExtendedPrecision = 8, + + /// + /// Pulse-code-modulated coding units are enabled. + /// + Pcm = 16, + + /// + /// Transform-skip-specific coefficient contexts are enabled. + /// + TransformSkipContext = 32, + + /// + /// Tile entry points are enabled. + /// + Tiles = 64, + + /// + /// Wavefront row entry points are enabled. + /// + Wavefront = 128, + + /// + /// CABAC bypass bins are byte-aligned. + /// + CabacBypassAlignment = 256, + + /// + /// A coding-unit chroma quantization-offset list is enabled. + /// + ChromaQuantizationAdjustment = 512, + } + /// /// Verifies the first independently coded picture from official ITU RExt conformance streams against its /// published decoded-picture hashes. @@ -168,7 +230,7 @@ public class HevcPictureDecoderTests { byte[] annexB = TestFile.Create(path).Bytes; byte[] expectedYuv = TestFile.Create($"{path[..^4]}_frame0.yuv").Bytes; - ConvertAnnexBStillPicture(annexB, bitDepth, chromaFormat, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, bitDepth, bitDepth, chromaFormat, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcSliceSegmentHeader sliceHeader = bitstream.SliceSegments[0]; @@ -206,6 +268,127 @@ public class HevcPictureDecoderTests } } + /// + /// Verifies the remaining supported Range Extensions profiles and independently coded tools against normative + /// decoded-picture hashes or first pictures from published reference output. + /// + /// The provenance-preserving extracted Annex B picture. + /// The signaled luma precision. + /// The signaled chroma precision. + /// The signaled HEVC chroma-format identifier. + /// The signaled HEVC profile identifier. + /// The Range Extensions syntax that the retained picture must enable. + /// The normative luma-plane MD5 digest. + /// The normative blue-difference-plane MD5 digest. + /// The normative red-difference-plane MD5 digest. + [Theory] + [InlineData(TestImages.Heif.RangeExtensionChromaAngle422, 10, 10, 2, 4, RangeExtensionTools.None, "90085930ec5de68c8e0c95ed59ec0ce4", "a2053b886e4d2b26569472c4e65865ca", "82fc61a1450dc6df0b87d1e17c4d66db")] + [InlineData(TestImages.Heif.RangeExtensionCrossComponent8Bit444, 8, 8, 3, 4, RangeExtensionTools.CrossComponentPrediction, "ab4619c33dc1f67d332ec1945acab23f", "2cc70454f33f32f97c7ecf244d858398", "c54605014b2e9133d66867bf572c3ac6")] + [InlineData(TestImages.Heif.RangeExtensionCrossComponent10Bit444, 10, 10, 3, 4, RangeExtensionTools.CrossComponentPrediction, "daa07e34beaa525d416211025b9ee73d", "7ca36368377b0c02cdf53767ea43c36a", "d2a777f65e1fe6c2e638ae0d4f8ad884")] + [InlineData(TestImages.Heif.RangeExtensionCrossComponent12Bit444, 12, 12, 3, 4, RangeExtensionTools.CrossComponentPrediction, "7bed50ae49c39dd30e1085e7578d3555", "d2a06b27ddfba5fd2f14463f5d88e10d", "1a06a414d88ec6a7819a464021b1e935")] + [InlineData(TestImages.Heif.RangeExtensionLuma12Chroma8, 12, 8, 3, 4, RangeExtensionTools.UnequalBitDepth, "c8a92f6c83830232615157130460aa52", "1a88d067a709f8d4ee66e608edcf1454", "7582e448a0ca0ec91d84e86264048c58")] + [InlineData(TestImages.Heif.RangeExtensionLuma8Chroma12, 8, 12, 3, 4, RangeExtensionTools.UnequalBitDepth, "0f0b9d9ae27e541854f985d2b4f1cb8c", "a1834614ecd2d873cf748af0d182fccd", "cc733d65275087e6ad480f98150139e5")] + [InlineData(TestImages.Heif.ExtendedPrecision8Bit444, 8, 8, 3, 4, RangeExtensionTools.ExtendedPrecision, "abef53fa20dab9ab755b51b6eafac2a8", "eb3fb765be767658b515ce4260a011e9", "e9f741b608b8c2c8efa4607c5fee6664")] + [InlineData(TestImages.Heif.ExtendedPrecision10Bit444, 10, 10, 3, 4, RangeExtensionTools.ExtendedPrecision, "0a6955b11ede15c22279186dcef5f75e", "3de15052d5e92ffc8cc98db58ed3db5c", "bfe0b418ca96bafc86953d9e0065315b")] + [InlineData(TestImages.Heif.ExtendedPrecision12Bit444, 12, 12, 3, 4, RangeExtensionTools.ExtendedPrecision, "c8664d56d8391b236a8347397eb97a08", "08cd345d8798ac2714b2939462ac45e2", "5424bce4562f298e983302da697db849")] + [InlineData(TestImages.Heif.HighThroughputExtendedPrecision8Bit444, 8, 8, 3, 5, RangeExtensionTools.ExtendedPrecision, "ca77f9c29a2d25266d33d77bea0edc66", "473d1bd93cfebffa04f99cfe7e37eb0d", "8ab614af0526c77685ade3c9bbde2510")] + [InlineData(TestImages.Heif.HighThroughputExtendedPrecision10Bit444, 10, 10, 3, 5, RangeExtensionTools.ExtendedPrecision, "635507721877b619dc04593abafcfb1d", "d486efd70d9d3cbc3bcd2110abab6e87", "2b9966cd21c5b1fba41e3c793a40ebcb")] + [InlineData(TestImages.Heif.HighThroughputExtendedPrecision12Bit444, 12, 12, 3, 5, RangeExtensionTools.ExtendedPrecision, "cf547552a75b5e7b819937b82abf7985", "f2b863051a7c8f9af29bddd18401f291", "39a89074bc70d212dfe082ce544a43a0")] + [InlineData(TestImages.Heif.RangeExtensionPcm10Bit422, 10, 10, 2, 4, RangeExtensionTools.Pcm, "32248d41f772b2f69ae921d59b19f878", "678aec54e4b2af3578d06eefd8d6d097", "072613ebc1393dc2a5c17f882d1476f1")] + [InlineData(TestImages.Heif.RangeExtensionPcm12Bit444, 12, 12, 3, 4, RangeExtensionTools.Pcm, "0d91f6c4b691e47f48cf039b6c948d50", "5578d8774855b2a52f26cffda0edf10c", "e7860063b7b05ff55cf8ad981d08ee0f")] + [InlineData(TestImages.Heif.PersistentRice12Bit444, 12, 12, 3, 4, RangeExtensionTools.PersistentRice, "ddea37dedd9b541aaf371351d73e821b", "eb611e94654b76eb14fbcf20295a33ec", "b1655845f49114550fd26ab722ccc335")] + [InlineData(TestImages.Heif.TransformSkipContext8Bit444, 8, 8, 3, 4, RangeExtensionTools.TransformSkipContext, "c148a3f5610b0ec1369b702fc1383445", "82b10517c01f4fe5ca0aa19f5f8f2a0a", "29a841e63b5bf84fd9f8734dcc5df4e7")] + [InlineData(TestImages.Heif.TransformSkipContext10Bit444, 10, 10, 3, 4, RangeExtensionTools.TransformSkipContext, "006f3314efb25b15adc1c734fe7845b0", "99fa977f7603eeaa4981d9ac08b5aec1", "16aa20a082b534aec5e91bc9924060d3")] + [InlineData(TestImages.Heif.TransformSkipContext12Bit444, 12, 12, 3, 4, RangeExtensionTools.TransformSkipContext, "f26cffd119796bcbd2c4730eac6cc0c7", "e12a6a3faccadc8cf77952a7ef443c27", "f96fff6246848c9bd6808d65d1f3337d")] + [InlineData(TestImages.Heif.Main42210A, 10, 10, 2, 4, RangeExtensionTools.ChromaQuantizationAdjustment, "41746faffb59051c7b9002d7c79dc05d", "5180c8020b597bc66d0c1ec3a35656f6", "44140b531120e0737afc57fb25d16207")] + [InlineData(TestImages.Heif.Main42210B, 10, 10, 2, 4, RangeExtensionTools.ChromaQuantizationAdjustment, "845e930817261106c8edb352a1cdc9d6", "ca1e0aa4fd8ea6ba6ebacb3997bc32d1", "4377426b33fee59375d9dedd3b1eee9b")] + [InlineData(TestImages.Heif.HighThroughput10Bit422TilesWavefront, 10, 10, 2, 5, RangeExtensionTools.Tiles | RangeExtensionTools.Wavefront, "efd80653065c89989303827c56eca1ad", "7966084cebcd537109bf49084de31ced", "8030bdf42331b9a1033d0c62ce3ea452")] + [InlineData(TestImages.Heif.HighThroughput8Bit420TilesWavefront, 8, 8, 1, 5, RangeExtensionTools.Tiles | RangeExtensionTools.Wavefront, "6a99581bc96d002befb1bc6ef1c610aa", "79c51aa1ea347d81edcd7a2128e14060", "103dcfa2c88f4d98a24044a0e283cf87")] + [InlineData(TestImages.Heif.HighThroughput8Bit420Wavefront, 8, 8, 1, 5, RangeExtensionTools.Wavefront, "6b7404a197543d0adb7a2711b04273c2", "2f0e9ce1af96ff80ad2c5028d0109685", "a5d0b489441120fe235b7110f4fcaa45")] + [InlineData(TestImages.Heif.HighThroughput8Bit420CabacBypassAlignment, 8, 8, 1, 5, RangeExtensionTools.Tiles | RangeExtensionTools.Wavefront | RangeExtensionTools.CabacBypassAlignment, "6a783152cea8c612766d2173f2a30c5b", "9329df9e4ad589dfc24ac64acc9db1ea", "b01428a538cd555d61a9d3e950faf1cd")] + [InlineData(TestImages.Heif.HighThroughput8Bit420ExtendedPrecision, 8, 8, 1, 5, RangeExtensionTools.Tiles | RangeExtensionTools.Wavefront | RangeExtensionTools.ExtendedPrecision, "2e49cc92405a262f3b0065b764c96c7c", "f2f7073c45814147362ae156eadaaaa9", "b002b9b7a0da39301d112666ce4435d9")] + public void DecodeOfficialRangeExtensionProfilePictureMatchesDecodedPictureHash( + string path, + int bitDepthLuma, + int bitDepthChroma, + byte chromaFormat, + byte profileIdc, + RangeExtensionTools requiredTools, + string lumaDigest, + string chromaBlueDigest, + string chromaRedDigest) + { + byte[] annexB = TestFile.Create(path).Bytes; + ConvertAnnexBStillPicture(annexB, bitDepthLuma, bitDepthChroma, chromaFormat, 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); + + Assert.Equal(profileIdc, sequenceParameterSet.ProfileTierLevel.ProfileIdc); + Assert.Equal(bitDepthLuma, decoder.Picture.BitDepthLuma); + Assert.Equal(bitDepthChroma, decoder.Picture.BitDepthChroma); + Assert.Equal(chromaFormat, decoder.Picture.ChromaFormat); + if ((requiredTools & RangeExtensionTools.CrossComponentPrediction) != 0) + { + Assert.True(pictureParameterSet.CrossComponentPredictionEnabled); + } + + if ((requiredTools & RangeExtensionTools.UnequalBitDepth) != 0) + { + Assert.NotEqual(decoder.Picture.BitDepthLuma, decoder.Picture.BitDepthChroma); + } + + if ((requiredTools & RangeExtensionTools.PersistentRice) != 0) + { + Assert.True(sequenceParameterSet.PersistentRiceAdaptationEnabled); + } + + if ((requiredTools & RangeExtensionTools.ExtendedPrecision) != 0) + { + Assert.True(sequenceParameterSet.ExtendedPrecisionProcessingEnabled); + } + + if ((requiredTools & RangeExtensionTools.Pcm) != 0) + { + Assert.True(sequenceParameterSet.PcmEnabled); + } + + if ((requiredTools & RangeExtensionTools.TransformSkipContext) != 0) + { + Assert.True(pictureParameterSet.TransformSkipEnabled); + Assert.True(sequenceParameterSet.TransformSkipContextEnabled); + } + + if ((requiredTools & RangeExtensionTools.Tiles) != 0) + { + Assert.True(pictureParameterSet.TilesEnabled); + } + + if ((requiredTools & RangeExtensionTools.Wavefront) != 0) + { + Assert.True(pictureParameterSet.EntropyCodingSynchronizationEnabled); + } + + if ((requiredTools & RangeExtensionTools.CabacBypassAlignment) != 0) + { + Assert.True(sequenceParameterSet.CabacBypassAlignmentEnabled); + } + + if ((requiredTools & RangeExtensionTools.ChromaQuantizationAdjustment) != 0) + { + Assert.NotEmpty(pictureParameterSet.ChromaQuantizationParameterOffsetsCb); + Assert.NotEmpty(pictureParameterSet.ChromaQuantizationParameterOffsetsCr); + } + + Assert.Equal(lumaDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Y)); + Assert.Equal(chromaBlueDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cb)); + Assert.Equal(chromaRedDigest, GetPlaneDigest(decoder.Picture, HevcPlane.Cr)); + } + /// /// Verifies the official Main Still Picture stream containing every luma and chroma intra mode at every /// conformance block size against its published native planar output. @@ -215,7 +398,7 @@ public class HevcPictureDecoderTests { byte[] annexB = TestFile.Create(TestImages.Heif.IntraPredictionB).Bytes; byte[] expectedYuv = TestFile.Create(TestImages.Heif.IntraPredictionBReference).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcPictureParameterSet pictureParameterSet = bitstream.SliceSegments[0].PictureParameterSet; @@ -252,7 +435,7 @@ public class HevcPictureDecoderTests public void DecodeOfficialConstrainedIntraPictureMatchesPublishedDigest() { byte[] annexB = TestFile.Create(TestImages.Heif.ConstrainedIntraPredictionA).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcPictureParameterSet pictureParameterSet = bitstream.SliceSegments[0].PictureParameterSet; @@ -296,7 +479,7 @@ public class HevcPictureDecoderTests string chromaRedDigest) { byte[] annexB = TestFile.Create(path).Bytes; - ConvertAnnexBStillPicture(annexB, bitDepth, chromaFormat, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, bitDepth, bitDepth, chromaFormat, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcPictureParameterSet pictureParameterSet = bitstream.SliceSegments[0].PictureParameterSet; @@ -374,7 +557,7 @@ public class HevcPictureDecoderTests public void DecodeOfficialLoopFilterPictureWithConstrainedAllocatorMatchesPinnedHmDigest() { byte[] annexB = TestFile.Create(TestImages.Heif.SampleAdaptiveOffsetA).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration codecConfiguration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, codecConfiguration); TestMemoryAllocator allocator = new() { BufferCapacityInBytes = 2_048 }; @@ -468,7 +651,7 @@ public class HevcPictureDecoderTests string chromaRedDigest) { byte[] annexB = TestFile.Create(path).Bytes; - ConvertAnnexBStillPicture(annexB, bitDepth, chromaFormat, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, bitDepth, bitDepth, chromaFormat, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcSliceSegmentHeader sliceHeader = bitstream.SliceSegments[0]; @@ -520,7 +703,7 @@ public class HevcPictureDecoderTests string chromaRedDigest) { byte[] annexB = TestFile.Create(path).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcSequenceParameterSet sequenceParameterSet = bitstream.SliceSegments[0].PictureParameterSet.SequenceParameterSet; @@ -578,7 +761,7 @@ public class HevcPictureDecoderTests string chromaRedDigest) { byte[] annexB = TestFile.Create(path).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration configuration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, configuration); HevcPictureParameterSet pictureParameterSet = bitstream.SliceSegments[0].PictureParameterSet; @@ -642,7 +825,7 @@ public class HevcPictureDecoderTests string chromaRedDigest) { byte[] annexB = TestFile.Create(path).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration codecConfiguration = new(configurationData); HevcImageItemBitstream bitstream = new(itemData, codecConfiguration); TestMemoryAllocator allocator = new() { BufferCapacityInBytes = 4_096 }; @@ -781,7 +964,7 @@ public class HevcPictureDecoderTests public void DecodeRejectsNonDisplayAndConflictingSupplementalMetadata() { byte[] annexB = TestFile.Create(TestImages.Heif.IntraPredictionB).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration codecConfiguration = new(configurationData); HeifItem item = new(Heif4CharCode.Hvc1, 1) { HevcCodecConfiguration = codecConfiguration }; HevcHeifItemDecoder itemDecoder = new(); @@ -1061,7 +1244,7 @@ public class HevcPictureDecoderTests // intrinsics, so the remote process cannot obtain the test's cancellation token. CancellationToken cancellationToken = CancellationToken.None; byte[] annexB = TestFile.Create(TestImages.Heif.IntraPredictionB).Bytes; - ConvertAnnexBStillPicture(annexB, 8, 1, out byte[] configurationData, out byte[] itemData); + ConvertAnnexBStillPicture(annexB, 8, 8, 1, out byte[] configurationData, out byte[] itemData); HevcCodecConfiguration codecConfiguration = new(configurationData); HeifItem item = new(Heif4CharCode.Hvc1, 1) { HevcCodecConfiguration = codecConfiguration }; byte[] supplementalItemData = PrependPrefixSeiNalUnit(itemData, SupplementalMetadataRbsp); @@ -1287,13 +1470,15 @@ public class HevcPictureDecoderTests /// production decoder. /// /// The complete official conformance stream. - /// The stream's published component precision. + /// The stream's published luma precision. + /// The stream's published chroma precision. /// The stream's published chroma-format identifier. /// The generated item-local HEVC decoder configuration. /// The generated length-delimited payload containing only the first picture. private static void ConvertAnnexBStillPicture( ReadOnlySpan annexB, - int bitDepth, + int bitDepthLuma, + int bitDepthChroma, byte chromaFormat, out byte[] configurationData, out byte[] itemData) @@ -1377,8 +1562,8 @@ public class HevcPictureDecoderTests configurationData[13] = 0xF0; // reserved and min_spatial_segmentation_idc = 0 configurationData[15] = 0xFC; // reserved and parallelismType = 0 configurationData[16] = (byte)(0xFC | chromaFormat); // reserved and chromaFormat - configurationData[17] = (byte)(0xF8 | (bitDepth - 8)); // reserved and bitDepthLumaMinus8 - configurationData[18] = (byte)(0xF8 | (chromaFormat == 0 ? 0 : bitDepth - 8)); // reserved and bitDepthChromaMinus8 + configurationData[17] = (byte)(0xF8 | (bitDepthLuma - 8)); // reserved and bitDepthLumaMinus8 + configurationData[18] = (byte)(0xF8 | (chromaFormat == 0 ? 0 : bitDepthChroma - 8)); // reserved and bitDepthChromaMinus8 int maxSubLayers = ((spsRbspPrefix[0] >> 1) & 7) + 1; int temporalIdNesting = spsRbspPrefix[0] & 1; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d08f60c39..af2b51da4 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1304,6 +1304,30 @@ 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 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 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"; + public const string HighThroughputExtendedPrecision10Bit444 = "Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit"; + public const string HighThroughputExtendedPrecision12Bit444 = "Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.bit"; + public const string RangeExtensionPcm10Bit422 = "Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0.bit"; + public const string RangeExtensionPcm12Bit444 = "Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0.bit"; + public const string PersistentRice12Bit444 = "Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0.bit"; + public const string TransformSkipContext8Bit444 = "Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0.bit"; + public const string TransformSkipContext10Bit444 = "Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0.bit"; + public const string TransformSkipContext12Bit444 = "Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0.bit"; + public const string Main42210A = "Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0.bit"; + public const string Main42210B = "Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0.bit"; + public const string HighThroughput10Bit422TilesWavefront = "Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.bit"; + public const string HighThroughput8Bit420TilesWavefront = "Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit"; + 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 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"; diff --git a/tests/Images/Input/Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.bit new file mode 100644 index 000000000..4755dd43c --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56924b6d5c19e5147649973d13a5ddd83af402fd3dca41b2698d03515b4bb2d7 +size 77368 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/Bitdepth_A_RExt_Sony_1_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/Bitdepth_A_RExt_Sony_1_frame0.bit new file mode 100644 index 000000000..4e46a40af --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/Bitdepth_A_RExt_Sony_1_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19206fe90232d5cc99cadd70a663a303ec0a27f64539bbf155012461e8c14b8d +size 26723 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/Bitdepth_B_RExt_Sony_1_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/Bitdepth_B_RExt_Sony_1_frame0.bit new file mode 100644 index 000000000..08bfd07ce --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/Bitdepth_B_RExt_Sony_1_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e8bb3d6ad34078bd5319aebc52c4f64a3999cf6fb529808dc7e9a3d51a69c4b +size 26751 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0.bit new file mode 100644 index 000000000..744fc3720 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/CCP_10bit_RExt_QCOM_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e92952c1da523290592c98b766656964299bac330a357851980f71331b920ee4 +size 44331 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0.bit new file mode 100644 index 000000000..83f89c0c0 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/CCP_12bit_RExt_QCOM_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:33c20dd58a4ae2e16e412bb00ec8def0d071ab6959a8821ea9410405c732ea4e +size 365428 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0.bit new file mode 100644 index 000000000..8ac51c3f6 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/CCP_8bit_RExt_QCOM_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bb969c41f2eb6664ba29bcbd71a094c76add86df6a2c6c49e90d1f3265952f2 +size 28905 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit new file mode 100644 index 000000000..2a16e0a55 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3572e1c350bd60ba6b0edd71bae1388ccd4d57a1c18c7d62439fa1661e33980c +size 149305 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.bit b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.bit new file mode 100644 index 000000000..eaa304262 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15026126bbaa266f5551077bf1a29018ef11d5aa274ae3aadfd282184c1837b0 +size 206758 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit new file mode 100644 index 000000000..1867c6c63 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5584b06fbf9affc87d3f1bffa56ecfadb892a80ed6468401a2acf46622444d66 +size 93552 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit new file mode 100644 index 000000000..660d620c6 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28f0fa43f8c9a5c80c2158b087ed030d8e3e8deac6819239ba84890302a8f30a +size 148045 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit new file mode 100644 index 000000000..819e7ea7c --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abace12c9947acaaf91bf8e4cb8bf50cd5ff5b2a7ab5a14d9ee25fe2cdf6b746 +size 92709 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0.bit new file mode 100644 index 000000000..bdf499e96 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/IPCM_A_RExt_NEC_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26ae7aefa4ded2ccdc917b99b5ecf2352bd9c7100ce0cfd9a9bdc918c5d242b6 +size 4273 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0.bit new file mode 100644 index 000000000..3f71b427f --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/IPCM_B_RExt_NEC_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39f97b25079ce5f12340cce43c9dbd5821c5e23f44da58dd6f1942e135bc93b5 +size 4973 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0.bit new file mode 100644 index 000000000..204075e6c --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_A_RExt_Sony_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d6dd0506e85bfd17cfd8d676107927c2860d38d1e8b7e5486647279e6b33876 +size 632639 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0.bit new file mode 100644 index 000000000..c3fc445cf --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/Main_422_10_B_RExt_Sony_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:951acc9c846dcb9f8ccbdc0b6971a947144baed2d9021ae4be77bcce106bbe21 +size 1113811 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0.bit new file mode 100644 index 000000000..868082e00 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/PERSIST_RPARAM_A_RExt_Sony_3_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6a86ff4122512fda96ec6c4c7a143079eee5371760433c05428749140036cec +size 329271 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/README.md b/tests/Images/Input/Heif/Hevc/Conformance/README.md index 259d6f61d..dab1b573d 100644 --- a/tests/Images/Input/Heif/Hevc/Conformance/README.md +++ b/tests/Images/Input/Heif/Hevc/Conformance/README.md @@ -6,7 +6,7 @@ The `.bit` files are the original Annex B conformance streams. The Samsung archi `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 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. The tool-specific matrix below completes independently coded coverage for the exposed Range Extensions profiles and tools. Explicit residual DPCM remains with dependent-picture inter decoding because the normative syntax requires an inter prediction unit. 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. @@ -31,6 +31,39 @@ The residual-reconstruction fixtures come from the official HEVC v1 and Range Ex - `GENERAL_12b_444_RExt_Sony_2_idr7.bit` is the seventh independently coded picture extracted with its active VPS, SPS, and PPS from the already retained official GENERAL stream. It has SHA-256 `981D97F0ADC228F2E3A739D7A68161F84CD60309745397D5CF24D2F81C009DBC` and contains 39 coding-unit chroma-QP adjustment decisions across 8-, 16-, and 32-sample chroma transforms. - `LS_A_Orange_2.bit` has SHA-256 `14251238F005A4576437429A327B34D216B346AAAC2A7A05C132A3430174B11B` and published MD5 `9118d01cf6b3671038d6f99342c0895e`. The official lossless description states that every coding unit uses transform, quantization, and filtering bypass; the retained first picture exercises the bypass-flag path and its decoded-picture hash reports OK. +The remaining Range Extensions fixtures come from the official H.265.1 RExt attachment. Each retained file contains the active VPS, SPS, and PPS followed by exactly one independently coded picture. For the extended-precision streams, the retained picture is the second concatenated one-picture sequence because that sequence enables extended-precision processing. `HevcPictureDecoderTests.DecodeOfficialRangeExtensionProfilePictureMatchesDecodedPictureHash` checks profile identifier, luma and chroma precision, chroma layout, required tool flags, and every native-plane MD5 through the production still-item decoder. + +The expected plane hashes come directly from each selected picture's decoded-picture-hash SEI message when present. The CCP 8/10/12-bit, IPCM A/B, and Main 4:2:2 10 B streams omit that per-picture message. Their first reference pictures were extracted only after FFmpeg 9.0.1 reproduced the archives' published complete-output MD5 values `54231c6f121ca65d8b94a747b9504b8b`, `363f55fc6097a3bb7525392b87a6498a`, `f3e914fccdb820eac85f46642ea0e168`, `8d4eb18812338f9f475035b8da27e74a`, `eea32e6e1f88b7782515e53f8122be7d`, and `fd163bcbdc24792a23781ee7aace74eb`, respectively. + +The SHA-256 columns below identify the downloaded archive, its original Annex B payload, and the retained bounded picture: + +| Retained picture | Archive SHA-256 | Original payload SHA-256 | Retained SHA-256 | +| --- | --- | --- | --- | +| `ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2_frame0.bit` | `8C915B0554265CCD6FB1347B41788006DF9E7C66349FDEAA142D953340B12997` | `54B72F9B2F5BD7C25049A63FD4289AB19735AF5B30C2105DEDD7AA5AE90A72E8` | `56924B6D5C19E5147649973D13A5DDD83AF402FD3DCA41B2698D03515B4BB2D7` | +| `Bitdepth_A_RExt_Sony_1_frame0.bit` | `34967E2047D59B0F3E96E7501712A056C01F369501D812B170C717CE1D417368` | `0519F266D11FAD0A25878F29D5DAC153BA00629AACEF34ECD78F5F5AD0FB2174` | `19206FE90232D5CC99CADD70A663A303EC0A27F64539BBF155012461E8C14B8D` | +| `Bitdepth_B_RExt_Sony_1_frame0.bit` | `6F5F16377E9287CED1AD06A9493249ED1D61E393D779B06E777A92E14B6C6EB6` | `C8B03A11E8453E430E41BC499F686BE9E75CEF269F80CCAB85C971D048A91EA8` | `0E8BB3D6AD34078BD5319AEBC52C4F64A3999CF6FB529808DC7E9A3D51A69C4B` | +| `CCP_8bit_RExt_QCOM_frame0.bit` | `E5A0216C23F3816107441366B7743160BD0E6A39CE15B14A9FE1A3FFEA38BF88` | `C5E0D9B5E0062C2F4BFB1EC9E8A6465FB715E3AF498306D7D0E4BEC0BC9BAE5C` | `2BB969C41F2EB6664BA29BCBD71A094C76ADD86DF6A2C6C49E90D1F3265952F2` | +| `CCP_10bit_RExt_QCOM_frame0.bit` | `190AB9B4A9AADEE32ECFB639223156A3DEE721DBBA064C28574E176CE07FF032` | `6E40E49BA5BEF61D951C4088B0234DB20E1F264804C59A007B9F32A117A45603` | `E92952C1DA523290592C98B766656964299BAC330A357851980F71331B920EE4` | +| `CCP_12bit_RExt_QCOM_frame0.bit` | `E54417A143D59BA112D90355BE88E535761A22EC44C88BDA5C4913ED0B3CE7F3` | `17FD17F2449B4C44D4AFDADDAC9FE1A61B572E1BD4BF1FBDAC609E108A7F2BD3` | `33C20DD58A4AE2E16E412BB00EC8DEF0D071AB6959A8821EA9410405C732EA4E` | +| `EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit` | `7EBC6DB0E9BFBCEEEF1F168843E824CDD2B3A672C9574ECEEA9ADA8F41A37A37` | `52DEF2115F3FF5D2B4E1BCDD702B893DF280B83CD6D0DDED940735E6899556A8` | `ABACE12C9947ACAAF91BF8E4CB8BF50CD5FF5B2A7AB5A14D9EE25FE2CDF6B746` | +| `EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit` | `1120A6B1CC6D1E8AF5CF2D9980A5D4AC2C8C83217E570900D5C45BC6CD92403A` | `8760ABA893522FE302C14C8472677FED3C3A29B241918A49067F12107F6B5FDE` | `28F0FA43F8C9A5C80C2158B087ED030D8E3E8DEAC6819239BA84890302A8F30A` | +| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1_extended.bit` | `B7D3993DC6AA87E86D09C245665FB13F6F970E14DFE75AB25F7EE689C3BB78A0` | `07C7A14717FFFB5828D9B3472D1DB1DE554ACB9A126D34CA4E73EF1ED6F68734` | `5584B06FBF9AFFC87D3F1BFFA56ECFADB892A80ED6468401A2ACF46622444D66` | +| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1_extended.bit` | `445D8EF653C1C37495B62C6AFBE11006218131540289CDE5B35DFAFBA4ACF975` | `5FE487203641FDC5920C2FBC85F1A0E329A01462E18862850B42890F90F148AE` | `3572E1C350BD60BA6B0EDD71BAE1388CCD4D57A1C18C7D62439FA1661E33980C` | +| `EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1_extended.bit` | `78DF34AC5602D59A67730E231CA86A6F1E41D4B9E6967C6FBB31AFD276B2D4F8` | `BEBB8D008469343017680082D847309A0122F3133B9A8296D5BEA8F402D3F445` | `15026126BBAA266F5551077BF1A29018EF11D5AA274AE3AADFD282184C1837B0` | +| `IPCM_A_RExt_NEC_2_frame0.bit` | `CC78DF0AA70ED8536B002B48EA7FEACF72AB703BBA7E5286C290D02D1EB51308` | `26AE7AEFA4DED2CCDC917B99B5ECF2352BD9C7100CE0CFD9A9BDC918C5D242B6` | `26AE7AEFA4DED2CCDC917B99B5ECF2352BD9C7100CE0CFD9A9BDC918C5D242B6` | +| `IPCM_B_RExt_NEC_frame0.bit` | `B248E35A32F76F3384DDFB3EA7727B7D088AE977B3C649E152CCA06149F546CE` | `39F97B25079CE5F12340CCE43C9DBD5821C5E23F44DA58DD6F1942E135BC93B5` | `39F97B25079CE5F12340CCE43C9DBD5821C5E23F44DA58DD6F1942E135BC93B5` | +| `Main_422_10_A_RExt_Sony_2_frame0.bit` | `7618CCC9C836EEC9A981910F4E0E46DC36936D620755857005CF6F85BBD5CC84` | `4004FE9C86D10F36ACC6E111B8E6A473351CEECEB6B0649F1D3EFB442D27A231` | `5D6DD0506E85BFD17CFD8D676107927C2860D38D1E8B7E5486647279E6B33876` | +| `Main_422_10_B_RExt_Sony_2_frame0.bit` | `9A8CB40F0AC87635ADA427EFE80DEAAD7FE45C8ABD2E72BEF258D5EC0914C086` | `951ACC9C846DCB9F8CCBDC0B6971A947144BAED2D9021AE4BE77BCCE106BBE21` | `951ACC9C846DCB9F8CCBDC0B6971A947144BAED2D9021AE4BE77BCCE106BBE21` | +| `PERSIST_RPARAM_A_RExt_Sony_3_frame0.bit` | `8237DFE09F09E9AD390C04A30FA57D66F26AB75B9DA90C6B482BA1330DCDBEBB` | `5E1A69D29278E3E4CBD7695C7D3C229AC63C1E5E2B7AF3B1C8F8062586EA1468` | `B6A86FF4122512FDA96EC6C4C7A143079EEE5371760433C05428749140036CEC` | +| `TSCTX_8bit_I_RExt_SHARP_1_frame0.bit` | `E15D63CF239A2F4297EA6EE1E404CB02F19862929270448D0668BD01A5A3D352` | `FCB7B066FF751FE3BA72C0583D289C73B61BE3DB59691B4423ED10B9F00A5F25` | `2849C0B451F6DF2945903B5274E59C87D30E439744FAC6B5E9ECB7014EF23488` | +| `TSCTX_10bit_I_RExt_SHARP_1_frame0.bit` | `813F1951C6EB2C1F469098A05D72FBB23BE0FD1C9D15FCB93C54DA74C0FE9169` | `4B62369D263F475DD560D9F129760100C3EE429F14A515DA23D5A7A622B9368A` | `C27C76EA271243EF36D372F86551012E9E2380D92DEAED84F0E2218108810696` | +| `TSCTX_12bit_I_RExt_SHARP_1_frame0.bit` | `96CC6851668F4968EB439FC4E4823E73394415C4D26B9032AB5EC401E753F0FC` | `7A9608103F06AA750F0A07ABE42693F87B77E38EE7BBF2E47D1D0AF9A1CD958D` | `A5A766D2CEB72DEFF1006107A5A5E65290434F2CCA9EBAAA1696E9EF19898067` | +| `WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.bit` | `C813326651E42576644264EA0F82D03DD79081F6E3163C1C0F283EE6AC03F4C2` | `25DBD378D19E10B020F413213A3CA183FF4C5132500DDECF84D7D9D22218F301` | `DA432C41E52F4DB66B8D2878D8A14A95A9320F4252851EC3242DD3800034377F` | +| `WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit` | `E0703E36A275DB2715D2051C72F0B4FC392C3CBA9421C069FD58EE037823C8DD` | `00075C57F3C1E17619904B60C5352C52814EAFF495012DF453763FE7A5DCB9F2` | `B5EAC077AA30EE4D228F5D89DA9EFD1588BF046B8F521D55C4E53A9455B99217` | +| `WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit` | `FDFD79B04A4FAEC48E7536E4FFCF692B84B2C5945253A9E8EDFA382816B27335` | `2B7110F868BFB62DA8282A0A6300408D7ABAD70A5A940A6A0BA1FBC69536F870` | `741854FDF832F4BD144FB9F68E49119FE4094C5305EEC00472129F00C1690261` | +| `WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit` | `A852B1501950E9CE50827FD7E65043511115FFC6ACA0E5E68A1B6B25932172B9` | `BDC2868A887A56A58AAEF4046F4341525C320616834189C9E2D2F582E08340C7` | `25FD77A0BB9E41A7AD145CBBAB044F981508C506FD25B8F8F6155EB71EC082C2` | +| `WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit` | `4D8135BD94FE6EEFFD58E162999241F6068CCCB67C377C18A18C25B33EF34A1D` | `BE5BE06A8DD2C873E8B386B4E4EAB2F45713277F1D6F2E6BDE5C96E6D7426AF4` | `A6DAE7D643DCB2918465D82347877E6BB70F8BE30C3F9D90C9515DC4DF55A468` | + The loop-filter fixtures are the unchanged Annex B payloads from the official HEVC v1 and Range Extensions archives. `HevcPictureDecoderTests.DecodeOfficialLoopFilterPictureMatchesPinnedHmDigest` retains each first independently coded picture, verifies its signaled precision and chroma layout, and compares every native plane with output from the pinned HIGH_BITDEPTH HM decoder. The feature-runner companion repeats the same production decoder path through every available SIMD tier and the scalar fallback. - `DBLK_A_SONY_3.bit` is the 8-bit 4:2:0 deblocking stream. The archive SHA-256 is `CE18CD42375359B9FF293D12A95793CC6B56EB75D899AD012C68E25DFA54DFBF`, and the bitstream SHA-256 is `D61A13E04A1678816C0F16CF7A47F5BB918DE95ECF1B6FAB305E2390C3DD7DE9`. Pinned HM reproduces the published complete-output MD5 `42486a48ea12d5ab6cd98ed2e2807cfe`; the retained first picture has Y, Cb, and Cr MD5 values `3ea2c2ef1f973345111480e7658908b3`, `0390b32143b1a832a385f78229e7e574`, and `8388f3a8af827da46f1fb52941ec00ad`. diff --git a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0.bit new file mode 100644 index 000000000..e4bf33b4e --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_10bit_I_RExt_SHARP_1_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c27c76ea271243ef36d372f86551012e9e2380d92deaed84f0e2218108810696 +size 165113 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0.bit new file mode 100644 index 000000000..7a894a09a --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_12bit_I_RExt_SHARP_1_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a5a766d2ceb72deff1006107a5a5e65290434f2cca9ebaaa1696e9ef19898067 +size 382534 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0.bit new file mode 100644 index 000000000..deba4e447 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/TSCTX_8bit_I_RExt_SHARP_1_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2849c0b451f6df2945903b5274e59c87d30e439744fac6b5e9ecb7014ef23488 +size 165586 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.bit new file mode 100644 index 000000000..ab4f9f6cf --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_10Bit422Test_HIGH_TP_444_10BIT_RExt_Apple_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da432c41e52f4db66b8d2878d8a14a95a9320f4252851ec3242dd3800034377f +size 37152 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.bit b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit new file mode 100644 index 000000000..c6c7164d9 --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_BYPASS_ALIGN_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25fd77a0bb9e41a7ad145cbbab044f981508c506fd25b8f8f6155eb71ec082c2 +size 42150 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.bit b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit new file mode 100644 index 000000000..9ad5d1dad --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_AND_CABAC_EXT_PREC_1_HIGH_TP_444_14BIT_RExt_Apple_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6dae7d643dcb2918465d82347877e6bb70f8be30c3f9d90c9515dc4df55a468 +size 41800 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit new file mode 100644 index 000000000..25ba27fdd --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/WPP_AND_TILE_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5eac077aa30ee4d228f5d89da9efd1588bf046b8f521d55c4e53a9455b99217 +size 41776 diff --git a/tests/Images/Input/Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit b/tests/Images/Input/Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit new file mode 100644 index 000000000..18068e86c --- /dev/null +++ b/tests/Images/Input/Heif/Hevc/Conformance/WPP_HIGH_TP_444_8BIT_RExt_Apple_2_frame0.bit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:741854fdf832f4bd144fb9f68e49119fe4094c5305eec00472129f00c1690261 +size 41569