Unity Socket实现画面实时传输

文章目录

  • Unity Socket实现画面实时传输
  • 一、Socket通信原理
  • 二、画面传输设计
    • 1.逻辑设计图
    • 2.Unity服务端
    • 3.Unity客户端
    • 4.最终效果

一、Socket通信原理

Socket是比较常用的一种通信方式。有关介绍可以点击查看Socket通信原理

二、画面传输设计

1.逻辑设计图

2.Unity服务端

首先创建一个Unity工程,然后新建Server场景,用于接受数据,展示画面。
然后再场景中创建一个RawImage并设置为全屏。

如图:

然后创建一个脚本,命名为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面板上对应的位置。

如图:

3.Unity客户端

然后我们创建一个客户端工程,创建一个Client场景。
选中Main Camera,用Ctrl+D复制一个摄像机,放在Main Camera下面。
设置localPosition 和 localRotation为零。
这个相机的主要作用抓取屏幕渲染纹理。

如图:

然后再创建一个脚本,命名为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;// 开启Socketsocket = 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实现画面实时传输相关推荐

  1. 电脑桌面画面实时传输到手机端或者HoloLens上显示(基于FMETP STREAM)

    电脑桌面画面实时传输到手机端或者HoloLens上显示(基于FMETP STREAM) 最近在研究HoloLens,突发奇想在HoloLens上显示电脑画面,便做了各种尝试,使用过微软的Mirage, ...

  2. rtp 多媒体流同步控制 实时传输协议 简介

    RTP(Real-time Transport Protocol)是由IETF开发的实时传输协议,可以在面向连接或无连接的下层协议上工作,通常和UDP协议一起使用.RTP的工作机理与RSVP不同,主要 ...

  3. 利用VC++实现局域网实时传输

    本文针对不同的局域网,提出一种通用的实时视频传输的解决方案.在使用Divx编解码的基础上,提出了从压缩.组帧.发送到接收.解压整个流程的思想,具体实施方案和VC++实现核心源代码以及传输控制策略,有效 ...

  4. Unity3d+百度AI 实现摄像头画面实时手势识别

    本文将讲到,如何利用百度ai的人体分析sdk在unity中实现摄像头实时画面的手势识别 工程链接在文末 (本人使用的是unity2018,unity2017以上都可以,不然.NET版本不支持) 1.准 ...

  5. android下实时传输h264并播放

    这周给安排了个任务,在android端读取H264原始视频数据,传一帧播一帧,播就播吧,还要Socket实时传输实时播,虽然并没有接触过,都无从下手,不过想到直播都是这么个形式,说明肯定是行得通的,而 ...

  6. 三维,XR视频低延时实时传输

    前言 伴随硬件性能和网络带宽的提升,终端部署的三维实时渲染,VR,AR等高计算,高数据量的服务也逐步可实现集中部署或云端部署.如云游戏,智慧园区中的数字孪生,智慧城市中的数据可视化,智慧教育中的三维可 ...

  7. Unity3d游戏画面实时同步html5或WebGL中(基于FMETP STREAM)

    一.准备画面发送端 1.新建unity3d工程(这里的版本为Unity3d2018.4.14),导入FMETP STREAM插件. 2.在场景创建空实体FMSocketIOManager,添加FMSo ...

  8. WebRTC音视频实时传输与服务质量

    为了保证音视频的质量,WebRTC底层做了大量的工作,尤其是网络传输与服务质量,更是其核心技术,本文由北京音视跳动科技有限公司 首席架构师 李超在LiveVideoStack线上分享的演讲整理而成,详 ...

  9. 实时传输协议(RTP)

    RTP简介 RTP是一种提供端对端传输服务的实时传输协议,用来支持在单目标广播和多目标广播网络服务中传输实时数据,而实时数据的传输则由RTCP协议来监视和控制. RTP定义在RFC 使用RTP协议的应 ...

最新文章

  1. 成功解决ValueError: could not convert string to float: ‘\\N‘
  2. python实现杨辉三角形博客园_Python实现杨辉三角
  3. mysql5.7 的 user表的密码字段从 password 变成了 authentication_string
  4. VB版双语对照制作助手
  5. 各地女孩被刮开短裙的反映
  6. 一周学C#之第4天——语句
  7. mysql数据库插入数据错误Error Code: 1118 - Row size too large ( 8126)
  8. 团队作业个人博客07
  9. R:读取大的TXT文件
  10. 项目管理的扫地僧---PRINCE2,学过PMP的必进!
  11. win11u盘无法弹出怎么办?win11u盘老是被占用不能退出?
  12. 一零四五、FAILED: SemanticException [Error 10293]: Unable to create temp file for insert values Expressio
  13. 快排(基础详解入门)
  14. 影音视频领域开源项目专区
  15. ubuntu 12.04下安装adobe flash
  16. 字体界的黑科技!输入数字立刻生成酷炫信息图的字体
  17. 重装解决一切 Linux:unknown filesystem
  18. 全球行政区划数据库 地理数据库
  19. PLC通讯-串口通讯
  20. ADI公司的元器件AD封装

热门文章

  1. 创始人学华为必看18词:力出一孔,利出一孔
  2. 2.0 Arduino各类模块-1(HC595、L293D芯片、L293D驱动板)
  3. 使用mshta.exe绕过应用程序白名单(多种方法)
  4. MuddyWater APT 样本分析
  5. LED数显驱动芯片,LED数码管驱动芯片VK1650,LED驱动控制IC,键盘扫描集成电路,内置RC震荡电路
  6. js 年月日时间转换
  7. EasyX库简单中文手册
  8. 天天生鲜Django项目源码
  9. 【Bash百宝箱】认识git
  10. C++ 制作检索小程序