upm_guru_kcp/Runtime/csharp-kcp/base-kcp/fec/FecEncode.cs

178 lines
5.9 KiB
C#
Raw Permalink Normal View History

2023-08-30 05:50:21 +00:00
using System;
using DotNetty.Buffers;
using fec;
namespace fec.fec
{
public class FecEncode
{
/**消息包长度**/
private readonly int dataShards;
/**冗余包长度**/
private readonly int parityShards;
/** dataShards+parityShards **/
private int shardSize;
//Protect Against Wrapped Sequence numbers
private readonly long paws;
// next seqid
private long next;
//count the number of datashards collected
private int shardCount;
// record maximum data length in datashard
private int maxSize;
// FEC header offset
private readonly int headerOffset;
// FEC payload offset
private readonly int payloadOffset;
//用完需要手动release
private readonly IByteBuffer[] shardCache;
private readonly IByteBuffer[] encodeCache;
private readonly IByteBuffer zeros;
private readonly ReedSolomon codec;
public FecEncode(int headerOffset, ReedSolomon codec, int mtu)
{
this.dataShards = codec.getDataShardCount();
this.parityShards = codec.getParityShardCount();
this.shardSize = this.dataShards + this.parityShards;
//this.paws = (Integer.MAX_VALUE/shardSize - 1) * shardSize;
this.paws = 0xffffffffL / shardSize * shardSize;
this.headerOffset = headerOffset;
this.payloadOffset = headerOffset + Fec.fecHeaderSize;
this.codec = codec;
this.shardCache = new IByteBuffer[shardSize];
this.encodeCache = new IByteBuffer[parityShards];
zeros = PooledByteBufferAllocator.Default.DirectBuffer(mtu);
zeros.WriteBytes(new byte[mtu]);
}
/**
*
* 使:
* 1bytebuf bytebuf,bytebuf
* 2nullnull
*
* headerOffset +6fectHead + 2bodylenth(lenth-headerOffset-6)
*
* 1, markData
* 2,
* 3,
* 4,fec
* 5,fec makefec
* 6,
*
* : bytebuf
* bytebuf
* @param byteBuf
* @return
*/
public IByteBuffer[] encode(IByteBuffer byteBuf)
{
markData(byteBuf, headerOffset);
int sz = byteBuf.WriterIndex;
byteBuf.SetShort(payloadOffset, sz - headerOffset - Fec.fecHeaderSizePlus2);
this.shardCache[shardCount] = byteBuf.RetainedDuplicate();
this.shardCount++;
if (sz > this.maxSize)
{
this.maxSize = sz;
}
if (shardCount != dataShards)
{
return null;
}
//填充parityShards
for (int i = 0; i < parityShards; i++)
{
IByteBuffer parityByte = PooledByteBufferAllocator.Default.DirectBuffer(this.maxSize);
shardCache[i + dataShards] = parityByte;
encodeCache[i] = parityByte;
markParity(parityByte, headerOffset);
parityByte.SetWriterIndex(this.maxSize);
}
//按着最大长度不足补充0
for (var i = 0; i < this.dataShards; i++)
{
var shard = shardCache[i];
var left = this.maxSize - shard.WriterIndex;
if (left <= 0)
continue;
//是否需要扩容 会出现吗??
//if(shard.capacity()<this.maxSize){
// ByteBuf newByteBuf = ByteBufAllocator.DEFAULT.buffer(this.maxSize);
// newByteBuf.writeBytes(shard);
// shard.release();
// shard = newByteBuf;
// shardCache[i] = shard;
//}
shard.WriteBytes(zeros, left);
zeros.SetReaderIndex(0);
}
codec.encodeParity(shardCache, payloadOffset, this.maxSize - payloadOffset);
//释放dataShards
for (int i = 0; i < dataShards; i++)
{
this.shardCache[i].Release();
this.shardCache[i] = null;
}
this.shardCount = 0;
this.maxSize = 0;
return this.encodeCache;
}
public void release()
{
this.shardSize = 0;
this.next = 0;
this.shardCount = 0;
this.maxSize = 0;
for (int i = 0; i < dataShards; i++)
{
var byteBuf = this.shardCache[i];
byteBuf?.Release();
}
zeros.Release();
}
private void markData(IByteBuffer byteBuf, int offset)
{
byteBuf.SetIntLE(offset, (int)this.next);
byteBuf.SetShortLE(offset + 4, Fec.typeData);
this.next++;
}
private void markParity(IByteBuffer byteBuf, int offset)
{
byteBuf.SetIntLE(offset, (int) this.next);
byteBuf.SetShortLE(offset + 4, Fec.typeParity);
//if(next==this.paws){
// next=0;
//}else{
// next++;
//}
this.next = (this.next + 1) % this.paws;
//if(next+1>=this.paws) {
// this.next++;
// //this.next = (this.next + 1) % this.paws;
//}
}
}
}