/* * NatCorder * Copyright (c) 2020 Yusuf Olokoba. */ namespace NatSuite.Recorders { using UnityEngine; using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; using Internal; /// /// JPG image sequence recorder. /// This recorder is currently supported on macOS and Windows. /// This recorder is NOT thread-safe, and as such it is not fully compliant with the `IMediaRecorder` interfacex. /// public sealed class JPGRecorder : IMediaRecorder { #region --Client API-- /// /// Image size. /// public (int width, int height) frameSize => (framebuffer.width, framebuffer.height); /// /// Create a JPG recorder. /// /// Image width. /// Image height. public JPGRecorder (int imageWidth, int imageHeight) { // Save state this.framebuffer = new Texture2D(imageWidth, imageHeight, TextureFormat.RGBA32, false, false); this.writeTasks = new List(); // Create directory this.recordingPath = Utility.GetPath(string.Empty); Directory.CreateDirectory(recordingPath); } /// /// Commit a video pixel buffer for encoding. /// The pixel buffer MUST have an RGBA8888 pixel layout. /// /// Pixel buffer containing video frame to commit. /// Not used. public void CommitFrame (T[] pixelBuffer, long timestamp = default) where T : struct { var handle = GCHandle.Alloc(pixelBuffer, GCHandleType.Pinned); CommitFrame(handle.AddrOfPinnedObject(), timestamp); handle.Free(); } /// /// Commit a video pixel buffer for encoding. /// The pixel buffer MUST have an RGBA8888 pixel layout. /// /// Pixel buffer in native memory to commit. /// Not used. public void CommitFrame (IntPtr nativeBuffer, long timestamp = default) { // Encode immediately framebuffer.LoadRawTextureData(nativeBuffer, framebuffer.width * framebuffer.height * 4); var frameData = ImageConversion.EncodeToJPG(framebuffer); // Write out on a worker thread var frameIndex = ++frameCount; writeTasks.Add(Task.Run(() => File.WriteAllBytes(Path.Combine(recordingPath, $"{frameIndex}.jpg"), frameData))); } /// /// This recorder does not support committing audio samples. /// public void CommitSamples (float[] sampleBuffer = default, long timestamp = default) { } /// /// Finish writing and return the path to the recorded media file. /// public Task FinishWriting () { Texture2D.Destroy(framebuffer); return Task.WhenAll(writeTasks).ContinueWith(_ => recordingPath); } #endregion #region --Operations-- private readonly Texture2D framebuffer; private readonly string recordingPath; private readonly List writeTasks; private int frameCount; #endregion } }