2015-07-07 2 views
4

Как говорится в этом вопросе, я пытаюсь передать 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 действительно бедна.

+0

Я работаю над подобным проектом, и мне было бы очень интересно увидеть содержание вашего метода сериализации. В любом случае, спасибо за то, что вы ответили на эту проблему. – Mario

ответ

1

В этом конкретном тестовом коде/примере все еще будут проблемы даже с патчем Unity 5.2.

Выполнение кода в Unity 5.3.4f1, я смог увидеть, что ошибка 4 (NetworkError.NoResource) происходит после 200 пакетов и прекращает отправку вскоре после этого.Я предполагаю, что причина в том, что это была блокировка отправки, и поэтому очередь сообщений никогда не сбрасывается должным образом.

Я переписал код, чтобы захватить изображение веб-камеры с текстуры после 2-секундной задержки (потому что веб-камера нуждается в времени для интуиции, иначе вы отправляете пустое изображение).

После отправки через изображение веб-камеры один пакет за выполнение обновления теперь кажется прекрасным. Вероятно, потому, что Update успели работать и не блокировалось. Поэтому отправьте пакет и выйдите из функции «Обновить», перемещая индекс и другие переменные из «Обновить».

Надеюсь, что это поможет кому-то еще, глядя на это, потребовалось 3 дня, чтобы выяснить.

РЕДАКТИРОВАТЬ: Для тестирования более простой метод заключается в том, чтобы вывести блокировку отправки (в то время как бит) и добавить его в совместную процедуру. Кажется, так и работает.

1

Наконец-то мне удалось снять снимок камеры по сети. Кажется, что попробуйте отправить несколько сообщений, не дожидаясь ответа сервера на заполнение очереди.

Все, что мне нужно было, это отправить ответ с сервера на клиент с помощью одного байта после каждого полученного сообщения. Клиент ожидает, что этот ACK отправит следующее сообщение. С этим все стало работать как шарм.

Я думаю, что для решения этой проблемы должен быть альтернативный способ, так как я не вижу достаточно разумного отправить сообщение для каждого полученного сообщения, но теперь он сделал трюк. Я отредактирую этот ответ с дополнительными выводами.

С уважением.

EDIT: Он оказался ошибкой Unity, и он был решен в Unity 5.2. (если я правильно помню).

Смежные вопросы