From b26c0fa18391dfbe0db2a58a0ce4acdb547b2773 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 1 Jun 2024 11:08:44 +0200 Subject: [PATCH] PartitionType symbol round trips --- src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs | 2 +- .../Heif/Av1/Symbol/Av1SymbolDecoder.cs | 2 +- .../Heif/Av1/Symbol/Av1SymbolEncoder.cs | 8 +++-- .../Heif/Av1/Symbol/Av1SymbolWriter.cs | 16 ++++----- .../Formats/Heif/Av1/SymbolTest.cs | 34 +++++++++++-------- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs b/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs index 0a8fac5d0..35ce9c37f 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs @@ -205,7 +205,7 @@ internal class Av1Decoder : IAv1TileDecoder else if (hasRows && hasColumns) { int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize); - partitionType = reader.ReadPartitionSymbol(ctx); + partitionType = reader.ReadPartitionType(ctx); } else if (hasColumns) { diff --git a/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolDecoder.cs index d0193031e..faec9c821 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolDecoder.cs @@ -32,7 +32,7 @@ internal ref struct Av1SymbolDecoder return r.ReadSymbol(this.tileIntraBlockCopy) > 0; } - public Av1PartitionType ReadPartitionSymbol(int context) + public Av1PartitionType ReadPartitionType(int context) { ref Av1SymbolReader r = ref this.reader; return (Av1PartitionType)r.ReadSymbol(this.tilePartitionTypes[context]); diff --git a/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolEncoder.cs b/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolEncoder.cs index 7ed6ff745..391cd1360 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolEncoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolEncoder.cs @@ -8,14 +8,18 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol; internal class Av1SymbolEncoder : IDisposable { private readonly Av1Distribution tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy; + private readonly Av1Distribution[] tilePartitionTypes = Av1DefaultDistributions.PartitionTypes; private Av1SymbolWriter? writer; public Av1SymbolEncoder(Configuration configuration, int initialSize) => this.writer = new(configuration, initialSize); - public void WriteUseIntraBlockCopySymbol(bool value) - => this.writer!.WriteSymbol(value ? 1 : 0, this.tileIntraBlockCopy, 2); + public void WriteUseIntraBlockCopy(bool value) + => this.writer!.WriteSymbol(value ? 1 : 0, this.tileIntraBlockCopy); + + public void WritePartitionType(Av1PartitionType value, int context) + => this.writer!.WriteSymbol((int)value, this.tilePartitionTypes[context]); public IMemoryOwner Exit() => this.writer!.Exit(); diff --git a/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolWriter.cs b/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolWriter.cs index cf36b04a1..2752facb4 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolWriter.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolWriter.cs @@ -25,13 +25,13 @@ internal class Av1SymbolWriter : IDisposable public void Dispose() => this.memory.Dispose(); - public void WriteSymbol(int symbol, Av1Distribution distribution, int numberOfSymbols) + public void WriteSymbol(int symbol, Av1Distribution distribution) { DebugGuard.MustBeGreaterThanOrEqualTo(symbol, 0, nameof(symbol)); - DebugGuard.MustBeLessThan(symbol, numberOfSymbols, nameof(symbol)); - DebugGuard.IsTrue(distribution[numberOfSymbols - 1] == 0, "Last entry in Probabilities table needs to be zero."); + DebugGuard.MustBeLessThan(symbol, distribution.NumberOfSymbols, nameof(symbol)); + DebugGuard.IsTrue(distribution[distribution.NumberOfSymbols - 1] == 0, "Last entry in Probabilities table needs to be zero."); - this.EncodeIntegerQ15(symbol, distribution, numberOfSymbols); + this.EncodeIntegerQ15(symbol, distribution); distribution.Update(symbol); } @@ -128,12 +128,8 @@ internal class Av1SymbolWriter : IDisposable /// [s > 0 ? (CDF_PROB_TOP - icdf[s - 1]) : 0, CDF_PROB_TOP - icdf[s]). /// The values must be monotonically non - increasing, and icdf[nsyms - 1] must be 0. /// - /// - /// The number of symbols in the alphabet. - /// This should be at most 16. - /// - private void EncodeIntegerQ15(int symbol, Av1Distribution distribution, int numberOfSymbols) - => this.EncodeIntegerQ15(symbol > 0 ? distribution[symbol - 1] : Av1Distribution.ProbabilityTop, distribution[symbol], symbol, numberOfSymbols); + private void EncodeIntegerQ15(int symbol, Av1Distribution distribution) + => this.EncodeIntegerQ15(symbol > 0 ? distribution[symbol - 1] : Av1Distribution.ProbabilityTop, distribution[symbol], symbol, distribution.NumberOfSymbols); private void EncodeIntegerQ15(uint lowFrequency, uint highFrequency, int symbol, int numberOfSymbols) { diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs index 36b66a8b7..943eced4c 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs @@ -186,29 +186,35 @@ public class SymbolTest Assert.Equal(expectedValues, values); } - [Theory] - [InlineData(0, 255, 255, 255, 158)] - - // [InlineData(1, 255, 255, 255, 158)] - // [InlineData(4, 255, 207, 254, 18)] - public void ReadPartitionTypeSymbols(int ctx, byte b0, byte b1, byte b2, byte b3) + [Fact] + public void RoundTripPartitionType() { // Assign - byte[] values = [b0, b1, b2, b3, 0]; - Av1SymbolDecoder decoder = new(values); - Av1PartitionType[] expected = [ + int ctx = 7; + Configuration configuration = Configuration.Default; + Av1SymbolEncoder encoder = new(configuration, 100 / 8); + Av1PartitionType[] values = [ Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.None, Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.None, Av1PartitionType.None ]; - Av1PartitionType[] actuals = new Av1PartitionType[expected.Length]; + Av1PartitionType[] actuals = new Av1PartitionType[values.Length]; // Act - for (int i = 0; i < expected.Length; i++) + foreach (Av1PartitionType value in values) + { + encoder.WritePartitionType(value, 7); + } + + using IMemoryOwner encoded = encoder.Exit(); + + Av1SymbolDecoder decoder = new(encoded.GetSpan()); + Av1SymbolReader reader = new(encoded.GetSpan()); + for (int i = 0; i < values.Length; i++) { - actuals[i] = decoder.ReadPartitionSymbol(ctx); + actuals[i] = decoder.ReadPartitionType(ctx); } // Assert - Assert.Equal(expected, actuals); + Assert.Equal(values, actuals); } [Fact] @@ -223,7 +229,7 @@ public class SymbolTest // Act foreach (bool value in values) { - encoder.WriteUseIntraBlockCopySymbol(value); + encoder.WriteUseIntraBlockCopy(value); } using IMemoryOwner encoded = encoder.Exit();