Skip to content

Instantly share code, notes, and snippets.

@makihiro
Last active January 14, 2021 04:10
Show Gist options
  • Save makihiro/c880535fa6f9e3055f6371e5c3142add to your computer and use it in GitHub Desktop.
Save makihiro/c880535fa6f9e3055f6371e5c3142add to your computer and use it in GitHub Desktop.
ARTest-Reproducer.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR.ARFoundation;
using WebSocketSharp;
using WebSocketSharp.Server;
using System.IO;
// Replay AR data and camera images
namespace ARKitStream
{
public sealed class Reproducer : MonoBehaviour
{
public class ARKitService : WebSocketBehavior
{
public ARKitService()
{
}
protected override void OnMessage(MessageEventArgs e)
{
Debug.Log(e);
}
public void ExternalSend(byte[] data)
{
Send(data);
}
public void ExternalSendAsync(byte[] data)
{
SendAsync(data, null);
}
}
[SerializeField] ARCameraManager cameraManager = null;
[SerializeField] uint port = 8888;
[SerializeField] int targetFrameRate = 30;
RenderTexture renderTexture;
WebSocketServer server;
ARKitService service;
public string SavePath;
[SerializeField] string dirPath;
Texture2D tex;
IEnumerator<byte[]> coroutine;
Camera _camera;
float m_LastLocalizeTime = 0;
float m_LocalizationInterval = 4;
bool isLocalizing = false;
void Awake()
{
Application.targetFrameRate = targetFrameRate;
}
void Start()
{
if (!Application.isEditor)
{
Destroy(gameObject);
return;
}
SavePath = Application.persistentDataPath + "/saved-ardata.bytes";
dirPath = Application.persistentDataPath + "/imgs/";
tex = new Texture2D(1440, 1920);
// Prepare coroutine for loading AR data
coroutine = LoadARFileCoroutine();
cameraManager.frameReceived += OnCameraFrameReceived;
// Prepare camera texture
var commandBuffer = new CommandBuffer();
commandBuffer.name = "CameraView";
commandBuffer.Blit(tex, BuiltinRenderTextureType.CameraTarget);
_camera = GameObject.Find("AR Camera").GetComponent<Camera>();
_camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);
server = new WebSocketServer((int)port);
server.AddWebSocketService<ARKitService>("/arkit", (behaviour) =>
{
this.service = behaviour;
});
server.Start();
if (renderTexture == null)
{
renderTexture = new RenderTexture(1920, 1440, 0, RenderTextureFormat.ARGB32);
}
}
void OnDestroy()
{
if (cameraManager != null)
{
cameraManager.frameReceived -= OnCameraFrameReceived;
}
server?.Stop();
}
void OnValidate()
{
if (cameraManager == null)
{
cameraManager = FindObjectOfType<ARCameraManager>();
}
}
void Update()
{
if (service != null)
{
// Load LoadARFileCoroutine() by each frame update
coroutine.MoveNext();
if (coroutine.Current.Length > 0)
{
// Send AR data to ARKitStream Receiver
service.ExternalSendAsync(coroutine.Current);
}
}
else
{
Debug.Log("Preparing data to play");
}
}
// Coroutine for loading saved AR data
public IEnumerator<byte[]> LoadARFileCoroutine()
{
const byte RecordSeparator = 0x1e;
using (var stream = File.OpenRead(SavePath))
{
for ( ; ; )
{
var data = stream.ReadByte();
if (data < 0)
{
yield break;
}
using (var mem = new MemoryStream())
{
// Load each record data
for ( ; ; )
{
if (data == RecordSeparator)
{
var tmp = new int[4];
for (int i = 0; i < 4; i++) tmp[i] = stream.ReadByte();
// use five sequential 0x1e as a record separator
if (tmp[0] == 0x1e && tmp[1] == 0x1e && tmp[2] == 0x1e && tmp[3] == 0x1e)
{
break;
}
else
{
mem.WriteByte((byte)data);
for (int i = 0; i < 4; i++) mem.WriteByte((byte)tmp[i]);
}
}
else
{
mem.WriteByte((byte)data);
}
data = stream.ReadByte();
}
var record = mem.ToArray();
yield return record;
}
}
}
}
// Set texture by captured camera image
void OnCameraFrameReceived(ARCameraFrameEventArgs args)
{
var cameraImagePath = dirPath + args.timestampNs.Value + ".jpg";
if (File.Exists(cameraImagePath))
{
FileStream stream = File.OpenRead(cameraImagePath);
var data = new byte[stream.Length];
stream.Read(data, 0, (int)stream.Length);
tex.LoadImage(data);
float curTime = Time.unscaledTime;
stream.Close();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment