Browse Source

Correct HEVC intra edge filtering

pull/2633/head
James Jackson-South 1 week ago
parent
commit
dbe310b51f
  1. 13
      src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Prediction.cs
  2. 2
      src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.TransformTree.cs
  3. 1
      tests/ImageSharp.Tests/Formats/Heif/Hevc/HevcPictureDecoderTests.cs
  4. 2
      tests/ImageSharp.Tests/TestImages.cs
  5. 3
      tests/Images/Input/Heif/Hevc/image2-tile7-hm.yuv
  6. 3
      tests/Images/Input/Heif/Hevc/image2-tile7.hvc1

13
src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.Prediction.cs

@ -17,8 +17,9 @@ internal sealed partial class HevcPictureDecoder
/// <param name="log2Size">The base-two logarithm of the square prediction-block side.</param> /// <param name="log2Size">The base-two logarithm of the square prediction-block side.</param>
/// <param name="regionId">The current independent-slice and tile prediction region.</param> /// <param name="regionId">The current independent-slice and tile prediction region.</param>
/// <param name="colorPlaneIndex">The selected separate-color plane, or zero for combined coding.</param> /// <param name="colorPlaneIndex">The selected separate-color plane, or zero for combined coding.</param>
/// <param name="transquantBypass">Whether the governing coding unit bypasses inverse quantization and transform.</param>
/// <returns>The packed predicted samples.</returns> /// <returns>The packed predicted samples.</returns>
private Span<ushort> PredictComponentBlock(HevcPlane plane, int x, int y, int log2Size, int regionId, int colorPlaneIndex) private Span<ushort> PredictComponentBlock(HevcPlane plane, int x, int y, int log2Size, int regionId, int colorPlaneIndex, bool transquantBypass)
{ {
int size = 1 << log2Size; int size = 1 << log2Size;
int sampleCount = size * size; int sampleCount = size * size;
@ -69,6 +70,14 @@ internal sealed partial class HevcPictureDecoder
mode = HevcIntraPredictionMode.RemapChroma422(mode); mode = HevcIntraPredictionMode.RemapChroma422(mode);
} }
// H.265 8.4.4.2.3 and 8.4.4.2.6 restrict prediction-edge filtering to luma blocks no larger than 16 samples.
// Implicit RDPCM bypasses that filtering for the lossless horizontal and vertical prediction modes.
bool filterPredictionEdges = useLumaSyntax
&& size <= 16
&& !(transquantBypass
&& this.sequenceParameterSet.ImplicitResidualDpcmEnabled
&& (mode == HevcIntraPredictionMode.Horizontal || mode == HevcIntraPredictionMode.Vertical));
bool filterReferences = HevcIntraPredictor.ShouldFilterReferenceSamples( bool filterReferences = HevcIntraPredictor.ShouldFilterReferenceSamples(
useLumaSyntax ? HevcPlane.Y : plane, useLumaSyntax ? HevcPlane.Y : plane,
mode, mode,
@ -101,7 +110,7 @@ internal sealed partial class HevcPictureDecoder
log2Size, log2Size,
mode, mode,
this.Picture.GetBitDepth(plane), this.Picture.GetBitDepth(plane),
useLumaSyntax, filterPredictionEdges,
operationScratch); operationScratch);
return prediction; return prediction;

2
src/ImageSharp/Formats/Heif/Hevc/HevcPictureDecoder.TransformTree.cs

@ -369,7 +369,7 @@ internal sealed partial class HevcPictureDecoder
Span<int> dequantized = integerScratch.Slice(MaximumTransformSampleCount, MaximumTransformSampleCount); Span<int> dequantized = integerScratch.Slice(MaximumTransformSampleCount, MaximumTransformSampleCount);
Span<int> residual = integerScratch.Slice(MaximumTransformSampleCount * 2, MaximumTransformSampleCount); Span<int> residual = integerScratch.Slice(MaximumTransformSampleCount * 2, MaximumTransformSampleCount);
Span<int> transformScratch = integerScratch.Slice(MaximumTransformSampleCount * 4, MaximumTransformSampleCount * 2); Span<int> transformScratch = integerScratch.Slice(MaximumTransformSampleCount * 4, MaximumTransformSampleCount * 2);
Span<ushort> prediction = this.PredictComponentBlock(plane, x, y, log2Size, regionId, colorPlaneIndex); Span<ushort> prediction = this.PredictComponentBlock(plane, x, y, log2Size, regionId, colorPlaneIndex, transquantBypass);
residual[..sampleCount].Clear(); residual[..sampleCount].Clear();
bool useLumaSyntax = this.sequenceParameterSet.SeparateColorPlaneFlag; bool useLumaSyntax = this.sequenceParameterSet.SeparateColorPlaneFlag;
HevcPlane codingPlane = useLumaSyntax ? HevcPlane.Y : plane; HevcPlane codingPlane = useLumaSyntax ? HevcPlane.Y : plane;

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

