diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1Math.cs b/src/ImageSharp/Formats/Heif/Av1/Av1Math.cs
index f390cbdb8b..e899a7dfcb 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Av1Math.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Av1Math.cs
@@ -196,4 +196,10 @@ internal static class Av1Math
/// implies .
///
internal static bool Implies(bool a, bool b) => !a || b;
+
+ internal static int GetBit(int value, int n)
+ => (value & (1 << n)) >> n;
+
+ internal static void SetBit(ref int endOfBlockExtra, int n)
+ => endOfBlockExtra |= 1 << n;
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs
index b421676885..4632274dad 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs
@@ -353,7 +353,7 @@ internal ref struct Av1SymbolDecoder
bool bit = this.ReadEndOfBlockExtra(transformSizeContext, planeType, endOfBlockContext);
if (bit)
{
- endOfBlockExtra += 1 << (endOfBlockShift - 1);
+ Av1Math.SetBit(ref endOfBlockExtra, endOfBlockShift - 1);
}
else
{
@@ -361,7 +361,7 @@ internal ref struct Av1SymbolDecoder
{
if (this.ReadLiteral(1) != 0)
{
- endOfBlockExtra += 1 << (endOfBlockShift - 1 - j);
+ Av1Math.SetBit(ref endOfBlockExtra, endOfBlockShift - 1 - j);
}
}
}
@@ -379,11 +379,11 @@ internal ref struct Av1SymbolDecoder
if (level > Av1Constants.BaseLevelsCount)
{
int baseRangeContext = Av1SymbolContextHelper.GetBaseRangeContextEndOfBlock(position, transformClass);
- for (int idx = 0; idx < Av1Constants.CoefficientBaseRange / Av1Constants.BaseRangeSizeMinus1; idx++)
+ for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1)
{
- int coefficinetBaseRange = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext);
- level += coefficinetBaseRange;
- if (coefficinetBaseRange < Av1Constants.BaseRangeSizeMinus1)
+ int coefficientBaseRange = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext);
+ level += coefficientBaseRange;
+ if (coefficientBaseRange < Av1Constants.BaseRangeSizeMinus1)
{
break;
}
@@ -405,9 +405,9 @@ internal ref struct Av1SymbolDecoder
int baseRangeContext = Av1SymbolContextHelper.GetBaseRangeContext2d(levels, position);
for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1)
{
- int k = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext);
- level += k;
- if (k < Av1Constants.BaseRangeSizeMinus1)
+ int coefficientBaseRange = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext);
+ level += coefficientBaseRange;
+ if (coefficientBaseRange < Av1Constants.BaseRangeSizeMinus1)
{
break;
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs b/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs
index ab12516e17..1feed0fff8 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs
@@ -204,13 +204,13 @@ internal class Av1SymbolEncoder : IDisposable
{
ref Av1SymbolWriter w = ref this.writer;
int eobShift = eobOffsetBitCount - 1;
- uint bit = (eobExtra & (1 << eobShift)) != 0 ? 1u : 0u;
- w.WriteSymbol((int)bit, this.endOfBlockExtra[(int)transformSizeContext][(int)componentType][endOfBlockPosition]);
+ int bit = Av1Math.GetBit(eobExtra, eobShift);
+ w.WriteSymbol(bit, this.endOfBlockExtra[(int)transformSizeContext][(int)componentType][endOfBlockPosition]);
for (int i = 1; i < eobOffsetBitCount; i++)
{
eobShift = eobOffsetBitCount - 1 - i;
- bit = (eobExtra & (1 << eobShift)) != 0 ? 1u : 0u;
- w.WriteLiteral(bit, 1);
+ bit = Av1Math.GetBit(eobExtra, eobShift);
+ w.WriteLiteral((uint)bit, 1);
}
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1MathTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1MathTests.cs
new file mode 100644
index 0000000000..60f5b30a9c
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1MathTests.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using SixLabors.ImageSharp.Formats.Heif.Av1;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
+
+[Trait("Format", "Avif")]
+public class Av1MathTests
+{
+ [Theory]
+ [InlineData(4, 2, 1)]
+ [InlineData(4, 3, 0)]
+ [InlineData(5, 3, 0)]
+ [InlineData(8, 3, 1)]
+ [InlineData(9, 3, 1)]
+ [InlineData(9, 0, 1)]
+ [InlineData(8, 0, 0)]
+ public void TestGetBitSet(int value, int n, int expected)
+ {
+ int actual = Av1Math.GetBit(value, n);
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(4, 2, 4)]
+ [InlineData(0, 2, 4)]
+ [InlineData(0, 3, 8)]
+ [InlineData(4, 3, 12)]
+ public void TestSetBitSet(int value, int n, int expected)
+ {
+ int actual = value;
+ Av1Math.SetBit(ref actual, n);
+ Assert.Equal(expected, actual);
+ }
+}