Browse Source

Isolate AV1 tile entropy contexts

pull/2633/head
James Jackson-South 2 weeks ago
parent
commit
6df6f0e61a
  1. 70
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1Distribution.cs
  2. 69
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs
  3. 63
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs
  4. 19
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolReader.cs
  5. 20
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolWriter.cs
  6. 9
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs

70
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1Distribution.cs

@ -267,6 +267,22 @@ internal class Av1Distribution
this.speed = speed;
}
/// <summary>
/// Initializes a new instance of the <see cref="Av1Distribution"/> class with the same probability and adaptation state as another distribution.
/// </summary>
/// <param name="source">The distribution state to copy.</param>
private Av1Distribution(Av1Distribution source)
{
this.probabilities = new uint[source.probabilities.Length];
source.probabilities.CopyTo(this.probabilities, 0);
// The adaptation rate depends on both the alphabet size and prior update count, so copying only the
// thresholds would make the cloned frame context diverge after its next symbol.
this.speed = source.speed;
this.updateCount = source.updateCount;
this.NumberOfSymbols = source.NumberOfSymbols;
}
/// <summary>
/// Gets the number of symbols represented by the distribution.
/// </summary>
@ -279,6 +295,60 @@ internal class Av1Distribution
/// <returns>The Q15 inverse cumulative threshold.</returns>
public uint this[int index] => this.probabilities[index];
/// <summary>
/// Creates an independently adaptable copy of a distribution.
/// </summary>
/// <returns>A distribution initialized with the same probabilities and update count.</returns>
public Av1Distribution CreateCopy() => new(this);
/// <summary>
/// Creates independently adaptable copies of a distribution array.
/// </summary>
/// <param name="source">The distributions to copy.</param>
/// <returns>An array with the same shape and distribution state.</returns>
public static Av1Distribution[] CreateCopy(Av1Distribution[] source)
{
Av1Distribution[] result = new Av1Distribution[source.Length];
for (int i = 0; i < source.Length; i++)
{
result[i] = source[i].CreateCopy();
}
return result;
}
/// <summary>
/// Creates independently adaptable copies of a two-dimensional jagged distribution array.
/// </summary>
/// <param name="source">The distributions to copy.</param>
/// <returns>An array with the same shape and distribution state.</returns>
public static Av1Distribution[][] CreateCopy(Av1Distribution[][] source)
{
Av1Distribution[][] result = new Av1Distribution[source.Length][];
for (int i = 0; i < source.Length; i++)
{
result[i] = CreateCopy(source[i]);
}
return result;
}
/// <summary>
/// Creates independently adaptable copies of a three-dimensional jagged distribution array.
/// </summary>
/// <param name="source">The distributions to copy.</param>
/// <returns>An array with the same shape and distribution state.</returns>
public static Av1Distribution[][][] CreateCopy(Av1Distribution[][][] source)
{
Av1Distribution[][][] result = new Av1Distribution[source.Length][][];
for (int i = 0; i < source.Length; i++)
{
result[i] = CreateCopy(source[i]);
}
return result;
}
/// <summary>
/// Adapts the cumulative thresholds after coding one symbol.
/// </summary>

69
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs

