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)
{
int ctx = this.GetPartitionContext(rowIndex, columnIndex, blockSize);
partitionType = reader.ReadPartitionSymbol(ctx);
partitionType = reader.ReadPartitionType(ctx);
}
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;
}
public Av1PartitionType ReadPartitionSymbol(int context)
public Av1PartitionType ReadPartitionType(int context)
{
ref Av1SymbolReader r = ref this.reader;
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
{
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<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 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.
/// </param>
/// <param name="numberOfSymbols">
/// The number of symbols in the alphabet.
/// 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(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)
{

34
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<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.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<byte> encoded = encoder.Exit();

Loading…
Cancel
Save