mirror of https://github.com/SixLabors/ImageSharp
3 changed files with 149 additions and 16 deletions
@ -0,0 +1,56 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Heif.Av1; |
||||
|
|
||||
|
internal ref struct Av1BitStreamWriter(Stream stream) |
||||
|
{ |
||||
|
private const int WordSize = sizeof(byte) * 8; |
||||
|
private readonly Stream stream = stream; |
||||
|
private byte buffer = 0; |
||||
|
private int bitOffset = 0; |
||||
|
|
||||
|
public readonly int BitPosition => (int)(this.stream.Position * WordSize) + this.bitOffset; |
||||
|
|
||||
|
public readonly int Length => (int)this.stream.Length; |
||||
|
|
||||
|
public void Skip(int bitCount) |
||||
|
{ |
||||
|
this.bitOffset += bitCount; |
||||
|
while (this.bitOffset >= WordSize) |
||||
|
{ |
||||
|
this.bitOffset -= WordSize; |
||||
|
this.stream.WriteByte(this.buffer); |
||||
|
this.buffer = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Flush() |
||||
|
{ |
||||
|
this.stream.WriteByte(this.buffer); |
||||
|
this.bitOffset = 0; |
||||
|
} |
||||
|
|
||||
|
public void WriteLiteral(uint value, int bitCount) |
||||
|
{ |
||||
|
int shift = 24; |
||||
|
uint padded = value << ((32 - bitCount) - this.bitOffset); |
||||
|
while (bitCount >= 8) |
||||
|
{ |
||||
|
byte current = (byte)(((padded >> shift) & 0xff) | this.buffer); |
||||
|
this.stream.WriteByte(current); |
||||
|
shift -= 8; |
||||
|
bitCount -= 8; |
||||
|
this.buffer = 0; |
||||
|
this.bitOffset = 0; |
||||
|
} |
||||
|
|
||||
|
if (bitCount > 0) |
||||
|
{ |
||||
|
this.buffer = (byte)(((padded >> shift) & 0xff) | this.buffer); |
||||
|
this.bitOffset += bitCount; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void WriteBoolean(bool value) => this.WriteLiteral(value ? 1U : 0U, 1); |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Buffers.Binary; |
||||
|
using SixLabors.ImageSharp.Formats.Heif.Av1; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1; |
||||
|
|
||||
|
[Trait("Format", "Avif")] |
||||
|
public class Av1BitsStreamTests |
||||
|
{ |
||||
|
[Theory] |
||||
|
[InlineData(42, new bool[] { false, false, true, false, true, false, true, false })] |
||||
|
[InlineData(52, new bool[] { false, false, true, true, false, true, false, false })] |
||||
|
public void ReadAsBoolean(int value, bool[] bits) |
||||
|
{ |
||||
|
int bitCount = bits.Length; |
||||
|
byte[] buffer = new byte[4]; |
||||
|
BinaryPrimitives.WriteInt32BigEndian(buffer, value << (32 - bitCount)); |
||||
|
Av1BitStreamReader reader = new(buffer); |
||||
|
bool[] actual = new bool[bitCount]; |
||||
|
for (int i = 0; i < bitCount; i++) |
||||
|
{ |
||||
|
actual[i] = reader.ReadBoolean(); |
||||
|
} |
||||
|
|
||||
|
Assert.Equal(bits, actual); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(6, 4)] |
||||
|
[InlineData(42, 8)] |
||||
|
[InlineData(52, 8)] |
||||
|
[InlineData(4050, 16)] |
||||
|
public void ReadAsLiteral(uint expected, int bitCount) |
||||
|
{ |
||||
|
byte[] buffer = new byte[4]; |
||||
|
BinaryPrimitives.WriteUInt32BigEndian(buffer, expected << (32 - bitCount)); |
||||
|
Av1BitStreamReader reader = new(buffer); |
||||
|
uint actual = reader.ReadLiteral(bitCount); |
||||
|
Assert.Equal(expected, actual); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(new bool[] { false, false, true, false, true, false, true, false })] |
||||
|
[InlineData(new bool[] { false, true, false, true })] |
||||
|
public void WriteAsBoolean(bool[] booleans) |
||||
|
{ |
||||
|
using MemoryStream stream = new(4); |
||||
|
Av1BitStreamWriter writer = new(stream); |
||||
|
for (int i = 0; i < booleans.Length; i++) |
||||
|
{ |
||||
|
writer.WriteBoolean(booleans[i]); |
||||
|
} |
||||
|
|
||||
|
writer.Flush(); |
||||
|
|
||||
|
// Read the written value back.
|
||||
|
Av1BitStreamReader reader = new(stream.GetBuffer()); |
||||
|
bool[] actual = new bool[booleans.Length]; |
||||
|
for (int i = 0; i < booleans.Length; i++) |
||||
|
{ |
||||
|
actual[i] = reader.ReadBoolean(); |
||||
|
} |
||||
|
|
||||
|
Assert.Equal(booleans, actual); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(6, 4)] |
||||
|
[InlineData(42, 8)] |
||||
|
[InlineData(52, 8)] |
||||
|
[InlineData(4050, 16)] |
||||
|
public void WriteAsLiteral(uint value, int bitCount) |
||||
|
{ |
||||
|
using MemoryStream stream = new(4); |
||||
|
Av1BitStreamWriter writer = new(stream); |
||||
|
writer.WriteLiteral(value, bitCount); |
||||
|
writer.Flush(); |
||||
|
|
||||
|
// Read the written value back.
|
||||
|
Av1BitStreamReader reader = new(stream.GetBuffer()); |
||||
|
uint actual = reader.ReadLiteral(bitCount); |
||||
|
Assert.Equal(value, actual); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue