diff --git a/wrappers/csharp/Intel.RealSense/CMakeLists.txt b/wrappers/csharp/Intel.RealSense/CMakeLists.txt
index 822c617cf6..ce5089614a 100644
--- a/wrappers/csharp/Intel.RealSense/CMakeLists.txt
+++ b/wrappers/csharp/Intel.RealSense/CMakeLists.txt
@@ -16,6 +16,7 @@ add_library(${PROJECT_NAME}
StreamProfile.cs
Types.cs
SoftwareDevice.cs
+ Option.cs
.nuget/Intel.RealSense.targets
Properties/AssemblyInfo.cs
@@ -56,4 +57,8 @@ add_dependencies(${PROJECT_NAME} realsense2)
set_target_properties (${PROJECT_NAME} PROPERTIES
FOLDER Wrappers/csharp
-)
\ No newline at end of file
+)
+
+set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_REFERENCES
+ "System"
+)
diff --git a/wrappers/csharp/Intel.RealSense/Device.cs b/wrappers/csharp/Intel.RealSense/Device.cs
index a24aff0964..1da9cb9b50 100644
--- a/wrappers/csharp/Intel.RealSense/Device.cs
+++ b/wrappers/csharp/Intel.RealSense/Device.cs
@@ -110,7 +110,7 @@ internal Device(IntPtr dev)
public class CameraInfos
{
- IntPtr m_device;
+ readonly IntPtr m_device;
public CameraInfos(IntPtr device) { m_device = device; }
public string this[CameraInfo info]
@@ -258,6 +258,12 @@ internal PlaybackDevice(IntPtr dev) : base(dev)
}
+
+ protected override void Dispose(bool disposing)
+ {
+ // Intentionally empty, does not own the native device, only wraps it.
+ }
+
public static PlaybackDevice FromDevice(Device dev)
{
object error;
@@ -346,7 +352,7 @@ public float Speed
public class RecordDevice : Device
{
- IntPtr m_dev;
+ readonly IntPtr m_dev;
public RecordDevice(Device dev, string file) : base(IntPtr.Zero)
{
diff --git a/wrappers/csharp/Intel.RealSense/Frame.cs b/wrappers/csharp/Intel.RealSense/Frame.cs
index e484467a26..6ed2f3fa7f 100644
--- a/wrappers/csharp/Intel.RealSense/Frame.cs
+++ b/wrappers/csharp/Intel.RealSense/Frame.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Intel.RealSense
@@ -6,15 +7,30 @@ namespace Intel.RealSense
public class Frame : IDisposable
{
internal HandleRef m_instance;
+ public static readonly FramePool Pool = new FramePool(ptr => new Frame(ptr));
+
+ public IntPtr NativePtr { get { return m_instance.Handle; } }
public Frame(IntPtr ptr)
{
m_instance = new HandleRef(this, ptr);
- NativeMethods.rs2_keep_frame(m_instance.Handle);
+ }
+
+ internal static Frame CreateFrame(IntPtr ptr)
+ {
+ object error;
+ if (NativeMethods.rs2_is_frame_extendable_to(ptr, Extension.Points, out error) > 0)
+ return Points.Pool.Get(ptr);
+ else if (NativeMethods.rs2_is_frame_extendable_to(ptr, Extension.DepthFrame, out error) > 0)
+ return DepthFrame.Pool.Get(ptr);
+ else if (NativeMethods.rs2_is_frame_extendable_to(ptr, Extension.VideoFrame, out error) > 0)
+ return VideoFrame.Pool.Get(ptr);
+ else
+ return Frame.Pool.Get(ptr);
}
#region IDisposable Support
- private bool disposedValue = false; // To detect redundant calls
+ internal bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
@@ -49,18 +65,28 @@ public void Dispose()
}
#endregion
- public void Release()
+ public virtual void Release()
{
if (m_instance.Handle != IntPtr.Zero)
NativeMethods.rs2_release_frame(m_instance.Handle);
m_instance = new HandleRef(this, IntPtr.Zero);
+ Pool.Release(this);
}
public Frame Clone()
{
object error;
NativeMethods.rs2_frame_add_ref(m_instance.Handle, out error);
- return new Frame(m_instance.Handle);
+ return CreateFrame(m_instance.Handle);
+ }
+
+ public bool IsComposite
+ {
+ get
+ {
+ object error;
+ return NativeMethods.rs2_is_frame_extendable_to(m_instance.Handle, Extension.CompositeFrame, out error) > 0;
+ }
}
public IntPtr Data
@@ -77,7 +103,7 @@ public StreamProfile Profile
get
{
object error;
- return new StreamProfile(NativeMethods.rs2_get_frame_stream_profile(m_instance.Handle, out error));
+ return StreamProfile.Pool.Get(NativeMethods.rs2_get_frame_stream_profile(m_instance.Handle, out error));
}
}
@@ -115,6 +141,8 @@ public TimestampDomain TimestampDomain
public class VideoFrame : Frame
{
+ public static readonly new FramePool Pool = new FramePool(ptr => new VideoFrame(ptr));
+
public VideoFrame(IntPtr ptr) : base(ptr)
{
}
@@ -164,26 +192,69 @@ public int BitsPerPixel
///
///
///
- //public void CopyTo(out T[] array)
public void CopyTo(T[] array)
{
if (array == null)
- throw new ArgumentNullException("array");
+ throw new ArgumentNullException(nameof(array));
+ var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+ try
+ {
+ //System.Diagnostics.Debug.Assert((array.Length * Marshal.SizeOf(typeof(T))) == (Stride * Height));
+ CopyTo(handle.AddrOfPinnedObject());
+ }
+ finally
+ {
+ handle.Free();
+ }
+ }
+
+ public void CopyTo(IntPtr ptr)
+ {
+ //System.Diagnostics.Debug.Assert(ptr != IntPtr.Zero);
+ NativeMethods.memcpy(ptr, Data, Stride * Height);
+ }
+
+ ///
+ /// Copy from data from managed array
+ ///
+ ///
+ ///
+ public void CopyFrom(T[] array)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
try
{
//System.Diagnostics.Debug.Assert((array.Length * Marshal.SizeOf(typeof(T))) == (Stride * Height));
- NativeMethods.memcpy(handle.AddrOfPinnedObject(), Data, Stride * Height);
+ CopyFrom(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
}
+
+ public void CopyFrom(IntPtr ptr)
+ {
+ //System.Diagnostics.Debug.Assert(ptr != IntPtr.Zero);
+ NativeMethods.memcpy(Data, ptr, Stride * Height);
+ }
+
+ public override void Release()
+ {
+ //base.Release();
+ if (m_instance.Handle != IntPtr.Zero)
+ NativeMethods.rs2_release_frame(m_instance.Handle);
+ m_instance = new HandleRef(this, IntPtr.Zero);
+ Pool.Release(this);
+ }
}
public class DepthFrame : VideoFrame
{
+ public static readonly new FramePool Pool = new FramePool(ptr => new DepthFrame(ptr));
+
public DepthFrame(IntPtr ptr) : base(ptr)
{
}
@@ -193,11 +264,22 @@ public float GetDistance(int x, int y)
object error;
return NativeMethods.rs2_depth_frame_get_distance(m_instance.Handle, x, y, out error);
}
+
+ public override void Release()
+ {
+ //base.Release();
+ if (m_instance.Handle != IntPtr.Zero)
+ NativeMethods.rs2_release_frame(m_instance.Handle);
+ m_instance = new HandleRef(this, IntPtr.Zero);
+ Pool.Release(this);
+ }
}
public class Points : Frame
{
+ public static readonly new FramePool Pool = new FramePool(ptr => new Points(ptr));
+
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Vertex
{
@@ -210,6 +292,7 @@ public struct TextureCoordinate
public float u;
public float v;
}
+
public Points(IntPtr ptr) : base(ptr)
{
}
@@ -240,7 +323,7 @@ public IntPtr VertexData
public void CopyTo(Vertex[] array)
{
if (array == null)
- throw new ArgumentNullException("array");
+ throw new ArgumentNullException(nameof(array));
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
try
{
@@ -267,7 +350,7 @@ public IntPtr TextureData
public void CopyTo(TextureCoordinate[] textureArray)
{
if (textureArray == null)
- throw new ArgumentNullException("textureArray");
+ throw new ArgumentNullException(nameof(textureArray));
var handle = GCHandle.Alloc(textureArray, GCHandleType.Pinned);
try
@@ -280,45 +363,49 @@ public void CopyTo(TextureCoordinate[] textureArray)
handle.Free();
}
}
- }
-
-
-
- class FrameMarshaler : ICustomMarshaler
- {
- private static FrameMarshaler Instance;
-
- public static ICustomMarshaler GetInstance(string s)
- {
- if (Instance == null)
- {
- Instance = new FrameMarshaler();
- }
- return Instance;
- }
- public void CleanUpManagedData(object ManagedObj)
+ public override void Release()
{
+ //base.Release();
+ if (m_instance.Handle != IntPtr.Zero)
+ NativeMethods.rs2_release_frame(m_instance.Handle);
+ m_instance = new HandleRef(this, IntPtr.Zero);
+ Pool.Release(this);
}
+ }
- public void CleanUpNativeData(IntPtr pNativeData)
- {
- }
+ public class FramePool where T : Frame
+ {
+ readonly Stack stack = new Stack();
+ readonly object locker = new object();
+ readonly Func factory;
- public int GetNativeDataSize()
+ public FramePool(Func factory)
{
- //return IntPtr.Size;
- return -1;
+ this.factory = factory;
}
- public IntPtr MarshalManagedToNative(object ManagedObj)
+ public T Get(IntPtr ptr)
{
- throw new NotImplementedException();
+
+ lock (locker)
+ {
+ if(stack.Count == 0)
+ return factory(ptr);
+ T f = stack.Pop();
+ f.m_instance = new HandleRef(f, ptr);
+ f.disposedValue = false;
+ //NativeMethods.rs2_keep_frame(ptr);
+ return f;
+ }
}
- public object MarshalNativeToManaged(IntPtr pNativeData)
+ public void Release(T t)
{
- return new Frame(pNativeData);
+ lock (locker)
+ {
+ stack.Push(t);
+ }
}
}
}
diff --git a/wrappers/csharp/Intel.RealSense/FrameQueue.cs b/wrappers/csharp/Intel.RealSense/FrameQueue.cs
index 2581186ec1..bd46378f6f 100644
--- a/wrappers/csharp/Intel.RealSense/FrameQueue.cs
+++ b/wrappers/csharp/Intel.RealSense/FrameQueue.cs
@@ -11,35 +11,37 @@ public class FrameQueue : IDisposable, IEnumerable
{
internal HandleRef m_instance;
- public FrameQueue(int capacity = 10)
+ public FrameQueue(int capacity = 1)
{
object error;
m_instance = new HandleRef(this, NativeMethods.rs2_create_frame_queue(capacity, out error));
}
- public bool PollForFrame(out Frame frame, FramesReleaser releaser = null)
+ public bool PollForFrame(out Frame frame)
{
object error;
- if (NativeMethods.rs2_poll_for_frame(m_instance.Handle, out frame, out error) > 0)
+ IntPtr ptr;
+ if (NativeMethods.rs2_poll_for_frame(m_instance.Handle, out ptr, out error) > 0)
{
- frame = FramesReleaser.ScopedReturn(releaser, FrameSet.CreateFrame(frame.m_instance.Handle));
+ frame = Frame.CreateFrame(ptr);
return true;
}
+ frame = null;
return false;
}
- public Frame WaitForFrame(FramesReleaser releaser = null)
+ public Frame WaitForFrame(uint timeout_ms = 5000)
{
object error;
- var ptr = NativeMethods.rs2_wait_for_frame(m_instance.Handle, 5000, out error);
- return FramesReleaser.ScopedReturn(releaser, FrameSet.CreateFrame(ptr));
+ var ptr = NativeMethods.rs2_wait_for_frame(m_instance.Handle, timeout_ms, out error);
+ return Frame.CreateFrame(ptr);
}
- public FrameSet WaitForFrames(FramesReleaser releaser = null)
+ public FrameSet WaitForFrames(uint timeout_ms = 5000)
{
object error;
- var ptr = NativeMethods.rs2_wait_for_frame(m_instance.Handle, 5000, out error);
- return FramesReleaser.ScopedReturn(releaser, new FrameSet(ptr));
+ var ptr = NativeMethods.rs2_wait_for_frame(m_instance.Handle, timeout_ms, out error);
+ return FrameSet.Pool.Get(ptr);
}
public void Enqueue(Frame f)
diff --git a/wrappers/csharp/Intel.RealSense/FrameSet.cs b/wrappers/csharp/Intel.RealSense/FrameSet.cs
index 5c69e0d464..24cf115263 100644
--- a/wrappers/csharp/Intel.RealSense/FrameSet.cs
+++ b/wrappers/csharp/Intel.RealSense/FrameSet.cs
@@ -5,48 +5,67 @@
namespace Intel.RealSense
{
- public class FrameSet : IDisposable, IEnumerable
+ public class FrameSet : ICompositeDisposable, IEnumerable
{
internal HandleRef m_instance;
- readonly int m_count;
+ internal int m_count;
+ internal static readonly FrameSetPool Pool = new FrameSetPool();
+ internal readonly FrameEnumerator m_enum;
+
+ public IntPtr NativePtr { get { return m_instance.Handle; } }
public Frame AsFrame()
{
object error;
NativeMethods.rs2_frame_add_ref(m_instance.Handle, out error);
- return CreateFrame(m_instance.Handle);
+ return Frame.CreateFrame(m_instance.Handle);
}
- public static FrameSet FromFrame(Frame composite, FramesReleaser releaser = null)
+ public static FrameSet FromFrame(Frame composite)
{
- object error;
- if (NativeMethods.rs2_is_frame_extendable_to(composite.m_instance.Handle,
- Extension.CompositeFrame, out error) > 0)
+ if (composite.IsComposite)
{
+ object error;
NativeMethods.rs2_frame_add_ref(composite.m_instance.Handle, out error);
- return FramesReleaser.ScopedReturn(releaser, new FrameSet(composite.m_instance.Handle));
+ return FrameSet.Pool.Get(composite.m_instance.Handle);
}
- throw new Exception("The frame is a not composite frame");
+ throw new ArgumentException("The frame is a not composite frame", nameof(composite));
}
- internal static Frame CreateFrame(IntPtr ptr)
+ [Obsolete("This method is obsolete. Use DisposeWith method instead")]
+ public static FrameSet FromFrame(Frame composite, FramesReleaser releaser)
{
- object error;
- if (NativeMethods.rs2_is_frame_extendable_to(ptr, Extension.Points, out error) > 0)
- return new Points(ptr);
- else if (NativeMethods.rs2_is_frame_extendable_to(ptr, Extension.DepthFrame, out error) > 0)
- return new DepthFrame(ptr);
- else if (NativeMethods.rs2_is_frame_extendable_to(ptr, Extension.VideoFrame, out error) > 0)
- return new VideoFrame(ptr);
- else
- return new Frame(ptr);
+ return FromFrame(composite).DisposeWith(releaser);
+ }
+
+ public void ForEach(Action action)
+ {
+ for (int i = 0; i < m_count; i++)
+ {
+ using (var frame = this[i])
+ action(frame);
+ }
}
public T FirstOrDefault(Stream stream, Format format = Format.Any) where T : Frame
{
- foreach (Frame frame in this)
+ for (int i = 0; i < m_count; i++)
+ {
+ var frame = this[i];
+ using (var fp = frame.Profile)
+ if (fp.Stream == stream && (format == Format.Any || fp.Format == format))
+ return frame as T;
+ frame.Dispose();
+ }
+ return null;
+ }
+
+ public T FirstOrDefault(Predicate predicate) where T : Frame
+ {
+ for (int i = 0; i < m_count; i++)
{
- if (frame.Profile.Stream == stream && (Format.Any == format || frame.Profile.Format == format))
+ var frame = this[i];
+ if (predicate(frame))
return frame as T;
frame.Dispose();
}
@@ -57,7 +76,7 @@ public DepthFrame DepthFrame
{
get
{
- return FirstOrDefault(Stream.Depth);
+ return FirstOrDefault(Stream.Depth, Format.Z16);
}
}
@@ -69,19 +88,24 @@ public VideoFrame ColorFrame
}
}
- public IEnumerator GetEnumerator()
+ public VideoFrame InfraredFrame
{
- object error;
- for (int i = 0; i < m_count; i++)
+ get
{
- var ptr = NativeMethods.rs2_extract_frame(m_instance.Handle, i, out error);
- yield return CreateFrame(ptr);
+ return FirstOrDefault(Stream.Infrared);
}
}
+ public IEnumerator GetEnumerator()
+ {
+ m_enum.Reset();
+ return m_enum;
+ }
+
IEnumerator IEnumerable.GetEnumerator()
{
- return GetEnumerator();
+ m_enum.Reset();
+ return m_enum;
}
public int Count
@@ -98,7 +122,7 @@ public Frame this[int index]
{
object error;
var ptr = NativeMethods.rs2_extract_frame(m_instance.Handle, index, out error);
- return CreateFrame(ptr);
+ return Frame.CreateFrame(ptr);
}
}
@@ -106,14 +130,24 @@ public Frame this[int index]
{
get
{
- foreach (Frame frame in this)
+ return FirstOrDefault(f =>
{
- var p = frame.Profile;
- if (p.Stream == stream && p.Index == index)
- return frame;
- frame.Dispose();
- }
- return null;
+ using (var p = f.Profile)
+ return p.Stream == stream && p.Index == index;
+ });
+ }
+ }
+
+
+ public Frame this[Stream stream, Format format, int index = 0]
+ {
+ get
+ {
+ return FirstOrDefault(f =>
+ {
+ using (var p = f.Profile)
+ return p.Stream == stream && p.Format == format && p.Index == index;
+ });
}
}
@@ -122,10 +156,11 @@ internal FrameSet(IntPtr ptr)
m_instance = new HandleRef(this, ptr);
object error;
m_count = NativeMethods.rs2_embedded_frames_count(m_instance.Handle, out error);
+ m_enum = new FrameEnumerator(this);
}
#region IDisposable Support
- private bool disposedValue = false; // To detect redundant calls
+ internal bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
@@ -138,7 +173,11 @@ protected virtual void Dispose(bool disposing)
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
+
+ disposables.ForEach(d => d?.Dispose());
+
Release();
+
disposedValue = true;
}
}
@@ -165,43 +204,114 @@ public void Release()
if (m_instance.Handle != IntPtr.Zero)
NativeMethods.rs2_release_frame(m_instance.Handle);
m_instance = new HandleRef(this, IntPtr.Zero);
+ Pool.Release(this);
+ }
+
+ internal readonly List disposables = new List();
+ public void AddDisposable(IDisposable disposable)
+ {
+ disposables.Add(disposable);
}
}
- class FrameSetMarshaler : ICustomMarshaler
- {
- private static FrameSetMarshaler Instance;
+ public static class FrameSetExtensions {
+ public static FrameSet AsFrameSet(this Frame frame)
+ {
+ return FrameSet.FromFrame(frame);
+ }
+ }
- public static ICustomMarshaler GetInstance(string s)
+ public class FrameSetPool
+ {
+ readonly Stack