// RayMix Libs - RayMix's .Net Libs
// Copyright 2018 Ray@raymix.net. All rights reserved.
// https://www.raymix.net
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of RayMix.net. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using CScript.App;
using CScript.Entity;
using CScript.Utilities;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgcodecsModule;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace CScript.Net
{
public struct PackageCheck
{
public string frameSymbols;
public int frameLenght;
public byte frameLastByteValue;
}
///
/// PackageHandler
/// 数据包处理器
///
public class PackageHandler : PackageHandler
{
public PackageHandler(object sender) : base(sender)
{
}
}
///
/// PackageHandler
/// 数据包处理器
///
/// 消息发送者类型
public class PackageHandler
{
//private MemoryStream stream = new MemoryStream(1024*1024*8);
private MemoryStream stream = new MemoryStream(4096000);
private int readOffset = 0;
private T sender;
NetMeshData netMeshData;
private List _shortBufferList;
private List _byteBufferList;
//private byte[] _byteBufferArray = new byte[232643];
int totalByteCount;
int lostCount;
private MemoryStream _streamDataBuffer = new MemoryStream(409600 * 10);
private bool _start = false;
string packageTypeStr = string.Empty;
Mat rgbMat;
private float _decodeTime;
//private Dictionary _packageCheckInfoDic;
public PackageHandler(T sender)
{
this.sender = sender;
netMeshData = new NetMeshData();
_shortBufferList = new List();
_byteBufferList = new List();
totalByteCount = 0;
lostCount = 0;
//_isNewData = App.AppManager.Instance.isNewMeshData;
//_packageCheckInfoDic = new Dictionary();
}
///
/// 接收数据到PackageHandler
///
///
///
///
public void ReceiveData(byte[] data, int offset, int count)
{
//UnityEngine.Debug.LogError(data.Length + " $$$" + count + " " + stream.Position);
// UnityEngine.Debug.LogWarning(data.Length + " $$$" + count + " " + stream.Position + " offset: " + offset + " stream.Capacity:" + stream.Capacity);
if (stream.Position + count > stream.Capacity)
{
throw new Exception("PackageHandler write buffer overflow");
}
stream.Write(data, offset, count);
ParsePackageTCP();
//ParsePackage();
}
public void ReceiveQuicData(byte[] data, int offset, int count)
{
if (_streamDataBuffer.Position + count > _streamDataBuffer.Capacity)
{
throw new Exception("PackageHandler write buffer overflow");
}
_streamDataBuffer.Write(data, offset, count);
totalByteCount += count;
netMeshData.Clear();
//UnPack1();
UnityEngine.Debug.LogWarning("_streamDataBuffer.len:"+_streamDataBuffer.Length);
bool isSuccess = UnPack2();
UnityEngine.Debug.LogWarning("lostCount: " + lostCount + "isSuccess:" + isSuccess);
UnityEngine.Debug.LogWarning("netMeshData:"+netMeshData);
if (isSuccess)
{
NetDistribute.Instance.Parsing(CScript.Utilities.AppUtil.Clone(netMeshData), rgbMat.clone(), totalByteCount, _decodeTime, lostCount);
}
netMeshData.Clear();
_streamDataBuffer.Position = 0;
_streamDataBuffer.SetLength(0);
totalByteCount = 0;
}
public void Reset()
{
readOffset = 0;
i = 0;
stream.Position = 0;
stream.SetLength(0);
_streamDataBuffer.Position = 0;
_streamDataBuffer.SetLength(0);
_start = false;
}
///
/// 打包消息
///
///
///
public static byte[] PackMessage()
{
byte[] package = null;
using (MemoryStream ms = new MemoryStream())
{
//ProtoBuf.Serializer.Serialize(ms, message);
package = new byte[ms.Length + 4];
Buffer.BlockCopy(BitConverter.GetBytes(ms.Length), 0, package, 0, 4);
Buffer.BlockCopy(ms.GetBuffer(), 0, package, 4, (int)ms.Length);
}
return package;
}
/////
///// 提取消息
/////
/////
/////
/////
/////
//public static SkillBridge.Message.NetMessage UnpackMessage(byte[] packet,int offset,int length)
//{
// SkillBridge.Message.NetMessage message = null;
// using (MemoryStream ms = new MemoryStream(packet, offset, length))
// {
// message = ProtoBuf.Serializer.Deserialize(ms);
// }
// return message;
//}
int i;
private int _frameIndex;
bool ParsePackageTCP()
{
if (!_start)
{
while (readOffset + 20 < stream.Position)
{
packageTypeStr = System.Text.Encoding.ASCII.GetString(stream.GetBuffer(), readOffset + 0, 1);
packageTypeStr += stream.GetBuffer()[readOffset + 1].ToString();
packageTypeStr += System.Text.Encoding.ASCII.GetString(stream.GetBuffer(), readOffset + 2, 1);
packageTypeStr += System.Text.Encoding.ASCII.GetString(stream.GetBuffer(), readOffset + 3, 1);
// UnityEngine.Debug.Log(packageTypeStr);
if (packageTypeStr == "$1@@")
{
_start = true;
break;
}
else
{
readOffset+=1;
}
}
}
else
{
if (readOffset + 20 < stream.Position)
{
int packageSize = BitConverter.ToInt32(stream.GetBuffer(), readOffset + 16);
if (packageSize + readOffset + 20 <= stream.Position)
{
_start = false;
_streamDataBuffer.Position = 0;
_streamDataBuffer.SetLength(0);
_streamDataBuffer.Write(stream.GetBuffer(), readOffset + 20, packageSize);
netMeshData.Clear();
UnPack2();
NetDistribute.Instance.Parsing(CScript.Utilities.AppUtil.Clone(netMeshData), rgbMat.clone(), totalByteCount, _decodeTime, 0);
netMeshData.Clear();
totalByteCount = 0;
_frameIndex = 0;
this.readOffset += (packageSize + 20);
return ParsePackageTCP();
}
}
}
//未接收完/要结束了
if (this.readOffset > 0)
{
long size = stream.Position - this.readOffset;
if (this.readOffset < stream.Position)
{
Array.Copy(stream.GetBuffer(), this.readOffset, stream.GetBuffer(), 0, stream.Position - this.readOffset);
}
//Reset Stream
this.readOffset = 0;
stream.Position = size;
stream.SetLength(size);
//UnityEngine.Debug.LogWarning("stream.Position: "+stream.Position+" "+ stream.Length);
netMeshData.Clear();
}
return true;
}
///
/// 数据包解析
///
///
bool ParsePackage()
{
if (!_start)
{
while (readOffset + 13 < stream.Position)
{
packageTypeStr = System.Text.Encoding.UTF8.GetString(stream.GetBuffer(), readOffset + 0, 1);
if (packageTypeStr == "#")
{
_start = true;
break;
}
else
{
readOffset++;
}
}
}
if (_start)
{
//UnityEngine.Debug.LogWarning("_start");
if (readOffset + 13 < stream.Position)
{
packageTypeStr = System.Text.Encoding.UTF8.GetString(stream.GetBuffer(), readOffset + 0, 1);
int packageSize = BitConverter.ToInt32(stream.GetBuffer(), readOffset + 9);
//UnityEngine.Debug.LogWarning(readOffset + " " + stream.Position + " " + packageSize+" "+ packageTypeStr);
if (packageSize + readOffset + 13 <= stream.Position)
{
if (packageTypeStr == "#")
{
// _packageCheckInfoDic.Clear();
_frameIndex = 0;
// UnityEngine.Debug.LogWarning("#");
_streamDataBuffer.Position = 0;
_streamDataBuffer.SetLength(0);
//UnityEngine.Debug.LogWarning("#:"+packageSize);
_streamDataBuffer.Write(stream.GetBuffer(), readOffset + 13, packageSize);
}
else if (packageTypeStr == "@")
{
// UnityEngine.Debug.LogWarning("@");
_streamDataBuffer.Write(stream.GetBuffer(), readOffset + 13, packageSize);
}
else if (packageTypeStr == "$")
{
_start = false;
_streamDataBuffer.Write(stream.GetBuffer(), readOffset + 13, packageSize);
//byte[] unzipData = lz4.Decompress(_streamDataBuffer.GetBuffer());
i++;
netMeshData.Clear();
if (AppConfig.isNewMeshData)
{
UnPack2();
}
else
{
UnPack1();
}
NetDistribute.Instance.Parsing(CScript.Utilities.AppUtil.Clone(netMeshData), rgbMat.clone(), totalByteCount, _decodeTime,0);
netMeshData.Clear();
totalByteCount = 0;
_frameIndex = 0;
}
this.readOffset += (packageSize + 13);
return ParsePackage();
}
}
}
//未接收完/要结束了
if (this.readOffset > 0)
{
long size = stream.Position - this.readOffset;
if (this.readOffset < stream.Position)
{
Array.Copy(stream.GetBuffer(), this.readOffset, stream.GetBuffer(), 0, stream.Position - this.readOffset);
}
//Reset Stream
this.readOffset = 0;
stream.Position = size;
stream.SetLength(size);
//UnityEngine.Debug.LogWarning("stream.Position: "+stream.Position+" "+ stream.Length);
netMeshData.Clear();
}
return true;
}
private void UnPack1()
{
int bufferOffset = 0;
//包有效
//总长度
ulong totalLenght = BitConverter.ToUInt64(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(UInt64);
// rgb size
uint rgbSize = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset) * 6;
bufferOffset += sizeof(UInt32);
_shortBufferList.Clear();
_shortBufferList.TrimExcess();
_shortBufferList.Capacity = (int)rgbSize;
// rgb 内容
for (int i = 0; i < rgbSize; i++)
{
_shortBufferList.Add(BitConverter.ToInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(Int16);
}
uint vertexCount = rgbSize / 6;
netMeshData.netSideVertexList.Capacity = (int)vertexCount * 3;
netMeshData.netColorList.Capacity = (int)vertexCount * 3;
// 顶点数据和颜色
for (int i = 0; i < vertexCount; i++)
{
netMeshData.netSideVertexList.Add(_shortBufferList[i * 6 + 0]);
netMeshData.netSideVertexList.Add(_shortBufferList[i * 6 + 1]);
netMeshData.netSideVertexList.Add(_shortBufferList[i * 6 + 2]);
netMeshData.netColorList.Add(_shortBufferList[i * 6 + 3]);
netMeshData.netColorList.Add(_shortBufferList[i * 6 + 4]);
netMeshData.netColorList.Add(_shortBufferList[i * 6 + 5]);
}
// 三角形
UInt64 indices_len_rgb = BitConverter.ToUInt64(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(UInt64);
if (indices_len_rgb > Int32.MaxValue)
{
//UnityEngine.Debug.Log("totalLenght:"+ totalLenght+" indices_len_rgb:" + indices_len_rgb);
UnityEngine.Debug.Log($"totalLenght:{totalLenght} rgbSize:{rgbSize} indices_len_rgb:{indices_len_rgb}");
}
netMeshData.netSideTriangles.Capacity = (int)indices_len_rgb;
for (ulong i = 0; i < indices_len_rgb; i++)
{
netMeshData.netSideTriangles.Add(BitConverter.ToUInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(Int16);
}
int ys_width_len = BitConverter.ToInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(Int32);
int ys_height_len = BitConverter.ToInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(Int32);
netMeshData.width = ys_width_len;
netMeshData.height = ys_height_len;
// 前面顶点长度
UInt32 vertexes_len = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (vertexes_len > Int32.MaxValue)
{
UnityEngine.Debug.Log(" vertexes_len*5:" + vertexes_len * 5);
}
UInt32 xyzuvs_size = vertexes_len * 5;
bufferOffset += sizeof(UInt32);
_shortBufferList.Clear();
_shortBufferList.TrimExcess();
_shortBufferList.Capacity = (int)xyzuvs_size;
for (int i = 0; i < xyzuvs_size; i++)
{
_shortBufferList.Add(BitConverter.ToInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(Int16);
}
netMeshData.netUvList.Capacity = (int)vertexes_len * 2;
netMeshData.netFrontVertexList.Capacity = (int)vertexes_len * 3;
vertexCount = xyzuvs_size / 5;
// 前面顶点 和 uv
for (int i = 0; i < vertexCount; i++)
{
netMeshData.netFrontVertexList.Add(_shortBufferList[i * 5 + 0]);
netMeshData.netFrontVertexList.Add(_shortBufferList[i * 5 + 1]);
netMeshData.netFrontVertexList.Add(_shortBufferList[i * 5 + 2]);
netMeshData.netUvList.Add(_shortBufferList[i * 5 + 3]);
netMeshData.netUvList.Add(_shortBufferList[i * 5 + 4]);
}
_shortBufferList.Clear();
_shortBufferList.TrimExcess();
UInt64 indices_len = BitConverter.ToUInt64(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(UInt64);
// 前面三角
netMeshData.netFrontTriangles.Capacity = (int)indices_len;
for (ulong i = 0; i < indices_len; i++)
{
netMeshData.netFrontTriangles.Add(BitConverter.ToUInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(ushort);
}
// 贴图数据
int imageYEncoderSize = BitConverter.ToInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(int);// y byte size
//netMeshData.netTexture.Capacity = imageYEncoderSize;
_byteBufferList.Clear();
_byteBufferList.Capacity = imageYEncoderSize;
//byte temp;
for (int i = 0; i < imageYEncoderSize; i++)
{
_byteBufferList.Add(_streamDataBuffer.GetBuffer()[bufferOffset++]);
}
DecodeImageMat(_byteBufferList.ToArray(),out rgbMat);
}
private bool UnPack2()
{
int bufferOffset = 0;
//总长度
ulong totalLenght = BitConverter.ToUInt64(_streamDataBuffer.GetBuffer(), bufferOffset);
bufferOffset += sizeof(UInt64);
int realCount = 0;
// atlsaXyz size
uint atlasXyzBufferLenght = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (atlasXyzBufferLenght > 1000000)
{
lostCount++;
return false;
}
bufferOffset += sizeof(UInt32);
realCount = (int)(atlasXyzBufferLenght / sizeof(Int16));
//UnityEngine.Debug.LogWarning("0 realCount:" + realCount);
netMeshData.netAtlasVertexList.Capacity = (int)realCount;
for (int i = 0; i < realCount; i++)
{
netMeshData.netAtlasVertexList.Add(BitConverter.ToInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(Int16);
}
//atlasUv size
uint atlasUvBufferLenght = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (atlasUvBufferLenght > 1000000)
{
lostCount++;
return false;
}
bufferOffset += sizeof(UInt32);
realCount = (int)(atlasUvBufferLenght / sizeof(UInt16));
//UnityEngine.Debug.LogWarning("1realCount:"+ realCount);
netMeshData.netAtlasUVList.Capacity = (int)realCount;
for (int i = 0; i < realCount; i++)
{
//UnityEngine.Debug.LogError(BitConverter.ToUInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
netMeshData.netAtlasUVList.Add(BitConverter.ToUInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(UInt16);
}
//atlasDices size
uint atlasIndicesBufferLenght = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (atlasIndicesBufferLenght > 1000000)
{
lostCount++;
return false;
}
bufferOffset += sizeof(UInt32);
realCount = (int)(atlasIndicesBufferLenght / sizeof(UInt16));
//UnityEngine.Debug.LogWarning("2realCount:" + realCount);
netMeshData.netTrianglesList.Capacity = (int)realCount;
for (int i = 0; i < realCount; i++)
{
netMeshData.netTrianglesList.Add(BitConverter.ToUInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(UInt16);
}
// 贴图数据
uint atlasImageBufferLenght = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (atlasImageBufferLenght > 1000000)
{
lostCount++;
return false;
}
bufferOffset += sizeof(UInt32);// y byte size
//netMeshData.netTexture.Capacity = imageYEncoderSize;
_byteBufferList.Clear();
realCount = (int)(atlasImageBufferLenght / sizeof(byte));
//UnityEngine.Debug.LogWarning("3 realCount:" + realCount);
_byteBufferList.Capacity = (int)realCount;
//byte temp;
for (int i = 0; i < realCount; i++)
{
_byteBufferList.Add(_streamDataBuffer.GetBuffer()[bufferOffset++]);
}
DecodeImageMat(_byteBufferList.ToArray(), out rgbMat);
//nosexyzrgb
uint noseXyzrgbBufferLenght = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (noseXyzrgbBufferLenght > 1000000)
{
lostCount++;
return false;
}
bufferOffset += sizeof(UInt32);
realCount = (int)(noseXyzrgbBufferLenght / sizeof(short));
_shortBufferList.Clear();
_shortBufferList.TrimExcess();
//UnityEngine.Debug.LogWarning("4 realCount:" + realCount);
_shortBufferList.Capacity = (int)realCount;
// nosexyzrgb 内容
for (int i = 0; i < realCount; i++)
{
_shortBufferList.Add(BitConverter.ToInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(Int16);
}
uint vertexCount = (uint)realCount / 6;
netMeshData.netSideVertexList.Capacity = (int)vertexCount * 3;
netMeshData.netColorList.Capacity = (int)vertexCount * 3;
// 顶点数据和颜色
for (int i = 0; i < vertexCount; i++)
{
netMeshData.netNoseVertexList.Add(_shortBufferList[i * 6 + 0]);
netMeshData.netNoseVertexList.Add(_shortBufferList[i * 6 + 1]);
netMeshData.netNoseVertexList.Add(_shortBufferList[i * 6 + 2]);
netMeshData.netNoseColorList.Add(_shortBufferList[i * 6 + 3]);
netMeshData.netNoseColorList.Add(_shortBufferList[i * 6 + 4]);
netMeshData.netNoseColorList.Add(_shortBufferList[i * 6 + 5]);
}
//nosexyzrgb
uint noseIndicesBufferLenght = BitConverter.ToUInt32(_streamDataBuffer.GetBuffer(), bufferOffset);
if (noseIndicesBufferLenght > 1000000)
{
lostCount++;
return false;
}
bufferOffset += sizeof(UInt32);
realCount = (int)(noseIndicesBufferLenght / sizeof(ushort));
// UnityEngine.Debug.LogWarning("5 realCount:" + realCount);
netMeshData.netNoseTriangles.Capacity = (int)realCount;
for (int i = 0; i < realCount; i++)
{
netMeshData.netNoseTriangles.Add(BitConverter.ToUInt16(_streamDataBuffer.GetBuffer(), bufferOffset));
bufferOffset += sizeof(UInt16);
}
return true;
}
private bool CheckSum(Dictionary packageCheckDic, ulong checksums)
{
UInt64 checkNumLocak = 0;
packageCheckDic.Values.ToList().ForEach(pcidValue => { checkNumLocak += (ulong)pcidValue.frameLenght; checkNumLocak += (ulong)pcidValue.frameLastByteValue; });
//UnityEngine.Debug.LogError(checkNumLocak);
if (checkNumLocak == checksums)
{
return true;
}
return false;
}
Stopwatch watch = new Stopwatch();
private void DecodeImageMat(byte[] imageRgbByte, out Mat imageRGBMat)
{
MatOfByte matOfByte = new MatOfByte(imageRgbByte);
Mat yuv;
// using (ProTimer p = new ProTimer("Imgcodecs.imdecode"))
{
//p._runTime
watch.Start();
yuv = Imgcodecs.imdecode(matOfByte, -1);
watch.Stop();
_decodeTime = watch.ElapsedMilliseconds;
watch.Reset();
}
imageRGBMat = new Mat(yuv.rows(), yuv.cols(), CvType.CV_8UC3);
Imgproc.cvtColor(yuv, imageRGBMat, Imgproc.COLOR_BGR2RGB);
}
}
}