From ebab7f0e15c95ac8bd88e1712fe921057bb7e1d8 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 30 Nov 2024 14:25:23 +0100 Subject: [PATCH] Bit getting and setting methods --- src/ImageSharp/Formats/Heif/Av1/Av1Math.cs | 6 ++++ .../Heif/Av1/Entropy/Av1SymbolDecoder.cs | 18 +++++----- .../Heif/Av1/Entropy/Av1SymbolEncoder.cs | 8 ++--- .../Formats/Heif/Av1/Av1MathTests.cs | 36 +++++++++++++++++++ 4 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Heif/Av1/Av1MathTests.cs 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); + } +}