Декодирование потока GStreamer jpeg с помощью c # unity

#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();
        }




    }