mirror of https://github.com/SixLabors/ImageSharp
4 changed files with 37 additions and 241 deletions
@ -1,173 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Six Labors Split License.
|
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.Heif.Av1; |
|
||||
|
|
||||
internal ref struct Av1BitStreamReader2 |
|
||||
{ |
|
||||
public const int WordSize = 1 << WordSizeLog2; |
|
||||
private const int WordSizeLog2 = 5; |
|
||||
|
|
||||
private readonly Span<byte> data; |
|
||||
private int wordPosition = 0; |
|
||||
private int bitOffset = 0; |
|
||||
|
|
||||
public Av1BitStreamReader2(Span<byte> data) => this.data = data; |
|
||||
|
|
||||
public readonly int BitPosition => ((this.wordPosition - 1) * WordSize) + this.bitOffset; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the number of bytes in the readers buffer.
|
|
||||
/// </summary>
|
|
||||
public readonly int Length => this.data.Length; |
|
||||
|
|
||||
public void Reset() |
|
||||
{ |
|
||||
this.wordPosition = 0; |
|
||||
this.bitOffset = 0; |
|
||||
} |
|
||||
|
|
||||
public void Skip(int bitCount) |
|
||||
{ |
|
||||
this.bitOffset += bitCount; |
|
||||
while (this.bitOffset >= WordSize) |
|
||||
{ |
|
||||
this.bitOffset -= WordSize; |
|
||||
this.wordPosition++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public uint ReadLiteral(int bitCount) |
|
||||
{ |
|
||||
DebugGuard.MustBeBetweenOrEqualTo(bitCount, 1, 32, nameof(bitCount)); |
|
||||
|
|
||||
uint literal = 0; |
|
||||
for (int bit = bitCount - 1; bit >= 0; bit--) |
|
||||
{ |
|
||||
literal |= this.ReadBit() << bit; |
|
||||
} |
|
||||
|
|
||||
return literal; |
|
||||
} |
|
||||
|
|
||||
internal uint ReadBit() |
|
||||
{ |
|
||||
int byteOffset = DivideBy8(this.bitOffset, false); |
|
||||
byte shift = (byte)(7 - Mod8(this.bitOffset)); |
|
||||
this.bitOffset++; |
|
||||
return (uint)((this.data[byteOffset] >> shift) & 0x01); |
|
||||
} |
|
||||
|
|
||||
internal bool ReadBoolean() => this.ReadLiteral(1) > 0; |
|
||||
|
|
||||
public ulong ReadLittleEndianBytes128(out int length) |
|
||||
{ |
|
||||
// See section 4.10.5 of the AV1-Specification
|
|
||||
DebugGuard.IsTrue((this.bitOffset & 0x07) == 0, $"Reading of Little Endian 128 value only allowed on byte alignment (offset {this.BitPosition})."); |
|
||||
|
|
||||
ulong value = 0; |
|
||||
length = 0; |
|
||||
for (int i = 0; i < 56; i += 7) |
|
||||
{ |
|
||||
uint leb128Byte = this.ReadLiteral(8); |
|
||||
value |= (leb128Byte & 0x7FUL) << i; |
|
||||
length++; |
|
||||
if ((leb128Byte & 0x80U) == 0) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
public uint ReadUnsignedVariableLength() |
|
||||
{ |
|
||||
// See section 4.10.3 of the AV1-Specification
|
|
||||
int leadingZerosCount = 0; |
|
||||
while (leadingZerosCount < 32 && this.ReadLiteral(1) == 0U) |
|
||||
{ |
|
||||
leadingZerosCount++; |
|
||||
} |
|
||||
|
|
||||
if (leadingZerosCount == 32) |
|
||||
{ |
|
||||
return uint.MaxValue; |
|
||||
} |
|
||||
|
|
||||
uint basis = (1U << leadingZerosCount) - 1U; |
|
||||
uint value = this.ReadLiteral(leadingZerosCount); |
|
||||
return basis + value; |
|
||||
} |
|
||||
|
|
||||
public uint ReadNonSymmetric(uint n) |
|
||||
{ |
|
||||
// See section 4.10.7 of the AV1-Specification
|
|
||||
if (n <= 1) |
|
||||
{ |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
int w = (int)(Av1Math.FloorLog2(n) + 1); |
|
||||
uint m = (uint)((1 << w) - n); |
|
||||
uint v = this.ReadLiteral(w - 1); |
|
||||
if (v < m) |
|
||||
{ |
|
||||
return v; |
|
||||
} |
|
||||
|
|
||||
return (v << 1) - m + this.ReadLiteral(1); |
|
||||
} |
|
||||
|
|
||||
public int ReadSignedFromUnsigned(int n) |
|
||||
{ |
|
||||
// See section 4.10.6 of the AV1-Specification
|
|
||||
int signedValue; |
|
||||
uint value = this.ReadLiteral(n); |
|
||||
uint signMask = 1U << (n - 1); |
|
||||
if ((value & signMask) == signMask) |
|
||||
{ |
|
||||
// Prevent overflow by casting to long;
|
|
||||
signedValue = (int)((long)value - (signMask << 1)); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
signedValue = (int)value; |
|
||||
} |
|
||||
|
|
||||
return signedValue; |
|
||||
} |
|
||||
|
|
||||
public uint ReadLittleEndian(int n) |
|
||||
{ |
|
||||
// See section 4.10.4 of the AV1-Specification
|
|
||||
DebugGuard.IsTrue((this.bitOffset & (WordSize - 1)) == 0, "Reading of Little Endian value only allowed on byte alignment"); |
|
||||
|
|
||||
uint t = 0; |
|
||||
for (int i = 0; i < 8 * n; i += 8) |
|
||||
{ |
|
||||
t += this.ReadLiteral(8) << i; |
|
||||
} |
|
||||
|
|
||||
return t; |
|
||||
} |
|
||||
|
|
||||
public Span<byte> GetSymbolReader(int tileDataSize) |
|
||||
{ |
|
||||
DebugGuard.IsTrue((this.bitOffset & 0x7) == 0, "Symbol reading needs to start on byte boundary."); |
|
||||
|
|
||||
throw new NotImplementedException("GetSymbolReader is not implemented yet / needs to be reviewd again"); |
|
||||
|
|
||||
// TODO: Pass exact byte iso Word start.
|
|
||||
// TODO: This needs to be reviewed again, due to the change in how ReadLiteral() works now!
|
|
||||
/*int spanLength = tileDataSize >> WordSizeInBytesLog2; |
|
||||
Span<uint> span = this.data.Slice(this.bitOffset >> WordSizeLog2, spanLength); |
|
||||
this.Skip(tileDataSize << Log2Of8); |
|
||||
return MemoryMarshal.Cast<uint, byte>(span);*/ |
|
||||
} |
|
||||
|
|
||||
// Last 3 bits are the value of mod 8.
|
|
||||
internal static int Mod8(int n) => n & 0x07; |
|
||||
|
|
||||
internal static int DivideBy8(int n, bool ceil) => (n + (ceil ? 7 : 0)) >> 3; |
|
||||
} |
|
||||
Loading…
Reference in new issue