|
|
|
@ -34,9 +34,9 @@ internal sealed class Av1Distribution |
|
|
|
private const int ProbabilityBitCount = 15; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The inverse cumulative thresholds followed by the required zero sentinel.
|
|
|
|
/// The Q15 inverse cumulative thresholds followed by the required zero sentinel.
|
|
|
|
/// </summary>
|
|
|
|
private InlineArray16<uint> probabilities; |
|
|
|
private InlineArray16<ushort> probabilities; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The symbol-count contribution to the adaptive update rate.
|
|
|
|
@ -273,13 +273,13 @@ internal sealed class Av1Distribution |
|
|
|
/// <param name="speed">The symbol-count contribution to the update rate.</param>
|
|
|
|
private Av1Distribution(ReadOnlySpan<uint> props, int speed) |
|
|
|
{ |
|
|
|
Span<uint> probabilities = this.probabilities; |
|
|
|
Span<ushort> probabilities = this.probabilities; |
|
|
|
|
|
|
|
// AV1 range coding consumes inverse cumulative thresholds. The defaults are written in the more readable
|
|
|
|
// forward form, so convert every real threshold while leaving the final zero sentinel untouched.
|
|
|
|
// Q15 thresholds range from zero through 32768, including zero-mass intervals, and fit in unsigned 16-bit storage.
|
|
|
|
// Convert the forward defaults before narrowing; the final zero sentinel is already initialized.
|
|
|
|
for (int i = 0; i < props.Length - 1; i++) |
|
|
|
{ |
|
|
|
probabilities[i] = ProbabilityTop - props[i]; |
|
|
|
probabilities[i] = (ushort)(ProbabilityTop - props[i]); |
|
|
|
} |
|
|
|
|
|
|
|
this.NumberOfSymbols = props.Length; |
|
|
|
@ -292,8 +292,8 @@ internal sealed class Av1Distribution |
|
|
|
/// <param name="source">The distribution state to copy.</param>
|
|
|
|
private Av1Distribution(Av1Distribution source) |
|
|
|
{ |
|
|
|
ReadOnlySpan<uint> sourceProbabilities = source.probabilities; |
|
|
|
Span<uint> probabilities = this.probabilities; |
|
|
|
ReadOnlySpan<ushort> sourceProbabilities = source.probabilities; |
|
|
|
Span<ushort> probabilities = this.probabilities; |
|
|
|
sourceProbabilities[..source.NumberOfSymbols].CopyTo(probabilities); |
|
|
|
|
|
|
|
// The adaptation rate depends on both the alphabet size and prior update count, so copying only the
|
|
|
|
@ -329,8 +329,8 @@ internal sealed class Av1Distribution |
|
|
|
{ |
|
|
|
// Entropy contexts are created from the same fixed default table shape. Copy only mutable state so resetting a
|
|
|
|
// working tile never allocates or replaces the distribution objects referenced by the symbol decoder.
|
|
|
|
ReadOnlySpan<uint> sourceProbabilities = source.probabilities; |
|
|
|
Span<uint> probabilities = this.probabilities; |
|
|
|
ReadOnlySpan<ushort> sourceProbabilities = source.probabilities; |
|
|
|
Span<ushort> probabilities = this.probabilities; |
|
|
|
sourceProbabilities[..source.NumberOfSymbols].CopyTo(probabilities); |
|
|
|
this.updateCount = source.updateCount; |
|
|
|
} |
|
|
|
@ -402,7 +402,8 @@ internal sealed class Av1Distribution |
|
|
|
int tmp = ProbabilityTop; |
|
|
|
|
|
|
|
// Switching tmp to zero at the observed symbol moves the thresholds on either side toward the sample while
|
|
|
|
// preserving their inverse-cumulative ordering in one pass.
|
|
|
|
// preserving their inverse-cumulative ordering in one pass. Arithmetic stays wide until the stored update;
|
|
|
|
// each step moves toward zero or 32768, so narrowing cannot discard a significant probability bit.
|
|
|
|
for (int i = 0; i < this.NumberOfSymbols - 1; i++) |
|
|
|
{ |
|
|
|
tmp = i == value ? 0 : tmp; |
|
|
|
|