Unity使用Socket发送安卓端摄像机的内容
使用Socket发送安卓端摄像机的内容其实也就是相当于发送一张图片,不同的是,这里是调用安卓的摄像机然后在进行实时发送。发送流程是:点对点的发送,发送方:捕获摄像机的数据将数据显示在纹理上将数据编程字节流将字节流发送出去接收方接收字节流切换到主线程将字节流转换为图片把图片显示出来首先创建两个RawImage,用来当做显示面板,一个用来做发送端一个用来做接收端。这...
使用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()事件。
本人正在学习中,如果有错误欢迎各位大佬提携提携小弟,感激不尽!!!
更多推荐
所有评论(0)