134 lines
3.6 KiB
C#
134 lines
3.6 KiB
C#
|
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)
|
||
|
{
|
||
|
_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 = _range;
|
||
|
|
||
|
uint split = 1 + (((range - 1) * (uint)probability) >> 8);
|
||
|
|
||
|
range = split;
|
||
|
|
||
|
if (bit)
|
||
|
{
|
||
|
_lowValue += split;
|
||
|
range = _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;
|
||
|
|
||
|
_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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|