赞
踩
使用Socket发送安卓端摄像机的内容其实也就是相当于发送一张图片,不同的是,这里是调用安卓的摄像机然后在进行实时发送。
发送流程是:点对点的发送,
发送方:
接收方
首先创建两个RawImage,用来当做显示面板,一个用来做发送端一个用来做接收端。
这次Socket采用UDP协议来进行传输。先进行封装一个ScoketUdp的类,后面用来调用发送和接收消息。
流程就是那几步,创建Socket、绑定IP和端口号、接收和发送消息、断开链接。’
这里直接放代码:
using System.Collections; using System.Collections.Generic; using System.Net.Sockets; using UnityEngine; using System.Net; using System.Threading; public class UdpSocket { Socket myUdpScoket; byte[] recvBuffer;//发送的容器 IPEndPoint recvPoint = new IPEndPoint(IPAddress.Any, 0); bool isRunning = true; Thread t; /// <summary> /// 接收到消息的回调函数 委托 /// </summary> public delegate void RecvDelegate(byte[] buffers, int realSize, string ip, int port); RecvDelegate recvCallBack; /// <summary> /// 构造函数 /// </summary> /// <param name="port"></param> /// <param name="bufferSize"></param> public UdpSocket(int port,int bufferSize,RecvDelegate recvDelegate) { recvCallBack = recvDelegate; Init(port,bufferSize); } public void Init(int port, int bufferSize) { recvBuffer = new byte[bufferSize];//接收消息的容器 myUdpScoket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //IPAddress 绑定网卡 IPAddress.Any自动获取一个闲的网卡 //10080为端口号 IPEndPoint tmpIPPoint = new IPEndPoint(IPAddress.Any, port); //绑定端口号和IP地址 myUdpScoket.Bind(tmpIPPoint); t = new Thread(ReceiveThrea); t.Start(); } /// <summary> /// 发送消息 /// </summary> public void SendMessage(byte[] buffers,string ip,int port) { //buffers 所需要发送的字节流 //buffers.Length发送的长度 //SocketFlags.None标记 //new IPEndPoint(IPAddress.Parse(ip), port) 发送的ip地址和端口号 //realSend 真正发送的字节数量 int realSend = myUdpScoket.SendTo(buffers, buffers.Length, SocketFlags.None, new IPEndPoint(IPAddress.Parse(ip), port)); } /// <summary> /// 接受消息的方法 /// </summary> public void ReceiveMessage() { EndPoint tmpPoint = recvPoint; int realRecv = myUdpScoket.ReceiveFrom(recvBuffer, ref tmpPoint); ///调用回调函数 recvCallBack(recvBuffer, realRecv, recvPoint.Address.ToString(), recvPoint.Port); } /// <summary> /// 异步接收 /// </summary> public void ReceiveThrea() { while (isRunning) { if (myUdpScoket != null && myUdpScoket.Available < 1) { Thread.Sleep(100); } ReceiveMessage(); } } /// <summary> /// 断开链接的方法 /// </summary> public void Dispose() { isRunning = false; t.Abort(); if (myUdpScoket != null) { myUdpScoket.Close(); } } }
然后我们按照上方的流程来一点一点的做:
首先发送方,需要捕获摄像机的内容,在Unity中有WebCamDevice这个API可以供我们使用
创建一个脚本,挂载到发送方,在Start方法中来来捕获摄像机的内容,并把它显示出来。
将图片转换成字节流,在Texture中有一个EncodeToJPG方法来供我们实现。每张图片都是一个二维数组的像素点,数组中的元素就是图片宽和高的位置信息。得到图片的大小以后进行二次循环,进行设置像素点即可。
创建一个发送的方法,使用上面我们封装好的Socket进行发送消息。
创建一个Socket对象,封装一个发送方法。
在获取摄像机内容的脚本中进行发送
这样发送方完成。
在创建一个用来接收的脚本。
先创建一个Socket,并创建出来,端口号为18002,因为在发送消息的时候,发送的端口号为18002,所以接收时的端口号一定为18002。
在上面我们封装好的Socket中,接收到消息时,我们会调用一个回调方法,也就是RecvBuffer这个方法。
定一个字节数组,把收到字节使用lock方式拷贝到这个字节数组中,完成辅线程到主线程的转换。
把字节流转换到图片,在Texture2d中有LoadImage这个API供我们使用,只需要传递一个字节数组就可以了,所以在Start方法中,还需要定义一个Texture2D,并赋值给接收方的RawImage的texture。
具体代码:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ReceiveImage : MonoBehaviour { UdpSocket udpSocket; byte[] receBuffer; bool isRecv; Texture2D texture2; private void Start() { udpSocket = new UdpSocket(18002, 1024 * 1024 * 10, new UdpSocket.RecvDelegate(RecvBuffer)); texture2 = new Texture2D(600,600); transform.GetComponent<RawImage>().texture = texture2; } private void Update() { if (isRecv) { isRecv = false; texture2.LoadImage(receBuffer); } } void RecvBuffer(byte[] buffers, int realSize, string ip, int port) { lock (this) { receBuffer = new byte[realSize]; Buffer.BlockCopy(buffers,0,receBuffer,0,realSize); } isRecv = true; } }
全部完成,打包安卓包,在手机运行,点击Button按钮就可以完成发送,记得给button添加点击事件,点击事件为获取摄像机方法中OnButtonClick()事件。
本人正在学习中,如果有错误欢迎各位大佬提携提携小弟,感激不尽!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。