RyuKen/Ryujinx.Graphics/VDec/VpxRangeEncoder.cs

134 lines
3.6 KiB
C#
Raw Normal View History

using System.IO;
namespace Ryujinx.Graphics.VDec
{
class VpxRangeEncoder
{
private const int HalfProbability = 128;
private static readonly int[] NormLut = new int[]
{
0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
private Stream BaseStream;
private uint LowValue;
private uint Range;
private int Count;
public VpxRangeEncoder(Stream BaseStream)
{
this.BaseStream = BaseStream;
Range = 0xff;
Count = -24;
Write(false);
}
public void WriteByte(byte Value)
{
Write(Value, 8);
}
public void Write(int Value, int ValueSize)
{
for (int Bit = ValueSize - 1; Bit >= 0; Bit--)
{
Write(((Value >> Bit) & 1) != 0);
}
}
public void Write(bool Bit)
{
Write(Bit, HalfProbability);
}
public void Write(bool Bit, int Probability)
{
uint Range = this.Range;
uint Split = 1 + (((Range - 1) * (uint)Probability) >> 8);
Range = Split;
if (Bit)
{
LowValue += Split;
Range = this.Range - Split;
}
int Shift = NormLut[Range];
Range <<= Shift;
Count += Shift;
if (Count >= 0)
{
int Offset = Shift - Count;
if (((LowValue << (Offset - 1)) >> 31) != 0)
{
long CurrentPos = BaseStream.Position;
BaseStream.Seek(-1, SeekOrigin.Current);
while (BaseStream.Position >= 0 && PeekByte() == 0xff)
{
BaseStream.WriteByte(0);
BaseStream.Seek(-2, SeekOrigin.Current);
}
BaseStream.WriteByte((byte)(PeekByte() + 1));
BaseStream.Seek(CurrentPos, SeekOrigin.Begin);
}
BaseStream.WriteByte((byte)(LowValue >> (24 - Offset)));
LowValue <<= Offset;
Shift = Count;
LowValue &= 0xffffff;
Count -= 8;
}
LowValue <<= Shift;
this.Range = Range;
}
private byte PeekByte()
{
byte Value = (byte)BaseStream.ReadByte();
BaseStream.Seek(-1, SeekOrigin.Current);
return Value;
}
public void End()
{
for (int Index = 0; Index < 32; Index++)
{
Write(false);
}
}
}
}