Как говорится в этом вопросе, я пытаюсь передать WebCamTexture из клиента с веб-камерой на сервер. Обе стороны (клиент и сервер) находятся в Unity. Позже клиент будет развернут на Android, и сервер будет настольным приложением.Потоковая WebCamTexture с новым API уровня транспортного уровня Unity 5.1
В настоящее время я получаю пиксели текстуры с помощью:
tex.GetPixels32();
и Сериализация их с помощью пользовательского сериализатором (для оптимизации его размера). В настоящее время у меня есть несжатый массив байтов размером около 3,5 МБ на фрейм, готовый к отправке. Я знаю, что он огромен, но я хотел, чтобы он передавался перед началом работы с частью сжатия и частью в реальном времени.
Последней частью процесса должно быть послать его с использованием нового статического класса 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 действительно бедна.
Я работаю над подобным проектом, и мне было бы очень интересно увидеть содержание вашего метода сериализации. В любом случае, спасибо за то, что вы ответили на эту проблему. – Mario