diff --git a/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs index 04cffd5ac0..caf760b2e3 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs @@ -410,15 +410,7 @@ internal ref struct Av1SymbolDecoder if (level > Av1Constants.BaseLevelsCount) { int baseRangeContext = Av1SymbolContextHelper.GetBaseRangeContextEndOfBlock(position, transformClass); - for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1) - { - int coefficientBaseRange = this.ReadCoefficientsBaseRange(limitedTransformSizeContext, planeType, baseRangeContext); - level += coefficientBaseRange; - if (coefficientBaseRange < Av1Constants.BaseRangeSizeMinus1) - { - break; - } - } + this.ReadCoefficientsBaseRangeLoop(transformSizeContext, planeType, baseRangeContext, ref level); } levels.GetRow(position)[position.X] = (byte)level; @@ -435,15 +427,7 @@ internal ref struct Av1SymbolDecoder if (level > Av1Constants.BaseLevelsCount) { int baseRangeContext = Av1SymbolContextHelper.GetBaseRangeContext2d(levels, position); - for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1) - { - int coefficientBaseRange = this.ReadCoefficientsBaseRange(limitedTransformSizeContext, planeType, baseRangeContext); - level += coefficientBaseRange; - if (coefficientBaseRange < Av1Constants.BaseRangeSizeMinus1) - { - break; - } - } + this.ReadCoefficientsBaseRangeLoop(transformSizeContext, planeType, baseRangeContext, ref level); } levels.GetRow(position)[position.X] = (byte)level; @@ -462,15 +446,7 @@ internal ref struct Av1SymbolDecoder if (level > Av1Constants.BaseLevelsCount) { int baseRangeContext = Av1SymbolContextHelper.GetBaseRangeContext(levels, position, transformClass); - for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1) - { - int coefficientBaseRange = this.ReadCoefficientsBaseRange(limitedTransformSizeContext, planeType, baseRangeContext); - level += coefficientBaseRange; - if (coefficientBaseRange < Av1Constants.BaseRangeSizeMinus1) - { - break; - } - } + this.ReadCoefficientsBaseRangeLoop(transformSizeContext, planeType, baseRangeContext, ref level); } levels.GetRow(position)[position.X] = (byte)level; @@ -566,7 +542,7 @@ internal ref struct Av1SymbolDecoder { ref Av1SymbolReader r = ref this.reader; Av1TransformSize limitedTransformSizeContext = (Av1TransformSize)Math.Min((int)transformSizeContext, (int)Av1TransformSize.Size32x32); - Av1Distribution distribution = this.coefficientsBaseRange[(int)transformSizeContext][(int)planeType][baseRangeContext]; + Av1Distribution distribution = this.coefficientsBaseRange[(int)limitedTransformSizeContext][(int)planeType][baseRangeContext]; for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1) { int coefficientBaseRange = r.ReadSymbol(distribution); diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1CoefficientsEntropyTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1CoefficientsEntropyTests.cs index c1a5a02a78..8d47cbe9df 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1CoefficientsEntropyTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1CoefficientsEntropyTests.cs @@ -112,6 +112,26 @@ public class Av1CoefficientsEntropyTests Av1TransformType transformType = (Av1TransformType)txType; Av1PredictionMode intraDirection = Av1PredictionMode.DC; Av1FilterIntraMode filterIntraMode = Av1FilterIntraMode.DC; + RoundTripCoefficientsCore(endOfBlock, componentType, blockSize, transformSize, transformType, intraDirection, filterIntraMode); + } + + [Theory] + [MemberData(nameof(GetBlockSize4x4Data))] + public void RoundTripFullCoefficientsUvSize4x4(int bSize, int txSize, int txType) + { + // Assign + const ushort endOfBlock = 16; + const Av1ComponentType componentType = Av1ComponentType.Chroma; + Av1BlockSize blockSize = (Av1BlockSize)bSize; + Av1TransformSize transformSize = (Av1TransformSize)txSize; + Av1TransformType transformType = (Av1TransformType)txType; + Av1PredictionMode intraDirection = Av1PredictionMode.DC; + Av1FilterIntraMode filterIntraMode = Av1FilterIntraMode.DC; + RoundTripCoefficientsCore(endOfBlock, componentType, blockSize, transformSize, transformType, intraDirection, filterIntraMode); + } + + private static void RoundTripCoefficientsCore(ushort endOfBlock, Av1ComponentType componentType, Av1BlockSize blockSize, Av1TransformSize transformSize, Av1TransformType transformType, Av1PredictionMode intraDirection, Av1FilterIntraMode filterIntraMode) + { Av1BlockModeInfo modeInfo = new(Av1Constants.MaxPlanes, blockSize, new Point(0, 0)); Av1TransformInfo transformInfo = new(transformSize, 0, 0); int[] aboveContexts = new int[transformSize.Get4x4WideCount()]; @@ -124,8 +144,7 @@ public class Av1CoefficientsEntropyTests // Act encoder.WriteCoefficients(transformSize, transformType, intraDirection, coefficientsBuffer, componentType, transformBlockContext, endOfBlock, true, filterIntraMode); - - using IMemoryOwner encoded = encoder.Exit(); + IMemoryOwner encoded = encoder.Exit(); Av1SymbolDecoder decoder = new(Configuration.Default, encoded.GetSpan(), BaseQIndex); int plane = Math.Min((int)componentType, 1);