Browse Source

PartitionType symbol round trips

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
b26c0fa183
  1. 2
      src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs
  2. 2
      src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolDecoder.cs
  3. 8
      src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolEncoder.cs
  4. 16
      src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolWriter.cs
  5. 34
      tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs

2
src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs

@ -205,7 +205,7 @@ internal class Av1Decoder : IAv1TileDecoder
else if (hasRows && hasColumns) else if (hasRows && hasColumns)
{ {
int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize); int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize);
partitionType = reader.ReadPartitionSymbol(ctx); partitionType = reader.ReadPartitionType(ctx);
} }
else if (hasColumns) else if (hasColumns)
{ {

2
src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolDecoder.cs

@ -32,7 +32,7 @@ internal ref struct Av1SymbolDecoder
return r.ReadSymbol(this.tileIntraBlockCopy) > 0; return r.ReadSymbol(this.tileIntraBlockCopy) > 0;
} }
public Av1PartitionType ReadPartitionSymbol(int context) public Av1PartitionType ReadPartitionType(int context)
{ {
ref Av1SymbolReader r = ref this.reader; ref Av1SymbolReader r = ref this.reader;
return (Av1PartitionType)r.ReadSymbol(this.tilePartitionTypes[context]); return (Av1PartitionType)r.ReadSymbol(this.tilePartitionTypes[context]);

8
src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolEncoder.cs

@ -8,14 +8,18 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal class Av1SymbolEncoder : IDisposable internal class Av1SymbolEncoder : IDisposable
{ {
private readonly Av1Distribution tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy; private readonly Av1Distribution tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy;
private readonly Av1Distribution[] tilePartitionTypes = Av1DefaultDistributions.PartitionTypes;
private Av1SymbolWriter? writer; private Av1SymbolWriter? writer;
public Av1SymbolEncoder(Configuration configuration, int initialSize) public Av1SymbolEncoder(Configuration configuration, int initialSize)
=> this.writer = new(configuration, initialSize); => this.writer = new(configuration, initialSize);
public void WriteUseIntraBlockCopySymbol(bool value) public void WriteUseIntraBlockCopy(bool value)
=> this.writer!.WriteSymbol(value ? 1 : 0, this.tileIntraBlockCopy, 2); => 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<byte> Exit() => this.writer!.Exit(); public IMemoryOwner<byte> Exit() => this.writer!.Exit();

16
src/ImageSharp/Formats/Heif/Av1/Symbol/Av1SymbolWriter.cs

@ -25,13 +25,13 @@ internal class Av1SymbolWriter : IDisposable
public void Dispose() => this.memory.Dispose(); 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.MustBeGreaterThanOrEqualTo(symbol, 0, nameof(symbol));
DebugGuard.MustBeLessThan(symbol, numberOfSymbols, nameof(symbol)); DebugGuard.MustBeLessThan(symbol, distribution.NumberOfSymbols, nameof(symbol));
DebugGuard.IsTrue(distribution[numberOfSymbols - 1] == 0, "Last entry in Probabilities table needs to be zero."); 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); 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]). /// [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 values must be monotonically non - increasing, and icdf[nsyms - 1] must be 0.
/// </param> /// </param>
/// <param name="numberOfSymbols"> private void EncodeIntegerQ15(int symbol, Av1Distribution distribution)
/// The number of symbols in the alphabet. => this.EncodeIntegerQ15(symbol > 0 ? distribution[symbol - 1] : Av1Distribution.ProbabilityTop, distribution[symbol], symbol, distribution.NumberOfSymbols);
/// This should be at most 16.
/// </param>
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(uint lowFrequency, uint highFrequency, int symbol, int numberOfSymbols) private void EncodeIntegerQ15(uint lowFrequency, uint highFrequency, int symbol, int numberOfSymbols)
{ {

34
tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs

@ -186,29 +186,35 @@ public class SymbolTest
Assert.Equal(expectedValues, values); Assert.Equal(expectedValues, values);
} }
[Theory] [Fact]
[InlineData(0, 255, 255, 255, 158)] public void RoundTripPartitionType()
// [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)
{ {
// Assign // Assign
byte[] values = [b0, b1, b2, b3, 0]; int ctx = 7;
Av1SymbolDecoder decoder = new(values); Configuration configuration = Configuration.Default;
Av1PartitionType[] expected = [ Av1SymbolEncoder encoder = new(configuration, 100 / 8);
Av1PartitionType[] values = [
Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.None, Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.None,
Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.None, Av1PartitionType.None ]; Av1PartitionType.Split, Av1PartitionType.Split, Av1PartitionType.None, Av1PartitionType.None ];
Av1PartitionType[] actuals = new Av1PartitionType[expected.Length]; Av1PartitionType[] actuals = new Av1PartitionType[values.Length];
// Act // Act
for (int i = 0; i < expected.Length; i++) foreach (Av1PartitionType value in values)
{
encoder.WritePartitionType(value, 7);
}
using IMemoryOwner<byte> 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
Assert.Equal(expected, actuals); Assert.Equal(values, actuals);
} }
[Fact] [Fact]
@ -223,7 +229,7 @@ public class SymbolTest
// Act // Act
foreach (bool value in values) foreach (bool value in values)
{ {
encoder.WriteUseIntraBlockCopySymbol(value); encoder.WriteUseIntraBlockCopy(value);
} }
using IMemoryOwner<byte> encoded = encoder.Exit(); using IMemoryOwner<byte> encoded = encoder.Exit();

Loading…
Cancel
Save