@ -21,67 +21,67 @@ internal ref struct Av1SymbolDecoder
/// <summary>
/// The tile-adaptive intra-block-copy distribution.
/// </summary>
private readonly Av1Distribution tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy;
private readonly Av1Distribution tileIntraBlockCopy;
/// <summary>
/// The tile-adaptive partition-type distributions.
/// </summary>
private readonly Av1Distribution[] tilePartitionTypes = Av1DefaultDistributions.PartitionTypes;
private readonly Av1Distribution[] tilePartitionTypes;
/// <summary>
/// The tile-adaptive key-frame luma-mode distributions.
/// </summary>
private readonly Av1Distribution[][] keyFrameYMode = Av1DefaultDistributions.KeyFrameYMode;
private readonly Av1Distribution[][] keyFrameYMode;
/// <summary>
/// The tile-adaptive chroma intra-mode distributions.
/// </summary>
private readonly Av1Distribution[][] uvMode = Av1DefaultDistributions.UvMode;
private readonly Av1Distribution[][] uvMode;
/// <summary>
/// The tile-adaptive transform-skip distributions.
/// </summary>
private readonly Av1Distribution[] skip = Av1DefaultDistributions.Skip;
private readonly Av1Distribution[] skip;
/// <summary>
/// The tile-adaptive skip-mode distributions.
/// </summary>
private readonly Av1Distribution[] skipMode = Av1DefaultDistributions.SkipMode;
private readonly Av1Distribution[] skipMode;
/// <summary>
/// The tile-adaptive absolute loop-filter delta distribution.
/// </summary>
private readonly Av1Distribution deltaLoopFilterAbsolute = Av1DefaultDistributions.DeltaLoopFilterAbsolute;
private readonly Av1Distribution deltaLoopFilterAbsolute;
/// <summary>
/// The tile-adaptive absolute quantizer delta distribution.
/// </summary>
private readonly Av1Distribution deltaQuantizerAbsolute = Av1DefaultDistributions.DeltaQuantizerAbsolute;
private readonly Av1Distribution deltaQuantizerAbsolute;
/// <summary>
/// The tile-adaptive spatial segment-identifier distributions.
/// </summary>
private readonly Av1Distribution[] segmentId = Av1DefaultDistributions.SegmentId;
private readonly Av1Distribution[] segmentId;
/// <summary>
/// The tile-adaptive directional angle-delta distributions.
/// </summary>
private readonly Av1Distribution[] angleDelta = Av1DefaultDistributions.AngleDelta;
private readonly Av1Distribution[] angleDelta;
/// <summary>
/// The tile-adaptive filter-intra mode distribution.
/// </summary>
private readonly Av1Distribution filterIntraMode = Av1DefaultDistributions.FilterIntraMode;
private readonly Av1Distribution filterIntraMode;
/// <summary>
/// The tile-adaptive filter-intra enable distributions.
/// </summary>
private readonly Av1Distribution[] filterIntra = Av1DefaultDistributions.FilterIntra;
private readonly Av1Distribution[] filterIntra;
/// <summary>
/// The tile-adaptive transform-size distributions.
/// </summary>
private readonly Av1Distribution[][] transformSize = Av1DefaultDistributions.TransformSize;
private readonly Av1Distribution[][] transformSize;
/// <summary>
/// The tile-adaptive end-of-block token distributions selected for the frame base quantizer.
@ -121,17 +121,17 @@ internal ref struct Av1SymbolDecoder
/// <summary>
/// The tile-adaptive joint chroma-from-luma sign distribution.
/// </summary>
private readonly Av1Distribution chromaFromLumaSign = Av1DefaultDistributions.ChromaFromLumaSign;
private readonly Av1Distribution chromaFromLumaSign;
/// <summary>
/// The tile-adaptive chroma-from-luma alpha-magnitude distributions.
/// </summary>
private readonly Av1Distribution[] chromaFromLumaAlpha = Av1DefaultDistributions.ChromaFromLumaAlpha;
private readonly Av1Distribution[] chromaFromLumaAlpha;
/// <summary>
/// The tile-adaptive intra transform-type distributions.
/// </summary>
private readonly Av1Distribution[][][] intraExtendedTransform = Av1DefaultDistributions.IntraExtendedTransform;
private readonly Av1Distribution[][][] intraExtendedTransform;
/// <summary>
/// The configuration providing temporary coefficient-context memory.
@ -154,18 +154,37 @@ internal ref struct Av1SymbolDecoder
/// <param name="configuration">The configuration providing temporary memory.</param>
/// <param name="tileData">The entropy-coded tile payload.</param>
/// <param name="qIndex">The frame base quantizer index.</param>
public Av1SymbolDecoder(Configuration configuration, Span<byte> tileData, int qIndex)
/// <param name="updateCdf">A value indicating whether decoded symbols adapt their tile distributions.</param>
public Av1SymbolDecoder(Configuration configuration, Span<byte> tileData, int qIndex, bool updateCdf = true)
{
// Every tile starts from its own frame-context copy. Sharing these objects would let one image's adaptive
// updates change the initial probabilities used to decode the next tile or image.
this.tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy.CreateCopy();
this.tilePartitionTypes = Av1Distribution.CreateCopy(Av1DefaultDistributions.PartitionTypes);
this.keyFrameYMode = Av1Distribution.CreateCopy(Av1DefaultDistributions.KeyFrameYMode);
this.uvMode = Av1Distribution.CreateCopy(Av1DefaultDistributions.UvMode);
this.skip = Av1Distribution.CreateCopy(Av1DefaultDistributions.Skip);
this.skipMode = Av1Distribution.CreateCopy(Av1DefaultDistributions.SkipMode);
this.deltaLoopFilterAbsolute = Av1DefaultDistributions.DeltaLoopFilterAbsolute.CreateCopy();
this.deltaQuantizerAbsolute = Av1DefaultDistributions.DeltaQuantizerAbsolute.CreateCopy();
this.segmentId = Av1Distribution.CreateCopy(Av1DefaultDistributions.SegmentId);
this.angleDelta = Av1Distribution.CreateCopy(Av1DefaultDistributions.AngleDelta);
this.filterIntraMode = Av1DefaultDistributions.FilterIntraMode.CreateCopy();
this.filterIntra = Av1Distribution.CreateCopy(Av1DefaultDistributions.FilterIntra);
this.transformSize = Av1Distribution.CreateCopy(Av1DefaultDistributions.TransformSize);
this.chromaFromLumaSign = Av1DefaultDistributions.ChromaFromLumaSign.CreateCopy();
this.chromaFromLumaAlpha = Av1Distribution.CreateCopy(Av1DefaultDistributions.ChromaFromLumaAlpha);
this.intraExtendedTransform = Av1Distribution.CreateCopy(Av1DefaultDistributions.IntraExtendedTransform);
this.configuration = configuration;
this.reader = new Av1SymbolReader(tileData);
this.reader = new Av1SymbolReader(tileData, updateCdf);
this.baseQIndex = qIndex;
this.endOfBlockFlag = Av1DefaultDistributions.GetEndOfBlockFlag(qIndex);
this.coefficientsBase = Av1DefaultDistributions.GetCoefficientsBase(qIndex);
this.baseEndOfBlock = Av1DefaultDistributions.GetBaseEndOfBlock(qIndex);
this.dcSign = Av1DefaultDistributions.GetDcSign(qIndex);
this.coefficientsBaseRange = Av1DefaultDistributions.GetCoefficientsBaseRange(qIndex);
this.transformBlockSkip = Av1DefaultDistributions.GetTransformBlockSkip(qIndex);
this.endOfBlockExtra = Av1DefaultDistributions.GetEndOfBlockExtra(qIndex);
this.endOfBlockFlag = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetEndOfBlockFlag(qIndex));
this.coefficientsBase = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetCoefficientsBase(qIndex));
this.baseEndOfBlock = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetBaseEndOfBlock(qIndex));
this.dcSign = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetDcSign(qIndex));
this.coefficientsBaseRange = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetCoefficientsBaseRange(qIndex));
this.transformBlockSkip = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetTransformBlockSkip(qIndex));
this.endOfBlockExtra = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetEndOfBlockExtra(qIndex));
}
/// <summary>

