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="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="transquantBypass">Whether the governing coding unit bypasses inverse quantization and transform.</param>
/// <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 sampleCount = size * size;
@ -69,6 +70,14 @@ internal sealed partial class HevcPictureDecoder
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(
useLumaSyntax ? HevcPlane.Y : plane,
mode,
@ -101,7 +110,7 @@ internal sealed partial class HevcPictureDecoder
log2Size,
mode,
this.Picture.GetBitDepth(plane),
useLumaSyntax,
filterPredictionEdges,
operationScratch);
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> residual = integerScratch.Slice(MaximumTransformSampleCount * 2, MaximumTransformSampleCount);
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();
bool useLumaSyntax = this.sequenceParameterSet.SeparateColorPlaneFlag;
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.Image1Tile2Payload, TestImages.Heif.Image1Tile2ReferenceYuv)]
[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)]
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 Image2Tile1Payload = "Heif/Hevc/image2-tile1.hvc1";
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 DwsampleTilePayload = "Heif/Hevc/dwsample-tile.hvc1";
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