@ -21,6 +21,7 @@ public class HevcPictureDecoderTests
[InlineData(TestImages.Heif.Image1TileHvcConfiguration, TestImages.Heif.Image1Tile1Payload, TestImages.Heif.Image1Tile1ReferenceYuv)] [InlineData(TestImages.Heif.Image1TileHvcConfiguration, TestImages.Heif.Image1Tile1Payload, TestImages.Heif.Image1Tile1ReferenceYuv)]
[InlineData(TestImages.Heif.Image1TileHvcConfiguration, TestImages.Heif.Image1Tile2Payload, TestImages.Heif.Image1Tile2ReferenceYuv)] [InlineData(TestImages.Heif.Image1TileHvcConfiguration, TestImages.Heif.Image1Tile2Payload, TestImages.Heif.Image1Tile2ReferenceYuv)]
[InlineData(TestImages.Heif.Image2TileHvcConfiguration, TestImages.Heif.Image2Tile1Payload, TestImages.Heif.Image2Tile1ReferenceYuv)] [InlineData(TestImages.Heif.Image2TileHvcConfiguration, TestImages.Heif.Image2Tile1Payload, TestImages.Heif.Image2Tile1ReferenceYuv)]
[InlineData(TestImages.Heif.Image2TileHvcConfiguration, TestImages.Heif.Image2Tile7Payload, TestImages.Heif.Image2Tile7ReferenceYuv)]
[InlineData(TestImages.Heif.DwsampleTileHvcConfiguration, TestImages.Heif.DwsampleTilePayload, TestImages.Heif.DwsampleTileReferenceYuv)] [InlineData(TestImages.Heif.DwsampleTileHvcConfiguration, TestImages.Heif.DwsampleTilePayload, TestImages.Heif.DwsampleTileReferenceYuv)]
public void DecodeRealHeicTileMatchesHmReference(string configurationPath, string itemPath, string referencePath) public void DecodeRealHeicTileMatchesHmReference(string configurationPath, string itemPath, string referencePath)
{ {

2
tests/ImageSharp.Tests/TestImages.cs

@ -1289,6 +1289,8 @@ public static class TestImages
public const string Image2TileHvcConfiguration = "Heif/Hevc/image2-tile.hvcc"; public const string Image2TileHvcConfiguration = "Heif/Hevc/image2-tile.hvcc";
public const string Image2Tile1Payload = "Heif/Hevc/image2-tile1.hvc1"; public const string Image2Tile1Payload = "Heif/Hevc/image2-tile1.hvc1";
public const string Image2Tile1ReferenceYuv = "Heif/Hevc/image2-tile1-hm.yuv"; public const string Image2Tile1ReferenceYuv = "Heif/Hevc/image2-tile1-hm.yuv";
public const string Image2Tile7Payload = "Heif/Hevc/image2-tile7.hvc1";
public const string Image2Tile7ReferenceYuv = "Heif/Hevc/image2-tile7-hm.yuv";
public const string DwsampleTileHvcConfiguration = "Heif/Hevc/dwsample-tile.hvcc"; public const string DwsampleTileHvcConfiguration = "Heif/Hevc/dwsample-tile.hvcc";
public const string DwsampleTilePayload = "Heif/Hevc/dwsample-tile.hvc1"; public const string DwsampleTilePayload = "Heif/Hevc/dwsample-tile.hvc1";
public const string DwsampleTileReferenceYuv = "Heif/Hevc/dwsample-tile-hm.yuv"; public const string DwsampleTileReferenceYuv = "Heif/Hevc/dwsample-tile-hm.yuv";

3
tests/Images/Input/Heif/Hevc/image2-tile7-hm.yuv

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

3
tests/Images/Input/Heif/Hevc/image2-tile7.hvc1

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