diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs b/src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs index f3d32187c0..cbeefa2128 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs @@ -49,15 +49,15 @@ internal class Av1FrameBuffer : IDisposable { case Av1ColorFormat.Yuv420: strideChroma = (strideY + 1) >> 1; - heightChroma = (this.Height + 1) >> 1; + heightChroma = (heightY + 1) >> 1; break; case Av1ColorFormat.Yuv422: strideChroma = (strideY + 1) >> 1; - heightChroma = this.Height; + heightChroma = heightY; break; case Av1ColorFormat.Yuv444: strideChroma = strideY; - heightChroma = this.Height; + heightChroma = heightY; break; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionDecoder.cs index a7c14a0e59..483598aa2a 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionDecoder.cs @@ -24,6 +24,9 @@ internal class Av1PredictionDecoder this.is16BitPipeline = is16BitPipeline; } + /// + /// SVT: svt_av1_predict_intra + /// public void Decode( Av1PartitionInfo partitionInfo, Av1Plane plane, @@ -37,8 +40,11 @@ internal class Av1PredictionDecoder { int bytesPerPixel = (bitDepth == Av1BitDepth.EightBit && !this.is16BitPipeline) ? 2 : 1; int stride = pixelStride * bytesPerPixel; - Span topNeighbor = pixelBuffer.Slice(-stride); - Span leftNeighbor = pixelBuffer.Slice(-1); + + // Deviation from SVT: Buffer starts at PREVIOUS row. + Span topNeighbor = pixelBuffer; + Span leftNeighbor = pixelBuffer[(stride - 1)..]; + Span startOfPixels = pixelBuffer[stride..]; bool is16BitPipeline = this.is16BitPipeline; Av1PredictionMode mode = (plane == Av1Plane.Y) ? partitionInfo.ModeInfo.YMode : partitionInfo.ModeInfo.UvMode; @@ -50,7 +56,7 @@ internal class Av1PredictionDecoder plane, transformSize, tileInfo, - pixelBuffer, + startOfPixels, stride, topNeighbor, leftNeighbor, @@ -63,7 +69,7 @@ internal class Av1PredictionDecoder this.PredictChromaFromLumaBlock( partitionInfo, partitionInfo.ChromaFromLumaContext, - ref pixelBuffer, + startOfPixels, stride, transformSize, plane); @@ -76,7 +82,7 @@ internal class Av1PredictionDecoder plane, transformSize, tileInfo, - pixelBuffer, + startOfPixels, stride, topNeighbor, leftNeighbor, @@ -87,7 +93,7 @@ internal class Av1PredictionDecoder bitDepth); } - private void PredictChromaFromLumaBlock(Av1PartitionInfo partitionInfo, Av1ChromaFromLumaContext? chromaFromLumaContext, ref Span pixelBuffer, int stride, Av1TransformSize transformSize, Av1Plane plane) + private void PredictChromaFromLumaBlock(Av1PartitionInfo partitionInfo, Av1ChromaFromLumaContext? chromaFromLumaContext, Span pixelBuffer, int stride, Av1TransformSize transformSize, Av1Plane plane) { Av1BlockModeInfo modeInfo = partitionInfo.ModeInfo; bool isChromaFromLumaAllowedFlag = IsChromaFromLumaAllowedWithFrameHeader(partitionInfo, this.sequenceHeader.ColorConfig, this.frameHeader); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs index fc90726a33..7f8f5b56bb 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs @@ -146,7 +146,6 @@ internal class Av1BlockDecoder } // if (!inter_block) - if (true) { // SVT: svt_av1_predict_intra predictionDecoder.Decode( @@ -226,25 +225,29 @@ internal class Av1BlockDecoder { int blockOffset; - if (plane == 0) + switch (plane) { - blockOffset = ((frameBuffer.OriginY + blockRowInPixels) * frameBuffer.BufferY!.Width) + - (frameBuffer.OriginX + blockColumnInPixels); - reconstructionStride = frameBuffer.BufferY!.Width; - } - else if (plane == 1) - { - blockOffset = (((frameBuffer.OriginY >> subY) + blockRowInPixels) * frameBuffer.BufferCb!.Width) + - ((frameBuffer.OriginX >> subX) + blockColumnInPixels); - reconstructionStride = frameBuffer.BufferCb!.Width; - } - else - { - blockOffset = (((frameBuffer.OriginY >> subY) + blockRowInPixels) * frameBuffer.BufferCr!.Width) + - ((frameBuffer.OriginX >> subX) + blockColumnInPixels); - reconstructionStride = frameBuffer.BufferCr!.Width; + case 0: + reconstructionStride = frameBuffer.BufferY!.Width; + blockOffset = ((frameBuffer.OriginY + blockRowInPixels) * reconstructionStride) + + (frameBuffer.OriginX + blockColumnInPixels); + break; + case 1: + reconstructionStride = frameBuffer.BufferCb!.Width; + blockOffset = (((frameBuffer.OriginY >> subY) + blockRowInPixels) * reconstructionStride) + + ((frameBuffer.OriginX >> subX) + blockColumnInPixels); + break; + default: + reconstructionStride = frameBuffer.BufferCr!.Width; + blockOffset = (((frameBuffer.OriginY >> subY) + blockRowInPixels) * reconstructionStride) + + ((frameBuffer.OriginX >> subX) + blockColumnInPixels); + break; } + // Deviation from SVT, return PREVIOUS row in Block Reconstruction Buffer. + blockOffset -= reconstructionStride; + Guard.MustBeGreaterThanOrEqualTo(blockOffset, 0, nameof(blockOffset)); + if (frameBuffer.BitDepth != Av1BitDepth.EightBit || frameBuffer.Is16BitPipeline) { // 16bit pipeline