中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Unity Sockect怎么實現畫面實時傳輸

發布時間:2021-08-24 17:14:47 來源:億速云 閱讀:307 作者:chen 欄目:開發技術

這篇文章主要介紹“Unity Sockect怎么實現畫面實時傳輸”,在日常操作中,相信很多人在Unity Sockect怎么實現畫面實時傳輸問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Unity Sockect怎么實現畫面實時傳輸”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

目錄
  • 前言

  • 一、Socket通信原理

  • 二、畫面傳輸設計

    •  1.邏輯設計圖

    • 2.Unity服務端

    • 3.Unity客戶端

    • 4.最終效果

前言

提示:這里可以添加本文要記錄的大概內容:
例如:隨著人工智能的不斷發展,機器學習這門技術也越來越重要,很多人都開啟了學習機器學習,本文就介紹了機器學習的基礎內容。

提示:以下是本篇文章正文內容,下面案例可供參考

一、Socket通信原理

Socket是比較常用的一種通信方式。有關介紹可以點擊查看Socket通信原理

二、畫面傳輸設計

 1.邏輯設計圖

Unity Sockect怎么實現畫面實時傳輸

2.Unity服務端

首先創建一個Unity工程,然后新建Server場景,用于接受數據,展示畫面。
然后再場景中創建一個RawImage并設置為全屏。

如圖:

Unity Sockect怎么實現畫面實時傳輸

然后創建一個腳本,命名為UnityServer,再創建一個UnityServer.cs
在Start函數中創建Socket服務器,并開啟一個線程用于接受數據。
這里要注意一點,不能在接受數據線程中處理數據,需要在主線程中進行處理。
因為Unity主線程里面的資源不允許其他線程進行訪問。
在Update函數中處理數據,并展示圖片。

UnityServer .cs代碼如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;

public class UnityServer : MonoBehaviour {

	Socket socket = null;
	Thread thread = null;
	byte[] buffer = null;
	bool receState = true;

	int readTimes = 0;

    public RawImage rawImage;

    private Queue<byte[]> datas;

    void Start () {
		buffer = new byte[1024 * 1024 * 10];

        // 創建服務器, 以Tcp的方式
		socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		socket.Connect(IPAddress.Parse("192.168.1.87"), 10002);

        // 開啟一個線程, 用于接受數據
		thread = new Thread(new ThreadStart(Receive));
		thread.Start();

        datas = new Queue<byte[]>();
    }

    private void Receive()
    {
        while (thread.ThreadState == ThreadState.Running && socket.Connected)
        {
            // 接受數據Buffer count是數據的長度
			int count = socket.Receive(buffer);
            if (receState && count > 0)
            {
				receState = false;
                BytesToImage(count, buffer);
            }
        }
    }

	MemoryStream ms = null;
	public void BytesToImage(int count, byte[] bytes)
    {
        try
        {
            ms = new MemoryStream(bytes, 0, count);
            datas.Enqueue(ms.ToArray());    // 將數據存儲在一個隊列中,在主線程中解析數據。這是一個多線程的處理。

            readTimes++;

            if (readTimes > 5000)
            {
                readTimes = 0;
                GC.Collect(2);  // 達到一定次數的時候,開啟GC,釋放內存
            }
        }
        catch
        {

        }
        receState = true;
    }

    void Update()
    {
        if (datas.Count > 0)
        {
            // 處理紋理數據,并顯示
            Texture2D texture2D = new Texture2D(Screen.width, Screen.height);
            texture2D.LoadImage(datas.Dequeue());
            rawImage.texture = texture2D;
        }
    }

    void OnDestroy()
    {
        try
        {
            if (socket != null)
            {
                socket.Shutdown(SocketShutdown.Both);
            }
        }
        catch { }

        try
        {
            if (thread != null)
            {
                thread.Abort();
            }
        }
        catch { }

        datas.Clear();
    }
}

然后在場景中創建一個GameObject,將腳本掛載上,并將創建的RawImage拖拽到Inspector面板上對應的位置。

如圖:

Unity Sockect怎么實現畫面實時傳輸

3.Unity客戶端

然后我們創建一個客戶端工程,創建一個Client場景。
選中Main Camera,用Ctrl+D復制一個攝像機,放在Main Camera下面。
設置localPosition 和 localRotation為零。
這個相機的主要作用抓取屏幕渲染紋理。

如圖:

Unity Sockect怎么實現畫面實時傳輸

然后再創建一個腳本,命名為UnityClient.cs腳本。在Start中開啟Socket,然后開啟一個線程發送數據。
將其掛載在Main Camera上面,并將渲染攝像機拖拽到相應的位置。

UnityClient.cs代碼如下:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;

public class UnityClient : MonoBehaviour {

	public Camera cam;
	public int port = 10002;

	RenderTexture cameraView = null;

	Socket socket = null;

	Thread thread = null;

	bool success = true;

	Dictionary<string, Client> clients = new Dictionary<string, Client>();

	Vector3 old_position;   // 舊位置
	Quaternion old_rotation;	// 舊旋轉

	void Start () {
		cameraView = new RenderTexture(Screen.width, Screen.height, 24);
		cameraView.enableRandomWrite = true;

		cam.targetTexture = cameraView;
		old_position = transform.position;
		old_rotation = transform.rotation;

        // 開啟Socket
		socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		socket.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.87"), port));
		socket.Listen(100);

        // 開啟一個線程發送渲染數據
		thread = new Thread(new ThreadStart(OnStart));
		thread.Start();
	}

	int isNewAdd = 0;

	void OnStart()
    {
        Debug.Log("Socket創建成功");
        while (thread.ThreadState == ThreadState.Running)
        {
			Socket _socket = socket.Accept();
            if (clients.ContainsKey(_socket.RemoteEndPoint.ToString()))
            {
                try
                {
					clients[_socket.RemoteEndPoint.ToString()].socket.Shutdown(SocketShutdown.Both);
                }
                catch
                {
                }
				clients.Remove(_socket.RemoteEndPoint.ToString());
            }

			Client client = new Client
			{
				socket = _socket
			};

			clients.Add(_socket.RemoteEndPoint.ToString(), client);

			isNewAdd = 1;
        }
    }

	void Update()
    {
        if (success && clients.Count > 0)
        {
			success = false;
            SendTexture();
        }

        if (isNewAdd > 0)
        {
            isNewAdd = 0;
            SendTexture(1);
        }
    }

	void OnGUI()
    {
		GUI.DrawTexture(new Rect(10, 10, 240, 135), cameraView, ScaleMode.StretchToFill);
    }

	void OnApplicationQuit()
    {
        try
        {
			socket.Shutdown(SocketShutdown.Both);
        }
        catch { }

        try
        {
			thread.Abort();
        }
        catch { }
    }

	Texture2D screenShot = null;
	int gc_count = 0;

	void SendTexture(int isInt = 0)
    {
        if ((!old_position.Equals(transform.position) || !old_rotation.Equals(transform.rotation)) || isInt == 1)
        {
            if (null == screenShot)
            {
				screenShot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
            }

            // 讀取屏幕像素進行渲染
			RenderTexture.active = cameraView;
			screenShot.ReadPixels(new Rect(0, 0, cameraView.width, cameraView.height), 0, 0);
			RenderTexture.active = null;
			byte[] bytes = screenShot.EncodeToJPG(100);

            foreach (var val in clients.Values)
            {
                try
                {
					val.socket.Send(bytes);
                }
                catch
                {
                    if (!val.socket.Connected)
                    {
                        clients.Remove(val.socket.RemoteEndPoint.ToString());
                    }
                }
            }
            gc_count++;
            if (gc_count > 5000)
            {
                gc_count = 0;
                GC.Collect(2);
            }
            Debug.Log("發送數據:" + (float)bytes.Length / 1024f + "KB");

            old_position = cam.transform.position;
            old_rotation = cam.transform.rotation;
        }
        success = true;
    }

    void OnDestroy()
    {
        try
        {
            socket.Shutdown(SocketShutdown.Both);
        }
        catch { }

        try
        {
            thread.Abort();
        }
        catch { }
    }
}

class Client {
	public Socket socket = null;
}

4.最終效果

Unity Sockect怎么實現畫面實時傳輸

到此,關于“Unity Sockect怎么實現畫面實時傳輸”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

垣曲县| 太和县| 九龙坡区| 突泉县| 高邑县| 湟中县| 南充市| 孝昌县| 三河市| 紫金县| 长治市| 太仓市| 普安县| 东乌珠穆沁旗| 吉木萨尔县| 甘洛县| 如皋市| 钟祥市| 米林县| 永吉县| 岳西县| 张家界市| 大厂| 苗栗县| 本溪| 林芝县| 保山市| 重庆市| 措美县| 广饶县| 翼城县| 凤冈县| 湘阴县| 民和| 罗江县| 延川县| 德化县| 布尔津县| 防城港市| 盱眙县| 县级市|