using Microsoft.Azure.Kinect.BodyTracking; using Microsoft.Azure.Kinect.Sensor; using System; using System.IO; using System.Runtime.InteropServices; using System.Threading; using UnityEngine; public class SkeletalTrackingProvider : BackgroundDataProvider { bool readFirstFrame = false; TimeSpan initialTimestamp; public SkeletalTrackingProvider(int id) : base(id) { Debug.Log("in the skeleton provider constructor"); } System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter { get; set; } = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); public Stream RawDataLoggingFile = null; protected override void RunBackgroundThreadAsync(int id, CancellationToken token) { try { UnityEngine.Debug.Log("Starting body tracker background thread."); // Buffer allocations. BackgroundData currentFrameData = new BackgroundData(); // Open device. using (Device device = Device.Open(id)) { device.StartCameras(new DeviceConfiguration() { CameraFPS = FPS.FPS30, ColorResolution = ColorResolution.Off, DepthMode = DepthMode.NFOV_Unbinned, WiredSyncMode = WiredSyncMode.Standalone, }); UnityEngine.Debug.Log("Open K4A device successful. id " + id + "sn:" + device.SerialNum); var deviceCalibration = device.GetCalibration(); using (Tracker tracker = Tracker.Create(deviceCalibration, new TrackerConfiguration() { ProcessingMode = TrackerProcessingMode.Gpu, SensorOrientation = SensorOrientation.Default })) { UnityEngine.Debug.Log("Body tracker created."); while (!token.IsCancellationRequested) { using (Capture sensorCapture = device.GetCapture()) { // Queue latest frame from the sensor. tracker.EnqueueCapture(sensorCapture); } // Try getting latest tracker frame. using (Frame frame = tracker.PopResult(TimeSpan.Zero, throwOnTimeout: false)) { if (frame == null) { UnityEngine.Debug.Log("Pop result from tracker timeout!"); } else { IsRunning = true; // Get number of bodies in the current frame. currentFrameData.NumOfBodies = frame.NumberOfBodies; // Copy bodies. for (uint i = 0; i < currentFrameData.NumOfBodies; i++) { currentFrameData.Bodies[i].CopyFromBodyTrackingSdk(frame.GetBody(i), deviceCalibration); } // Store depth image. Capture bodyFrameCapture = frame.Capture; Image depthImage = bodyFrameCapture.Depth; if (!readFirstFrame) { readFirstFrame = true; initialTimestamp = depthImage.DeviceTimestamp; } currentFrameData.TimestampInMs = (float)(depthImage.DeviceTimestamp - initialTimestamp).TotalMilliseconds; currentFrameData.DepthImageWidth = depthImage.WidthPixels; currentFrameData.DepthImageHeight = depthImage.HeightPixels; // Read image data from the SDK. var depthFrame = MemoryMarshal.Cast(depthImage.Memory.Span); // Repack data and store image data. int byteCounter = 0; currentFrameData.DepthImageSize = currentFrameData.DepthImageWidth * currentFrameData.DepthImageHeight * 3; for (int it = currentFrameData.DepthImageWidth * currentFrameData.DepthImageHeight - 1; it > 0; it--) { byte b = (byte)(depthFrame[it] / (ConfigLoader.Instance.Configs.SkeletalTracking.MaximumDisplayedDepthInMillimeters) * 255); currentFrameData.DepthImage[byteCounter++] = b; currentFrameData.DepthImage[byteCounter++] = b; currentFrameData.DepthImage[byteCounter++] = b; } if (RawDataLoggingFile != null && RawDataLoggingFile.CanWrite) { binaryFormatter.Serialize(RawDataLoggingFile, currentFrameData); } // Update data variable that is being read in the UI thread. SetCurrentFrameData(ref currentFrameData); } } } Debug.Log("dispose of tracker now!!!!!"); tracker.Dispose(); } device.Dispose(); } if (RawDataLoggingFile != null) { RawDataLoggingFile.Close(); } } catch (Exception e) { Debug.Log($"catching exception for background thread {e.Message}"); token.ThrowIfCancellationRequested(); } } }