您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
169 行
5.8 KiB
169 行
5.8 KiB
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
namespace NetworkCompression
|
|
{
|
|
// rANS
|
|
public struct RansOutputStream : IOutputStream
|
|
{
|
|
public RansOutputStream(byte[] buffer, int bufferOffset, NetworkCompressionCapture capture)
|
|
{
|
|
m_Entries = new List<uint>();
|
|
m_Buffer = buffer;
|
|
m_BufferOffset = bufferOffset;
|
|
}
|
|
|
|
public void Initialize(NetworkCompressionModel model, byte[] buffer, int bufferOffset, NetworkCompressionCapture capture)
|
|
{
|
|
this = new RansOutputStream(buffer, bufferOffset, capture);
|
|
}
|
|
|
|
public void WriteRawBits(uint value, int numBits)
|
|
{
|
|
Debug.Assert(numBits <= 32);
|
|
if(numBits > STATE_MIN_BITS)
|
|
{
|
|
m_Entries.Add(value & STATE_MIN_MASK);
|
|
value >>= STATE_MIN_BITS;
|
|
}
|
|
Debug.Assert(value < STATE_MIN_THRESHOLD);
|
|
m_Entries.Add(((uint)(numBits << STATE_MIN_BITS) | value));
|
|
}
|
|
|
|
public void WriteRawBytes(byte[] value, int srcIndex, int count)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
WriteRawBits(value[srcIndex + i], 8); //TODO: this sucks
|
|
}
|
|
|
|
public void WritePackedNibble(uint value, int context)
|
|
{
|
|
Debug.Assert(value < 16);
|
|
uint start = value * 16;
|
|
uint freq = 16;
|
|
m_Entries.Add((uint)((1 << 31) | (start << 8) | freq));
|
|
}
|
|
|
|
public void WritePackedUInt(uint value, int context)
|
|
{
|
|
int bucket = NetworkCompressionUtils.CalculateBucket(value);
|
|
uint offset = NetworkCompressionConstants.k_BucketOffsets[bucket];
|
|
int bits = NetworkCompressionConstants.k_BucketSizes[bucket];
|
|
|
|
WritePackedNibble((uint)bucket, context);
|
|
if (bits > 0)
|
|
WriteRawBits(value - offset, bits);
|
|
}
|
|
|
|
public void WritePackedIntDelta(int value, int baseline, int context)
|
|
{
|
|
WritePackedUIntDelta((uint)value, (uint)baseline, context);
|
|
}
|
|
|
|
public void WritePackedUIntDelta(uint value, uint baseline, int context)
|
|
{
|
|
int diff = (int)(baseline - value);
|
|
uint interleaved = (uint)((diff >> 31) ^ (diff << 1)); // interleave negative values between positive values: 0, -1, 1, -2, 2
|
|
WritePackedUInt(interleaved, context);
|
|
}
|
|
|
|
public int GetBitPosition2()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public NetworkCompressionModel GetModel()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public int Flush()
|
|
{
|
|
int numEntries = m_Entries.Count;
|
|
|
|
uint x = STATE_MIN_THRESHOLD;
|
|
|
|
int writePos = m_Buffer.Length;
|
|
for (int i = numEntries - 1; i >= 0; )
|
|
{
|
|
uint entry = m_Entries[i--];
|
|
if((entry & 0x80000000) != 0)
|
|
{
|
|
// Packed
|
|
uint start = (uint)((entry >> 8) & 0xFF);
|
|
uint freq = (uint)(entry & 0xFF);
|
|
|
|
// Renormalize
|
|
uint x_max = freq << STATE_MIN_BITS;
|
|
while (x >= x_max)
|
|
{
|
|
m_Buffer[--writePos] = (byte)x;
|
|
x >>= 8;
|
|
}
|
|
|
|
// Code
|
|
x = ((x / freq) << PROB_BITS) + (x % freq) + start;
|
|
}
|
|
else
|
|
{
|
|
// Raw
|
|
int numBits = (int)(entry >> STATE_MIN_BITS);
|
|
uint value = entry & STATE_MIN_MASK;
|
|
if (numBits > STATE_MIN_BITS)
|
|
{
|
|
uint x_max2 = STATE_MAX_THRESHOLD >> STATE_MIN_BITS;
|
|
while (x >= x_max2)
|
|
{
|
|
m_Buffer[--writePos] = (byte)x;
|
|
x >>= 8;
|
|
}
|
|
|
|
x = (x << STATE_MIN_BITS) | m_Entries[i--];
|
|
numBits -= STATE_MIN_BITS;
|
|
}
|
|
|
|
Debug.Assert(value < (1u << numBits));
|
|
|
|
uint x_max = STATE_MAX_THRESHOLD >> numBits;
|
|
while (x >= x_max)
|
|
{
|
|
m_Buffer[--writePos] = (byte)x;
|
|
x >>= 8;
|
|
}
|
|
|
|
x = (x << numBits) | value;
|
|
}
|
|
}
|
|
|
|
m_Entries.Clear();
|
|
|
|
int numBytes = m_Buffer.Length - writePos;
|
|
int compressedSize = 4 + numBytes;
|
|
|
|
// Write state and move output bytes to start of buffer
|
|
Debug.Assert(writePos >= compressedSize);
|
|
m_Buffer[m_BufferOffset + 0] = (byte)x;
|
|
m_Buffer[m_BufferOffset + 1] = (byte)(x >> 8);
|
|
m_Buffer[m_BufferOffset + 2] = (byte)(x >> 16);
|
|
m_Buffer[m_BufferOffset + 3] = (byte)(x >> 24);
|
|
for (int i = 0; i < numBytes; i++)
|
|
m_Buffer[m_BufferOffset + 4 + i] = m_Buffer[writePos + i];
|
|
|
|
m_BufferOffset += compressedSize;
|
|
return compressedSize;
|
|
}
|
|
|
|
List<uint> m_Entries; //TODO: can we cram this into ushort? We need probabilities to be at least 8bit, so signaling and encoding raw bytes is a little tricky
|
|
byte[] m_Buffer;
|
|
int m_BufferOffset;
|
|
|
|
const int PROB_BITS = 8;
|
|
const uint PROB_MASK = (1u << PROB_BITS) - 1u;
|
|
const int STATE_MIN_BITS = 23;
|
|
const int STATE_RENORM_BITS = 8;
|
|
const int STATE_MAX_BITS = STATE_MIN_BITS + STATE_RENORM_BITS;
|
|
const uint STATE_MIN_THRESHOLD = 1u << STATE_MIN_BITS;
|
|
const uint STATE_MAX_THRESHOLD = STATE_MIN_THRESHOLD << STATE_RENORM_BITS;
|
|
const uint STATE_MIN_MASK = STATE_MIN_THRESHOLD - 1u;
|
|
}
|
|
}
|