正如问题所述,我一直在尝试将WebCamTexture从带有网络摄像头的客户端流式传输到服务器.双方(客户端和服务器)都在Unity中.之后,客户端将部署到
Android,服务器将成为桌面应用程序.
目前我正在使用以下方法获取纹理的像素:
tex.GetPixels32();
并使用自定义序列化程序对它们进行序列化(以优化其大小).我目前有一个未压缩的字节数组,每帧大约3,5MB,可以发送.我知道它很大,但我希望在开始之前将其传输到压缩部分和实时部分.
该过程的最后一部分应该是使用新的Unity NetworkTransport静态类发送它.自从我上次使用套接字以来已经很长时间了,我真的很烂.目前我无法让它工作.
这是我的服务器端代码(为清晰起见省略了序列化代码):
void Start()
{
webcamTexture = new WebCamTexture();
Background.texture = webcamTexture;
Background.material.mainTexture = webcamTexture;
webcamTexture.Play();
if (!_isStarted)
{
_isStarted = true;
NetworkTransport.Init();
m_Config = new ConnectionConfig();
m_CommunicationChannel = m_Config.AddChannel(QosType.ReliableFragmented);
HostTopology topology = new HostTopology(m_Config, 12);
m_GenericHostId = NetworkTransport.AddHost(topology, 0);
byte error;
m_ConnectionId = NetworkTransport.Connect(m_GenericHostId, ip, port, 0, out error);
}
}
void Update()
{
if (!_isStarted)
return;
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
case NetworkEventType.Nothing: //1
break;
case NetworkEventType.ConnectEvent: //2
Debug.Log("Received connection confirmation");
_readyToSend = true;
break;
case NetworkEventType.DataEvent: //3
break;
case NetworkEventType.DisconnectEvent: //4
//one of the established connection has been disconnected
Debug.Log(String.Format("Disconnect from host {0} connection {1}", recHostId, connectionId));
break;
}
if (_readyToSend)
{
_readyToSend = false; // To send just the first frame
byte[] colourArray = SerializeObject(MakeSerializable(GetRenderTexturePixels(webcamTexture))); // Serialize the webcam texture
// Sending total size
byte[] sizeToSend = BitConverter.GetBytes(colourArray.Length);
NetworkTransport.Send(m_GenericHostId, m_ConnectionId, m_CommunicationChannel, sizeToSend, sizeToSend.Length, out error);
byte[] bytes = new byte[bufferLenght];
int remainingBytes = colourArray.Length;
int index = 0;
int i = 1;
while (remainingBytes >= bufferLenght)
{
System.Buffer.BlockCopy(colourArray, index, bytes, 0, bufferLenght);
NetworkTransport.Send(m_GenericHostId, m_ConnectionId, m_CommunicationChannel, bytes, bytes.Length, out error);
remainingBytes -= bufferLenght;
Debug.Log(i++ + "Remaining bytes: " + remainingBytes + " - Error: "+error);
index += bufferLenght;
}
if (remainingBytes > 0) // Send the last fragment below bufferLenght bytes
{
System.Buffer.BlockCopy(colourArray, index, bytes, 0, remainingBytes);
NetworkTransport.Send(m_GenericHostId, m_ConnectionId, m_CommunicationChannel, bytes, remainingBytes, out error);
Debug.Log("Error: "+error);
}
}
}
这是客户方:
void Start()
{
if (!_isStarted)
{
_isStarted = true;
NetworkTransport.Init();
m_Config = new ConnectionConfig();
m_CommunicationChannel = m_Config.AddChannel(QosType.ReliableFragmented);
HostTopology topology = new HostTopology(m_Config, 12);
m_GenericHostId = NetworkTransport.AddHost(topology, port, null);
}
}
void Update()
{
if (!_isStarted)
return;
int recHostId;
int connectionId;
int channelId;
byte[] recBuffer = new byte[bufferLenght];
int bufferSize = bufferLenght;
int dataSize;
byte error;
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
case NetworkEventType.Nothing: //1
break;
case NetworkEventType.ConnectEvent: //2
//somebody else connect to me
Log.text += string.Format("Connect from host {0} connection {1}\n", recHostId, connectionId);
break;
case NetworkEventType.DataEvent: //3
if (!sizeReceived)
{
sizeReceived = true;
if (dataSize == 2)
{
bytesToReceive = BitConverter.ToInt16(recBuffer, 0);
}
else if (dataSize == 4)
{
bytesToReceive = BitConverter.ToInt32(recBuffer, 0);
}
Debug.Log("We will receive: "+bytesToReceive);
}
else
{
Log.text = string.Format("Received event host {0} connection {1} channel {2} message length {3}\n", recHostId, connectionId, channelId, dataSize);
Log.text += "Received " + bufferSize + " bytes\n";
bytesToReceive -= bufferSize;
Log.text += "Remaining " + bytesToReceive + " bytes\n";
}
break;
case NetworkEventType.DisconnectEvent: //4
break;
}
}
我知道它会阻止Update函数直到发送,但现在对我来说并不重要,因为我只是试图让一个帧被传输以了解这个新系统如何工作,并从那里开始.目前我在第一个包发送后收到此错误,缓冲区为32768字节:
no free events for long message
UnityEngine.Networking.NetworkTransport:Send(Int32, Int32, Int32, Byte[], Int32, Byte&)
CameraStreamer:Update() (at Assets/Scripts/Client/CameraStreamer.cs:112)
我还尝试使用1024缓冲区,显示消息只需要更长时间(超过100个成功发送包后).
根据this thread,它与发送的消息太快并填满队列有关,但所提出的解决方案都不适用于我.
我很感激任何帮助或方向,因为Unity文档真的很差.
最佳答案 即使使用Unity 5.2补丁,这个特定的测试代码/示例仍然会出现问题.
在Unity 5.3.4f1中运行代码,我能够看到错误4(NetworkError.NoResource)在大约200个数据包之后发生并且之后不久就停止发送.我认为原因是因为它是阻塞发送,因此消息队列永远不会正常刷新.
我重写了代码,以便在延迟2秒后从纹理中抓取网络摄像头图像(因为网络摄像头需要时间进行初始化,否则您会发送空白图像).
然后通过网络摄像头图像发送,每次执行Update的单个数据包现在看起来很好.可能是因为Update有时间运行并且没有被阻止.因此,发送数据包并退出Update函数,将索引和其他变量移出Update.
希望这有助于其他任何人看着这个,花了3天时间才弄明白.
编辑:对于测试,一个更简单的方法是移出阻塞发送(同时位)并将其添加到协同例程中.似乎也是这样工作的.