diff --git a/K4AdotNet.Tests.Record/K4AdotNet.Tests.Record.csproj b/K4AdotNet.Tests.Record/K4AdotNet.Tests.Record.csproj
index da4bbcd..1162b2b 100644
--- a/K4AdotNet.Tests.Record/K4AdotNet.Tests.Record.csproj
+++ b/K4AdotNet.Tests.Record/K4AdotNet.Tests.Record.csproj
@@ -3,7 +3,7 @@
- netcoreapp2.1
+ netcoreapp3.1falseAnyCPUIntegration tests on Record API from K4AdotNet library
diff --git a/K4AdotNet.Tests.Unit/K4AdotNet.Tests.Unit.csproj b/K4AdotNet.Tests.Unit/K4AdotNet.Tests.Unit.csproj
index 29a1d28..a271537 100644
--- a/K4AdotNet.Tests.Unit/K4AdotNet.Tests.Unit.csproj
+++ b/K4AdotNet.Tests.Unit/K4AdotNet.Tests.Unit.csproj
@@ -3,7 +3,7 @@
- netcoreapp2.1
+ netcoreapp3.1falseAnyCPUUnit tests on types from K4AdotNet library
diff --git a/K4AdotNet.Tests.Unit/Sensor/ImageTests.cs b/K4AdotNet.Tests.Unit/Sensor/ImageTests.cs
index 2119cae..122eb6e 100644
--- a/K4AdotNet.Tests.Unit/Sensor/ImageTests.cs
+++ b/K4AdotNet.Tests.Unit/Sensor/ImageTests.cs
@@ -127,6 +127,52 @@ public void TestCreationFromArray()
}
}
+ [TestMethod]
+ public void TestCreationFromMemory()
+ {
+ var format = ImageFormat.Depth16;
+ var strideBytes = format.StrideBytes(testWidth);
+ var lengthElements = testWidth * testHeight;
+ var array = new short[lengthElements];
+ var owner = new TestMemoryOwner(array);
+
+ using (var image = Image.CreateFromMemory(owner, format, testWidth, testHeight, strideBytes))
+ {
+ Assert.AreNotEqual(IntPtr.Zero, image.Buffer);
+ Assert.AreEqual(format, image.Format);
+ Assert.AreEqual(testWidth, image.WidthPixels);
+ Assert.AreEqual(testHeight, image.HeightPixels);
+ Assert.AreEqual(strideBytes, image.StrideBytes);
+ Assert.AreEqual(owner.Memory.Length * sizeof(short), image.SizeBytes);
+
+ // Check that Buffer points to array
+ for (var i = 0; i < array.Length; i++)
+ array[i] = unchecked((short)i);
+
+ var buffer = image.Buffer;
+ for (var i = 0; i < array.Length; i++)
+ Assert.AreEqual(array[i], Marshal.ReadInt16(buffer, i * sizeof(short)));
+
+ Marshal.WriteInt16(buffer, ofs: 123 * sizeof(short), val: 2019);
+ Assert.AreEqual(2019, array[123]);
+
+ Assert.IsFalse(owner.IsDisposed);
+ }
+
+ Assert.IsTrue(owner.IsDisposed);
+ }
+
+ private sealed class TestMemoryOwner : System.Buffers.IMemoryOwner
+ {
+ private readonly short[] buffer;
+ private volatile bool isDisposed;
+ public TestMemoryOwner(short[] buffer) => this.buffer = buffer;
+ public Memory Memory => buffer;
+ public bool IsDisposed => isDisposed;
+ public void Dispose() => isDisposed = true;
+
+ }
+
#endregion
#region Testing of IsDisposed property, Dispose() method and Disposed event
diff --git a/K4AdotNet/K4AdotNet.csproj b/K4AdotNet/K4AdotNet.csproj
index 5f9b684..498965f 100644
--- a/K4AdotNet/K4AdotNet.csproj
+++ b/K4AdotNet/K4AdotNet.csproj
@@ -13,6 +13,10 @@
https://github.com/bibigone/k4a.net/raw/master/K4AdotNet-64.png
+
+ true
+
+
K4AdotNet.xmlOff
@@ -46,7 +50,6 @@
-
package\%(FileName)%(Extension)
diff --git a/K4AdotNet/K4AdotNet.xml b/K4AdotNet/K4AdotNet.xml
index d3a7509..4f853ce 100644
--- a/K4AdotNet/K4AdotNet.xml
+++ b/K4AdotNet/K4AdotNet.xml
@@ -6083,6 +6083,47 @@
or array is too small for specified image parameters.
+
+ Creates new image for specified underlying memory owner with specified format and size in pixels.
+ Type of elements in underlying memory buffer. Must be value type.
+ Memory owner of underlying buffer. Cannot be . Object will pin and keep reference to this array during all lifetime.
+ Format of image. Must be format with known stride: .
+ Width of image in pixels. Must be positive.
+ Height of image in pixels. Must be positive.
+ Created image. Not .
+
+ This version of method can be used only for with known dependency between image width in pixels and stride in bytes
+ and cannot be used for other formats. For details see .
+ For other formats use .
+
+ points to pinned memory of .
+
+
+ or is equal to or less than zero
+ or memory of is too small for specified image parameters.
+
+
+ Image stride in bytes cannot be automatically calculated from for specified .
+
+
+
+
+ Creates new image for specified underlying memory owner with specified format and size in pixels.
+ Type of elements in underlying memory buffer. Must be value type.
+ Memory owner of underlying buffer. Cannot be . Object will pin and keep reference to this array during all lifetime.
+ Format of image.
+ Width of image in pixels. Must be positive.
+ Height of image in pixels. Must be positive.
+ Image stride in bytes (the number of bytes per horizontal line of the image). Must be non-negative. Zero value can be used for and . /// Created image. Not .
+
+ points to pinned memory of .
+
+
+ or is equal to or less than zero
+ or is less than zero or is too small for specified
+ or memory of is too small for specified image parameters.
+
+
Call this method to free unmanaged resources associated with current instance.
@@ -6117,6 +6158,11 @@
Use this buffer to access the raw image data.This property cannot be called for disposed objects.
+
+ Access to the underlying memory buffer via span.
+ Unmanaged type that is going to use for memory access.
+ Span view to the underlying memory buffer.
+ Get the image buffer size in bytes.Use this function to know what the size of the image buffer is returned by .
diff --git a/K4AdotNet/Sensor/Image.cs b/K4AdotNet/Sensor/Image.cs
index 3d5643d..10af705 100644
--- a/K4AdotNet/Sensor/Image.cs
+++ b/K4AdotNet/Sensor/Image.cs
@@ -191,6 +191,83 @@ public static Image CreateFromArray(T[] buffer, ImageFormat format, int width
return Create(handle)!;
}
+#if NETSTANDARD2_1
+
+ /// Creates new image for specified underlying memory owner with specified format and size in pixels.
+ /// Type of elements in underlying memory buffer. Must be value type.
+ /// Memory owner of underlying buffer. Cannot be . Object will pin and keep reference to this array during all lifetime.
+ /// Format of image. Must be format with known stride: .
+ /// Width of image in pixels. Must be positive.
+ /// Height of image in pixels. Must be positive.
+ /// Created image. Not .
+ ///
+ /// This version of method can be used only for with known dependency between image width in pixels and stride in bytes
+ /// and cannot be used for other formats. For details see .
+ /// For other formats use .
+ ///
+ /// points to pinned memory of .
+ ///
+ ///
+ /// or is equal to or less than zero
+ /// or memory of is too small for specified image parameters.
+ ///
+ ///
+ /// Image stride in bytes cannot be automatically calculated from for specified .
+ ///
+ ///
+ public static Image CreateFromMemory(System.Buffers.IMemoryOwner memoryOwner, ImageFormat format, int widthPixels, int heightPixels)
+ where T : unmanaged
+ => CreateFromMemory(memoryOwner, format, widthPixels, heightPixels, format.StrideBytes(widthPixels));
+
+
+ /// Creates new image for specified underlying memory owner with specified format and size in pixels.
+ /// Type of elements in underlying memory buffer. Must be value type.
+ /// Memory owner of underlying buffer. Cannot be . Object will pin and keep reference to this array during all lifetime.
+ /// Format of image.
+ /// Width of image in pixels. Must be positive.
+ /// Height of image in pixels. Must be positive.
+ /// Image stride in bytes (the number of bytes per horizontal line of the image). Must be non-negative. Zero value can be used for and . /// Created image. Not .
+ ///
+ /// points to pinned memory of .
+ ///
+ ///
+ /// or is equal to or less than zero
+ /// or is less than zero or is too small for specified
+ /// or memory of is too small for specified image parameters.
+ ///
+ public static unsafe Image CreateFromMemory(System.Buffers.IMemoryOwner memoryOwner, ImageFormat format, int widthPixels, int heightPixels, int strideBytes)
+ where T : unmanaged
+ {
+ if (memoryOwner is null)
+ throw new ArgumentNullException(nameof(memoryOwner));
+ if (widthPixels <= 0)
+ throw new ArgumentOutOfRangeException(nameof(widthPixels));
+ if (heightPixels <= 0)
+ throw new ArgumentOutOfRangeException(nameof(heightPixels));
+ if (strideBytes < 0)
+ throw new ArgumentOutOfRangeException(nameof(strideBytes));
+ if (format.HasKnownBytesPerPixel() && strideBytes < widthPixels * format.BytesPerPixel())
+ throw new ArgumentOutOfRangeException(nameof(strideBytes));
+
+ var memory = memoryOwner.Memory;
+ var sizeBytes = memory.Length * Marshal.SizeOf();
+ if (strideBytes > 0 && sizeBytes < format.ImageSizeBytes(strideBytes, heightPixels))
+ throw new ArgumentOutOfRangeException(nameof(memoryOwner) + "." + nameof(memoryOwner.Memory) + nameof(memory.Length));
+
+ var memoryPin = memory.Pin();
+ var memoryPtr = new IntPtr(memoryPin.Pointer);
+
+ var res = NativeApi.ImageCreateFromBuffer(format, widthPixels, heightPixels, strideBytes,
+ memoryPtr, Helpers.Int32ToUIntPtr(sizeBytes), pinnedMemoryReleaseCallback, PinnedMemoryContext.Create(memoryOwner, memoryPin),
+ out var handle);
+ if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
+ throw new ArgumentException($"Cannot create image with format {format}, size {widthPixels}x{heightPixels} pixels, stride {strideBytes} bytes from memory of size {sizeBytes} bytes.");
+
+ return Create(handle)!;
+ }
+
+#endif
+
private void Handle_Disposed(object sender, EventArgs e)
{
handle.Disposed -= Handle_Disposed;
@@ -233,6 +310,16 @@ public Image DuplicateReference()
/// This property cannot be called for disposed objects.
public IntPtr Buffer => NativeApi.ImageGetBuffer(handle.ValueNotDisposed);
+#if NETSTANDARD2_1
+
+ /// Access to the underlying memory buffer via span.
+ /// Unmanaged type that is going to use for memory access.
+ /// Span view to the underlying memory buffer.
+ public unsafe Span GetSpan() where T : unmanaged
+ => new Span(Buffer.ToPointer(), SizeBytes / Marshal.SizeOf());
+
+#endif
+
/// Get the image buffer size in bytes.
/// Use this function to know what the size of the image buffer is returned by .
/// This property cannot be called for disposed objects.
@@ -483,7 +570,7 @@ public void FillFrom(int[] src)
internal static NativeHandles.ImageHandle ToHandle(Image? image)
=> image?.handle?.ValueNotDisposed ?? NativeHandles.ImageHandle.Zero;
- #region Equatable
+#region Equatable
/// Two images are equal when they reference to one and the same unmanaged object.
/// Another image to be compared with this one. Can be .
@@ -524,9 +611,9 @@ public override int GetHashCode()
public override string ToString()
=> handle.ToString();
- #endregion
+#endregion
- #region Memory management
+#region Memory management
// This field is required to keep callback delegate in memory
private static readonly NativeApi.MemoryDestroyCallback unmanagedBufferReleaseCallback
@@ -542,6 +629,41 @@ private static readonly NativeApi.MemoryDestroyCallback pinnedArrayReleaseCallba
private static void ReleasePinnedArray(IntPtr buffer, IntPtr context)
=> ((GCHandle)context).Free();
+#if NETSTANDARD2_1
+
+ private struct PinnedMemoryContext
+ {
+ private IDisposable memoryOwner;
+ private System.Buffers.MemoryHandle memoryHandle;
+
+ public static IntPtr Create(IDisposable memoryOwner, System.Buffers.MemoryHandle memoryHandle)
+ {
+ var context = new PinnedMemoryContext { memoryOwner = memoryOwner, memoryHandle = memoryHandle };
+ var ptr = Marshal.AllocHGlobal(Marshal.SizeOf());
+ Marshal.StructureToPtr(context, ptr, fDeleteOld: false);
+ return ptr;
+ }
+
+ public static void Destroy(IntPtr ptr)
+ {
+ var context = Marshal.PtrToStructure(ptr);
+ context.memoryHandle.Dispose();
+ context.memoryOwner.Dispose();
+ Marshal.FreeHGlobal(ptr);
+ }
+ }
+
+ // This field is required to keep callback delegate in memory
+ private static readonly NativeApi.MemoryDestroyCallback pinnedMemoryReleaseCallback
+ = new NativeApi.MemoryDestroyCallback(ReleasePinnedMemory);
+
+ private static void ReleasePinnedMemory(IntPtr _, IntPtr context)
+ => PinnedMemoryContext.Destroy(context);
+
+#endif
+
#endregion
+
+
}
}
diff --git a/Product.props b/Product.props
index a408be1..b28b342 100644
--- a/Product.props
+++ b/Product.props
@@ -1,7 +1,7 @@
- 1.4.12
- 1.4.12.0
+ 1.4.13
+ 1.4.13.0See https://github.com/bibigone/k4a.net/releases bibigone,baSSiLL
diff --git a/ProductInfo.cs b/ProductInfo.cs
index c57d438..fe5370b 100644
--- a/ProductInfo.cs
+++ b/ProductInfo.cs
@@ -7,5 +7,5 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("1.4.12.0")]
-[assembly: AssemblyFileVersion("1.4.12.0")]
+[assembly: AssemblyVersion("1.4.13.0")]
+[assembly: AssemblyFileVersion("1.4.13.0")]
diff --git a/README.md b/README.md
index 381a26d..b262e36 100644
--- a/README.md
+++ b/README.md
@@ -17,10 +17,9 @@
## Key features
* Written fully on C#
-* No unsafe code in library **K4AdotNet** itself (only `DllImports` to SDKs)
* CLS-compliant (can be used from any .Net-compatible language, including C#, F#, VB.Net)
* Library **K4AdotNet** is compiled against **.NET Standard 2.0, 2.1** and **.NET Framework 4.6.1** target frameworks
- * This makes it compatible with **.NET Core 2.0/3.1**, **.NET Framework 4.6.1** and later, **Unity 2018.1** and later, etc.
+ * This makes it compatible with **.NET 5**, **.NET Core 2.0-3.1**, **.NET Framework 4.6.1** and later, **Unity 2018.1** and later, etc.
* See https://docs.microsoft.com/en-us/dotnet/standard/net-standard for details
* Clean API, which is close to C/C++ native API from [Azure Kinect Sensor SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/sensor-sdk-download) and [Azure Kinect Body Tracking SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/body-sdk-download).
* Plus useful helper methods, additional checks and meaningful exceptions.
@@ -28,7 +27,7 @@
* Up-to-date with the latest versions of native SDKs
* No additional dependencies
* Except dependencies on native libraries (DLLs) from [Azure Kinect Sensor SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/sensor-sdk-download) and [Azure Kinect Body Tracking SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/body-sdk-download)
- * Native libraries from [Azure Kinect Sensor SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/sensor-sdk-download) are included to repository(see `externals` directory) and [NuGet package](https://www.nuget.org/packages/K4AdotNet)
+ * Native libraries from [Azure Kinect Sensor SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/sensor-sdk-download) are included to repository (see `externals` directory) and [NuGet package](https://www.nuget.org/packages/K4AdotNet)
* But native libraries from [Azure Kinect Body Tracking SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/body-sdk-download) are *not* included to repository. It is recommended to install [Azure Kinect Body Tracking SDK](https://docs.microsoft.com/en-us/azure/Kinect-dk/body-sdk-download) separately. For details see below
* Plenty of powerful samples:
* for .NET Core
@@ -85,15 +84,6 @@ How to use Body Tracking runtime:
See https://github.com/bibigone/k4a.net/releases
-## Roadmap
-
-* More samples (Box-man, 3D view, IMU...)
-* More unit and integration tests
-* Find out how to convert MJPEG -> BGRA faster (implementation in `k4a.dll` is very slow)
-* Test under Linux, samples for Linux (using [Avalonia UI Framework](http://avaloniaui.net/)?)
-* Some hosting for HTML documentation ([DocFX](https://dotnet.github.io/docfx/) + [github.io](https://pages.github.com/)?)
-
-
## How to build
* Open `K4AdotNet.sln` in Visual Studio 2019