63
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs

@ -18,22 +18,22 @@ internal class Av1SymbolEncoder : IDisposable
/// <summary>
/// The tile-adaptive intra-block-copy distribution.
/// </summary>
private readonly Av1Distribution tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy;
private readonly Av1Distribution tileIntraBlockCopy;
/// <summary>
/// The tile-adaptive partition-type distributions.
/// </summary>
private readonly Av1Distribution[] tilePartitionTypes = Av1DefaultDistributions.PartitionTypes;
private readonly Av1Distribution[] tilePartitionTypes;
/// <summary>
/// The tile-adaptive key-frame luma-mode distributions.
/// </summary>
private readonly Av1Distribution[][] keyFrameYMode = Av1DefaultDistributions.KeyFrameYMode;
private readonly Av1Distribution[][] keyFrameYMode;
/// <summary>
/// The tile-adaptive chroma intra-mode distributions.
/// </summary>
private readonly Av1Distribution[][] uvMode = Av1DefaultDistributions.UvMode;
private readonly Av1Distribution[][] uvMode;
/// <summary>
/// The tile-adaptive transform-block skip distributions selected for the frame base quantizer.
@ -63,17 +63,17 @@ internal class Av1SymbolEncoder : IDisposable
/// <summary>
/// The tile-adaptive filter-intra enable distributions.
/// </summary>
private readonly Av1Distribution[] filterIntra = Av1DefaultDistributions.FilterIntra;
private readonly Av1Distribution[] filterIntra;
/// <summary>
/// The tile-adaptive filter-intra mode distribution.
/// </summary>
private readonly Av1Distribution filterIntraMode = Av1DefaultDistributions.FilterIntraMode;
private readonly Av1Distribution filterIntraMode;
/// <summary>
/// The tile-adaptive absolute quantizer delta distribution.
/// </summary>
private readonly Av1Distribution deltaQuantizerAbsolute = Av1DefaultDistributions.DeltaQuantizerAbsolute;
private readonly Av1Distribution deltaQuantizerAbsolute;
/// <summary>
/// The tile-adaptive DC sign distributions selected for the frame base quantizer.
@ -88,37 +88,37 @@ internal class Av1SymbolEncoder : IDisposable
/// <summary>
/// The tile-adaptive intra transform-type distributions.
/// </summary>
private readonly Av1Distribution[][][] intraExtendedTransform = Av1DefaultDistributions.IntraExtendedTransform;
private readonly Av1Distribution[][][] intraExtendedTransform;
/// <summary>
/// The tile-adaptive spatial segment-identifier distributions.
/// </summary>
private readonly Av1Distribution[] segmentId = Av1DefaultDistributions.SegmentId;
private readonly Av1Distribution[] segmentId;
/// <summary>
/// The tile-adaptive directional angle-delta distributions.
/// </summary>
private readonly Av1Distribution[] angleDelta = Av1DefaultDistributions.AngleDelta;
private readonly Av1Distribution[] angleDelta;
/// <summary>
/// The tile-adaptive transform-skip distributions.
/// </summary>
private readonly Av1Distribution[] skip = Av1DefaultDistributions.Skip;
private readonly Av1Distribution[] skip;
/// <summary>
/// The tile-adaptive skip-mode distributions.
/// </summary>
private readonly Av1Distribution[] skipMode = Av1DefaultDistributions.SkipMode;
private readonly Av1Distribution[] skipMode;
/// <summary>
/// The tile-adaptive joint chroma-from-luma sign distribution.
/// </summary>
private readonly Av1Distribution chromaFromLumaSign = Av1DefaultDistributions.ChromaFromLumaSign;
private readonly Av1Distribution chromaFromLumaSign;
/// <summary>
/// The tile-adaptive chroma-from-luma alpha-magnitude distributions.
/// </summary>
private readonly Av1Distribution[] chromaFromLumaAlpha = Av1DefaultDistributions.ChromaFromLumaAlpha;
private readonly Av1Distribution[] chromaFromLumaAlpha;
/// <summary>
/// Indicates whether the range writer has been disposed.
@ -146,17 +146,34 @@ internal class Av1SymbolEncoder : IDisposable
/// <param name="configuration">The configuration providing output and temporary memory.</param>
/// <param name="initialSize">The initial output buffer size in bytes.</param>
/// <param name="qIndex">The frame base quantizer index.</param>
public Av1SymbolEncoder(Configuration configuration, int initialSize, int qIndex)
/// <param name="updateCdf">A value indicating whether encoded symbols adapt their tile distributions.</param>
public Av1SymbolEncoder(Configuration configuration, int initialSize, int qIndex, bool updateCdf = true)
{
this.transformBlockSkip = Av1DefaultDistributions.GetTransformBlockSkip(qIndex);
this.endOfBlockFlag = Av1DefaultDistributions.GetEndOfBlockFlag(qIndex);
this.coefficientsBaseRange = Av1DefaultDistributions.GetCoefficientsBaseRange(qIndex);
this.coefficientsBase = Av1DefaultDistributions.GetCoefficientsBase(qIndex);
this.coefficientsBaseEndOfBlock = Av1DefaultDistributions.GetBaseEndOfBlock(qIndex);
this.dcSign = Av1DefaultDistributions.GetDcSign(qIndex);
this.endOfBlockExtra = Av1DefaultDistributions.GetEndOfBlockExtra(qIndex);
// Encoding and decoding must begin from equivalent tile-local models. Copying the defaults also prevents
// one encoded image from changing the probabilities used by later encoder or decoder instances.
this.tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy.CreateCopy();
this.tilePartitionTypes = Av1Distribution.CreateCopy(Av1DefaultDistributions.PartitionTypes);
this.keyFrameYMode = Av1Distribution.CreateCopy(Av1DefaultDistributions.KeyFrameYMode);
this.uvMode = Av1Distribution.CreateCopy(Av1DefaultDistributions.UvMode);
this.filterIntra = Av1Distribution.CreateCopy(Av1DefaultDistributions.FilterIntra);
this.filterIntraMode = Av1DefaultDistributions.FilterIntraMode.CreateCopy();
this.deltaQuantizerAbsolute = Av1DefaultDistributions.DeltaQuantizerAbsolute.CreateCopy();
this.intraExtendedTransform = Av1Distribution.CreateCopy(Av1DefaultDistributions.IntraExtendedTransform);
this.segmentId = Av1Distribution.CreateCopy(Av1DefaultDistributions.SegmentId);
this.angleDelta = Av1Distribution.CreateCopy(Av1DefaultDistributions.AngleDelta);
this.skip = Av1Distribution.CreateCopy(Av1DefaultDistributions.Skip);
this.skipMode = Av1Distribution.CreateCopy(Av1DefaultDistributions.SkipMode);
this.chromaFromLumaSign = Av1DefaultDistributions.ChromaFromLumaSign.CreateCopy();
this.chromaFromLumaAlpha = Av1Distribution.CreateCopy(Av1DefaultDistributions.ChromaFromLumaAlpha);
this.transformBlockSkip = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetTransformBlockSkip(qIndex));
this.endOfBlockFlag = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetEndOfBlockFlag(qIndex));
this.coefficientsBaseRange = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetCoefficientsBaseRange(qIndex));
this.coefficientsBase = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetCoefficientsBase(qIndex));
this.coefficientsBaseEndOfBlock = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetBaseEndOfBlock(qIndex));
this.dcSign = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetDcSign(qIndex));
this.endOfBlockExtra = Av1Distribution.CreateCopy(Av1DefaultDistributions.GetEndOfBlockExtra(qIndex));
this.configuration = configuration;
this.writer = new(configuration, initialSize);
this.writer = new(configuration, initialSize, updateCdf);
this.baseQIndex = qIndex;
}

