#c# #unity3d #tcp #jpeg #gstreamer
#c# #unity3d #tcp #jpeg #gstreamer
Вопрос:
У меня есть поток, который я планировал закодировать с помощью GStreamer и отправить его по TCP, а затем декодировать их в Unity.
Это мой конвейер GStreamer:
gst-launch-1.0 v4l2src ! queue ! videoconvert ! video/x-raw,width=640,height=480,framerate=30/1 ! jpegenc ! multipartmux ! tcpserversink host=127.0.0.1 port=5000
У меня проблема с получением размера массива байтов для каждого кадра jpeg.
Чтобы правильно прочитать каждый кадр, мне нужно сначала получить размер каждого кадра и создать массив байтов такого размера.
var read = serverStream.Read(imageBytes, 0, **size**);
Если я извлекаю multipartmux
из конвейера, это выглядит как длинная последовательность данных, и она останавливается после получения первого кадра ( serverStream.DataAvailable
= FALSE)
Если я продолжу multipartmux
работу в конвейере, я сначала получу массив байтов, длина которого составляет примерно 70 ~ 80, затем я получу последовательность данных. Выглядит так:
{ 45, 45, 84, 104, 105, 115, 82, 97, 110, 100, 111, 109, 83, 116, 114, 105, 110, 103, 13, 10, 67, 111, 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 58, 32, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 13, 10, 67, 111, 110, 116, 101, 110, 116, 45, 76, 101, 110, 103, 116, 104, 58, 32, 51, 54, 55, 49, 52, 13, 10, 13, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
Но я не понимаю значения этого массива байтов … размер массива байтов каким-то образом описан в этом?
Если кто-нибудь может помочь мне с интерпретацией этих данных или дать мне некоторое представление о кодировке GStreamer jpeg и о том, как их декодировать, это было бы здорово. Спасибо!
private void readFrameByteArray(int size) {
bool disconnected = false;
UnityEngine.Debug.Log("- image size: " size);
NetworkStream serverStream = client.GetStream();
serverStream.ReadTimeout = 10;
UnityEngine.Debug.Log("ckp 1");
byte[] imageBytes = new byte[size];
var total = 0;
var sb = new StringBuilder("imageBytes[] { ");
do
{
//serverStream.ReadTimeout = 100;
UnityEngine.Debug.Log("ckp2: " serverStream.DataAvailable);
if (!serverStream.DataAvailable)return;
var read = serverStream.Read(imageBytes, total, size);
UnityEngine.Debug.Log("ckp3");
if (read == 0)
{
disconnected = true;
break;
}
total = read;
//UnityEngine.Debug.Log("- read: " read);
UnityEngine.Debug.Log("- FrameByteArray total: " total);
foreach (var b in imageBytes)
{
sb.Append(b ", ");
//if (b == 0) break;
}
sb.Append("}");
UnityEngine.Debug.Log(sb.ToString());
} while (serverStream.DataAvailable);
UnityEngine.Debug.Log("!serverStream.DataAvailable");
bool readyToReadAgain = false;
//Display Image
if (!disconnected) {
//Display Image on the main Thread
Loom.QueueOnMainThread(() => {
loadReceivedImage(imageBytes);
readyToReadAgain = true;
});
}
//Wait until old Image is displayed
while (!readyToReadAgain) {
UnityEngine.Debug.Log("!readyToReadAgain");
System.Threading.Thread.Sleep(1);
}
}
Ответ №1:
Для тех, кто ищет решение, вот как я в конечном итоге справился:
public class _TextureReceiver : MonoBehaviour
{
public int port = 5000;
public string IP = "127.0.0.1";
TcpClient client;
private NetworkStream serverStream;
[HideInInspector]
public Texture2D texture;
private bool stop = false;
[Header("Must be the same in sender and receiver")]
public int messageByteLength = 24;
public int maxFrameSize = 40000;
int try_count = 1;
// Use this for initialization
void Start()
{
//UnityEngine.Debug.Log("Start!");
Application.runInBackground = true;
client = new TcpClient();
//Connect to server from another Thread
Loom.RunAsync(() =>
{
TCP_Connect();
});
}
public void enStop()
{
stop = true;
if (client != null)
{
client.Close();
}
if (serverStream != null)
{
serverStream.Close();
}
return;
}
public void TCP_Connect()
{
client = new TcpClient();
IAsyncResult result = client.BeginConnect(IPAddress.Parse(IP), port, null, null);
result.AsyncWaitHandle.WaitOne(1000, true);
if (!client.Connected)
{
if (try_count > 0)
{
// UnityEngine.Debug.LogError("Ethernet Connection Error, Retry");
try_count ;
client.Close();
TCP_Connect();
}
else
{
client.Close();
//UnityEngine.Debug.Log("Missing Connection");
}
}
else
{
//UnityEngine.Debug.Log("V");
imageReceiver();
}
}
public void imageReceiver()
{
//While loop in another Thread is fine so we don't block main Unity Thread
Loom.RunAsync(() =>
{
while (!stop)
{
readFrameByteArray(maxFrameSize);
}
});
}
private void readFrameByteArray(int size)
{
bool disconnected = false;
serverStream = client.GetStream();
byte[] imageBytes = new byte[size];
var total = 0;
//UnityEngine.Debug.Log("serverStream.DataAvailable: " serverStream.DataAvailable);
if (!serverStream.DataAvailable) return;
var read = serverStream.Read(imageBytes, total, size);
if (read == 0)
{
disconnected = true;
//break;
}
total = read;
if (read == maxFrameSize) maxFrameSize = 5000;
//UnityEngine.Debug.Log("[V]read: " read);
bool readyToReadAgain = false;
//Display Image
if (!disconnected)
{
//Display Image on the main Thread
Loom.QueueOnMainThread(() =>
{
loadReceivedImage(imageBytes);
readyToReadAgain = true;
});
}
//Wait until old Image is displayed
while (!readyToReadAgain)
{
System.Threading.Thread.Sleep(1);
}
return;
}
void loadReceivedImage(byte[] receivedImageBytes)
{
//UnityEngine.Debug.Log("* load Received Image *");
if (texture)
{
if (receivedImageBytes[0] == 255 amp;amp; receivedImageBytes[1] == 216 amp;amp; receivedImageBytes[2] == 255 amp;amp; receivedImageBytes[3] == 224 amp;amp; receivedImageBytes[4] == 0 amp;amp; receivedImageBytes[5] == 16 amp;amp; receivedImageBytes[6] == 74 amp;amp; receivedImageBytes[7] == 70 amp;amp; receivedImageBytes[8] == 73 amp;amp; receivedImageBytes[9] == 70)
{
//UnityEngine.Debug.Log("* texture *");
texture.LoadImage(receivedImageBytes);
}
}
}
public void SetTargetTexture(Texture2D t)
{
texture = t;
}
public void OnApplicationQuit()
{
enStop();
}
}