soundvision/UnityProject/Assets/ThridParty/Keijiro/Internal/ThreadedDriver.cs
2019-12-12 15:38:57 +01:00

152 lines
4.2 KiB
C#

using Microsoft.Azure.Kinect.Sensor;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace Akvfx
{
sealed class ThreadedDriver : IDisposable
{
#region Public properties and methods
public ThreadedDriver(DeviceSettings settings)
{
// FIXME: Dangerous. We should do this only on Player.
K4aExtensions.DisableSafeCopyNativeBuffers();
_settings = settings;
_captureThread = new Thread(CaptureThread);
_captureThread.Start();
}
public void Dispose()
{
_terminate = true;
_captureThread.Join();
TrimQueue(0);
ReleaseLastFrame();
GC.SuppressFinalize(this);
}
public ReadOnlySpan<float> XYTable
{
get { return _xyTable != null ? _xyTable.Data : null; }
}
public (ReadOnlyMemory<byte> color,
ReadOnlyMemory<byte> depth) LockLastFrame()
{
// Try retrieving the last frame.
if (_lockedFrame.capture == null)
_queue.TryDequeue(out _lockedFrame);
// Return null if it failed to retrieve.
if (_lockedFrame.capture == null) return (null, null);
return (_lockedFrame.capture.Color.Memory,
_lockedFrame.depth.Memory);
}
public void ReleaseLastFrame()
{
_lockedFrame.capture?.Dispose();
_lockedFrame.depth?.Dispose();
_lockedFrame = (null, null);
}
#endregion
#region Private objects
DeviceSettings _settings;
XYTable _xyTable;
#endregion
#region Capture queue
ConcurrentQueue<(Capture capture, Image depth)>
_queue = new ConcurrentQueue<(Capture, Image)>();
(Capture capture, Image depth) _lockedFrame;
// Trim the queue to a specified count.
void TrimQueue(int count)
{
while (_queue.Count > count)
{
(Capture capture, Image depth) temp;
_queue.TryDequeue(out temp);
temp.capture?.Dispose();
temp.depth?.Dispose();
}
}
#endregion
#region Capture thread
Thread _captureThread;
bool _terminate;
void CaptureThread()
{
// If there is no available device, do nothing.
if (Device.GetInstalledCount() == 0) return;
// Open the default device.
var device = Device.Open();
// Depth Mode
// Start capturing with custom settings.
device.StartCameras(
new DeviceConfiguration {
ColorFormat = ImageFormat.ColorBGRA32,
ColorResolution = ColorResolution.R1536p, // 2048 x 1536 (4:3)
DepthMode = _settings.depthMode, // defautlt NFOV unbinned 640x576
SynchronizedImagesOnly = true
}
);
// Construct XY table as a background task.
Task.Run(() => {
_xyTable = new XYTable(device.GetCalibration(), 2048, 1536);
});
// Set up the transformation object.
var transformation = new Transformation(device.GetCalibration());
// Initially apply the device settings.
var setter = new DeviceSettingController(device, _settings);
while (!_terminate)
{
// Get a frame capture.
var capture = device.GetCapture();
// Transform the depth image to the color perspective.
var depth = transformation.DepthImageToColorCamera(capture);
// Push the frame to the capture queue.
_queue.Enqueue((capture, depth));
// Remove old frames.
TrimQueue(1);
// Apply changes on the device settings.
setter.ApplySettings(device, _settings);
}
// Cleaning up.
transformation.Dispose();
device.Dispose();
}
#endregion
}
}