19
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolReader.cs

@ -23,6 +23,11 @@ internal ref struct Av1SymbolReader
/// </summary>
private readonly Span<byte> buffer;
/// <summary>
/// Indicates whether decoded symbols adapt their distributions.
/// </summary>
private readonly bool updateCdf;
/// <summary>
/// The next byte position to load into the code-value window.
/// </summary>
@ -51,9 +56,11 @@ internal ref struct Av1SymbolReader
/// Initializes a new instance of the <see cref="Av1SymbolReader"/> struct over one entropy-coded span.
/// </summary>
/// <param name="span">The bounded entropy-coded bytes.</param>
public Av1SymbolReader(Span<byte> span)
/// <param name="updateCdf">A value indicating whether decoded symbols adapt their distributions.</param>
public Av1SymbolReader(Span<byte> span, bool updateCdf = true)
{
this.buffer = span;
this.updateCdf = updateCdf;
this.position = 0;
this.difference = (1U << (DecoderWindowsSize - 1)) - 1;
this.range = 0x8000;
@ -62,7 +69,7 @@ internal ref struct Av1SymbolReader
}
/// <summary>
/// Reads one symbol and adapts its distribution.
/// Reads one symbol and adapts its distribution when CDF updates are enabled.
/// </summary>
/// <param name="distribution">The inverse cumulative distribution for the symbol alphabet.</param>
/// <returns>The decoded zero-based symbol.</returns>
@ -70,8 +77,12 @@ internal ref struct Av1SymbolReader
{
int value = this.DecodeIntegerQ15(distribution);
// Decoder and encoder must adapt after the same symbol so their subsequent intervals remain identical.
distribution.Update(value);
// disable_cdf_update freezes every tile distribution while leaving range decoding unchanged.
if (this.updateCdf)
{
distribution.Update(value);
}
return value;
}

20
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolWriter.cs

@ -39,6 +39,11 @@ internal class Av1SymbolWriter : IDisposable
/// </summary>
private readonly AutoExpandingMemory<ushort> memory;
/// <summary>
/// Indicates whether encoded symbols adapt their distributions.
/// </summary>
private readonly bool updateCdf;
/// <summary>
/// The next pre-carry output position.
/// </summary>
@ -49,10 +54,12 @@ internal class Av1SymbolWriter : IDisposable
/// </summary>
/// <param name="configuration">The configuration that supplies output allocation.</param>
/// <param name="initialSize">The estimated encoded size in bytes.</param>
public Av1SymbolWriter(Configuration configuration, int initialSize)
/// <param name="updateCdf">A value indicating whether encoded symbols adapt their distributions.</param>
public Av1SymbolWriter(Configuration configuration, int initialSize, bool updateCdf = true)
{
this.configuration = configuration;
this.memory = new AutoExpandingMemory<ushort>(configuration, (initialSize + 1) >> 1);
this.updateCdf = updateCdf;
}
/// <summary>
@ -61,7 +68,7 @@ internal class Av1SymbolWriter : IDisposable
public void Dispose() => this.memory.Dispose();
/// <summary>
/// Writes one binary symbol and adapts its distribution.
/// Writes one binary symbol and adapts its distribution when CDF updates are enabled.
/// </summary>
/// <param name="symbol">The binary symbol.</param>
/// <param name="distribution">The inverse cumulative distribution for the binary alphabet.</param>
@ -69,7 +76,7 @@ internal class Av1SymbolWriter : IDisposable
=> this.WriteSymbol(symbol ? 1 : 0, distribution);
/// <summary>
/// Writes one symbol and adapts its distribution.
/// Writes one symbol and adapts its distribution when CDF updates are enabled.
/// </summary>
/// <param name="symbol">The zero-based symbol.</param>
/// <param name="distribution">The inverse cumulative distribution for the symbol alphabet.</param>
@ -80,7 +87,12 @@ internal class Av1SymbolWriter : IDisposable
DebugGuard.IsTrue(distribution[distribution.NumberOfSymbols - 1] == 0, "Last entry in Probabilities table needs to be zero.");
this.EncodeIntegerQ15(symbol, distribution);
distribution.Update(symbol);
// disable_cdf_update freezes every tile distribution while leaving range encoding unchanged.
if (this.updateCdf)
{
distribution.Update(symbol);
}
}
/// <summary>

9
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs

@ -168,7 +168,14 @@ internal class Av1TileReader : IAv1TileReader
/// <remarks>Corresponds to <c>parse_tile</c> in SVT-AV1.</remarks>
public void ReadTile(Span<byte> tileData, int tileNum)
{
Av1SymbolDecoder reader = new(this.configuration, tileData, this.FrameHeader.QuantizationParameters.BaseQIndex);
// The frame syntax exposes a disable flag, while the range reader follows libaom's positive
// allow_update_cdf convention.
Av1SymbolDecoder reader = new(
this.configuration,
tileData,
this.FrameHeader.QuantizationParameters.BaseQIndex,
!this.FrameHeader.DisableCdfUpdate);
int tileColumnIndex = tileNum % this.FrameHeader.TilesInfo.TileColumnCount;
int tileRowIndex = tileNum / this.FrameHeader.TilesInfo.TileColumnCount;

Loading…
Cancel
Save