我正在尝试为 Bonsai 框架开发一个模块,它通过 tcp 流连接通过它自己的名为 jit.net.send 和 jit.net.recv 的 TCP 通信协议/标准/模块将 OpenCV.NET IplImage 的流发送到 Max 6.1
cycling74.com/sdk/MaxSDK-6.1.3/html/chapter_jit_networking.html 上有一些关于 jit.net.send 和 jit.net.recv 的文档
在 C++ 上完成了一些类似的工作,将纹理从 OpenFrameworks 发送到 github.com/bakercp/ofxJitterNetworkSender 上的 Max
还有一些 5 年前的 C# 代码在 disis.music.vt.edu/main/portfolio.php 上将纹理从 Max 发送到 Unity3D
我所追求的是从 C# 应用程序(在 Bonsai 框架的模块下)向 Max 发送视频流(OpenCV.NET IplImage 的)。
我当前的源代码位于https://bitbucket.org/artica/bonsai-with-jitnetsend
我设法移植了 C++ 代码并找出了大端问题(使用来自另一个 stackoverflow 线程的一些代码)。现在,当我运行应用程序时,Max 标记它已连接,并且在应用程序端,调试时,所有内容都在发送。但是没有显示数据矩阵图像。
编辑-设法取得了一些进展,在 2 台机器之间发送了一些测试 jit.net.send 数据包,并捕获了数据包以使用 Wireshark 进行分析。以下是我的分析摘要:
https://bitbucket.org/artica/bonsai-with-jitnetsend/wiki/Example%204x4
我重写了代码以匹配实际的数据包示例并设法发送 4x4 图像,但图像在 8x8 上出现故障并开始以更高分辨率抛出错误。我猜此时这是一个 IplImage 格式问题。以下是相关代码:
private string JIT_MATRIX_PACKET_ID = "JMTX";
public unsafe struct t_jit_net_packet_matrix {
public Int32 id;
public Int32 size;
public Int32 planecount;
public Int32 type; //0=char,1=long,2=float32,3=float64
public Int32 dimcount;
//public fixed Int32 dim[32];
//public fixed Int32 dimstride[32];
//public Int32 datasize;
//public double time; //64 bit double precision float
}
private t_jit_net_packet_matrix m_matrixHeader;
private void sendFrame(IplImage input) {
// setup matrix
Int32 matrix_id = BitConverter.ToInt32(Encoding.ASCII.GetBytes(JIT_MATRIX_PACKET_ID), 0);
Int32 planecount = input.NumChannels;
Int32 typeSize = input.Depth;
Int32 type = JIT_MATRIX_TYPE_CHAR;
Int32 width = 16;// input.Width;
Int32 height = 16;// input.Height;
m_matrixHeader.id = matrix_id;
m_matrixHeader.size = 288;
m_matrixHeader.planecount = planecount;
m_matrixHeader.type = type;
m_matrixHeader.dimcount = 2;
Int32[] dim = new Int32[32];
dim[0] = width;
dim[1] = height;
int i2 = 2;
while (i2 < JIT_MATRIX_MAX_DIMCOUNT)
{
dim[i2] = 1;
i2++;
}
Int32[] dimstride = new Int32[32];
dimstride[0] = planecount;
dimstride[1] = width * height;
i2 = 2;
while (i2 < JIT_MATRIX_MAX_DIMCOUNT)
{
dimstride[i2] = 0;
i2++;
}
Int32 datasize = planecount * width * height;
m_chunkHeader.id = BitConverter.ToInt32(Encoding.ASCII.GetBytes(JIT_MATRIX_PACKET_ID), 0);
m_chunkHeader.size = sizeof(Int32) * (6 + 32 + 32) + sizeof(double); //should be 288 bytes
byte[] chunkHeader = StructToBytes(m_chunkHeader, Endianness.LittleEndian);
//Console.WriteLine(BitConverter.ToString(chunkHeader));
byte[] matrixHeader = StructToBytes(m_matrixHeader, Endianness.BigEndian);
//Console.WriteLine(BitConverter.ToString(matrixHeader));
byte[] dim_send = new byte[4 * 32];
byte[] dimstride_send = new byte[4 * 32];
for (int i = 0; i < 32; i++)
{
byte[] dimbytes = BitConverter.GetBytes(dim[i]);
Array.Reverse(dimbytes);
System.Buffer.BlockCopy(dimbytes, 0, dim_send, i * 4, dimbytes.Length);
byte[] dimstridebytes = BitConverter.GetBytes(dimstride[i]);
Array.Reverse(dimstridebytes);
System.Buffer.BlockCopy(dimstridebytes, 0, dimstride_send, i * 4, dimstridebytes.Length);
}
//Console.WriteLine(BitConverter.ToString(dim_send));
//Console.WriteLine(BitConverter.ToString(dimstride_send));
byte[] datasize_send = BitConverter.GetBytes(datasize);
Array.Reverse(datasize_send);
//Console.WriteLine(BitConverter.ToString(datasize_send));
double time = 0; //todo: should be elapsed time, not 0
byte[] time_send = BitConverter.GetBytes(time);
Array.Reverse(time_send);
//Console.WriteLine(BitConverter.ToString(time_send));
int size = width * height * 4 * 2;//input.Height * input.Width * input.NumChannels * input.Depth / 4;
byte[] managedArray = new byte[size];
Marshal.Copy(input.ImageData, managedArray, 0, size);
Array.Reverse(managedArray);
//Console.WriteLine(BitConverter.ToString(managedArray));
byte[] output = new byte[chunkHeader.Length + matrixHeader.Length + dim_send.Length + dimstride_send.Length + datasize_send.Length + time_send.Length + managedArray.Length];
// chunkheader
System.Buffer.BlockCopy(chunkHeader, 0, output, 0, chunkHeader.Length);
// matrixheader
System.Buffer.BlockCopy(matrixHeader, 0, output, chunkHeader.Length, matrixHeader.Length);
// dim
System.Buffer.BlockCopy(dim_send, 0, output, chunkHeader.Length + matrixHeader.Length, dim_send.Length);
// dimstride
System.Buffer.BlockCopy(dimstride_send, 0, output, chunkHeader.Length + matrixHeader.Length + dim_send.Length, dimstride_send.Length);
// datasize
System.Buffer.BlockCopy(datasize_send, 0, output, chunkHeader.Length + matrixHeader.Length + dim_send.Length + dimstride_send.Length, datasize_send.Length);
// time
System.Buffer.BlockCopy(time_send, 0, output, chunkHeader.Length + matrixHeader.Length + dim_send.Length + dimstride_send.Length + datasize_send.Length, time_send.Length);
// matrix array
System.Buffer.BlockCopy(managedArray, 0, output, chunkHeader.Length + matrixHeader.Length + dim_send.Length + dimstride_send.Length + datasize_send.Length + time_send.Length, managedArray.Length);
Console.WriteLine(BitConverter.ToString(output));
if (myClient.Connected)
myStream.Write(output, 0, output.Length);
Console.WriteLine("looping");
//if (myClient.Connected)
// myStream.Write(managedArray, 0, managedArray.Length);
//Console.WriteLine(managedArray.ToString());
}