gpt4 book ai didi

c# - 使用新的 Unity 5.1 传输层 API 流式传输 WebCamTexture

转载 作者:行者123 更新时间:2023-11-30 12:25:34 25 4
gpt4 key购买 nike

正如问题所述,我一直在尝试将 WebCamTexture 从带有网络摄像头的客户端流式传输到服务器。双方(客户端和服务器)都在 Unity 中。稍后,客户端将部署到Android,服务器将是桌面应用程序。

目前我正在使用以下方式获取纹理的像素:

tex.GetPixels32();

并使用自定义序列化程序对它们进行序列化(以优化其大小)。我目前有一个未压缩的字节数组,每帧大约 3.5MB 准备发送。我知道它很大,但我想在开始压缩部分和实时部分之前先传输它。

流程的最后一部分应该是使用新的 Unity NetworkTransport 静态类发送它。距离上次用sockets已经很久了,真的烂透了。目前我无法让它工作。

这是我的服务器端代码(为清楚起见省略了序列化代码):

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;

}
}

我知道它会在发送之前阻止更新功能,但现在对我来说并不重要,因为我只是想传输一个帧以了解这个新系统的工作原理,并从那里继续。目前我在发送第一个包后收到此错误,缓冲区为 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的buffer,只是显示消息的时间比较长(超过100个包成功发送后)。

根据 this thread ,它与消息发送速度过快和填满队列有关,但没有一个建议的解决方案对我有用。我将不胜感激任何帮助或指导,因为 Unity 文档真的很差。

最佳答案

即使使用 Unity 5.2 补丁,此特定测试代码/示例仍然存在问题。

在 Unity 5.3.4f1 中运行代码,我能够看到错误 4 (NetworkError.NoResource) 发生在大约 200 个数据包之后并在不久之后停止发送。我认为原因是因为它是一个阻塞发送,所以消息队列永远不会正确刷新。

我重写了代码以在延迟 2 秒后从纹理中抓取网络摄像头图像(因为网络摄像头需要时间来初始化,否则您将发送空白图像)。

通过网络摄像头图像发送后,每次执行更新一个数据包现在似乎没问题。可能是因为 Update 有时间运行并且没有被阻止。所以发送一个数据包并退出 Update 函数,将索引和其他变量移出 Update。

希望这对其他人有帮助,我花了 3 天时间才弄明白。

编辑:对于测试,更简单的方法是移出阻塞发送(while 位)并将其添加到协同例程中。似乎也以这种方式工作。

关于c# - 使用新的 Unity 5.1 传输层 API 流式传输 WebCamTexture,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31269550/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com