You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
302 lines
10 KiB
302 lines
10 KiB
// License: Apache 2.0. See LICENSE file in root directory.
|
|
// Copyright(c) 2017 Intel Corporation. All Rights Reserved.
|
|
|
|
namespace Intel.RealSense
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
|
|
// TODO: subclasses - DepthSensor, DepthStereoSensor, PoseSensor...
|
|
public class Sensor : Base.RefCountedPooledObject, IOptions
|
|
{
|
|
protected static Hashtable refCountTable = new Hashtable();
|
|
protected static readonly object tableLock = new object();
|
|
|
|
internal override void Initialize()
|
|
{
|
|
lock (tableLock)
|
|
{
|
|
if (refCountTable.Contains(Handle))
|
|
refCount = refCountTable[Handle] as Base.RefCount;
|
|
else
|
|
{
|
|
refCount = new Base.RefCount();
|
|
refCountTable[Handle] = refCount;
|
|
}
|
|
Retain();
|
|
}
|
|
Info = new InfoCollection(NativeMethods.rs2_supports_sensor_info, NativeMethods.rs2_get_sensor_info, Handle);
|
|
Options = new OptionsList(Handle);
|
|
}
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
private frame_callback m_callback;
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
private FrameQueue m_queue;
|
|
|
|
internal static T Create<T>(IntPtr ptr)
|
|
where T : Sensor
|
|
{
|
|
return ObjectPool.Get<T>(ptr);
|
|
}
|
|
|
|
/// <summary>Returns a strongly-typed clone</summary>
|
|
/// <typeparam name="T"><see cref="Sensor"/> type or subclass</typeparam>
|
|
/// <param name="other"><see cref="Sensor"/> to clone</param>
|
|
/// <returns>an instance of <typeparamref name="T"/></returns>
|
|
public static T Create<T>(Sensor other)
|
|
where T : Sensor
|
|
{
|
|
return ObjectPool.Get<T>(other.Handle);
|
|
}
|
|
|
|
internal Sensor(IntPtr sensor)
|
|
: base(sensor, NativeMethods.rs2_delete_sensor)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (m_instance.IsInvalid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//m_queue.Dispose();
|
|
(Options as OptionsList).Dispose();
|
|
|
|
lock (tableLock)
|
|
{
|
|
IntPtr localHandle = Handle;
|
|
System.Diagnostics.Debug.Assert(refCountTable.Contains(localHandle));
|
|
|
|
base.Dispose(disposing);
|
|
|
|
if (refCount.count == 0)
|
|
{
|
|
refCountTable.Remove(localHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class CameraInfos : IEnumerable<KeyValuePair<CameraInfo, string>>
|
|
{
|
|
private readonly IntPtr m_sensor;
|
|
|
|
public CameraInfos(IntPtr sensor)
|
|
{
|
|
m_sensor = sensor;
|
|
}
|
|
|
|
/// <summary>retrieve sensor specific information, like versions of various internal components</summary>
|
|
/// <param name="info">camera info type to retrieve</param>
|
|
/// <returns>the requested camera info string, in a format specific to the device model</returns>
|
|
public string this[CameraInfo info]
|
|
{
|
|
get
|
|
{
|
|
object err;
|
|
if (NativeMethods.rs2_supports_sensor_info(m_sensor, info, out err) > 0)
|
|
{
|
|
return Marshal.PtrToStringAnsi(NativeMethods.rs2_get_sensor_info(m_sensor, info, out err));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static readonly CameraInfo[] CameraInfoValues = Enum.GetValues(typeof(CameraInfo)) as CameraInfo[];
|
|
|
|
/// <inheritdoc/>
|
|
public IEnumerator<KeyValuePair<CameraInfo, string>> GetEnumerator()
|
|
{
|
|
object error;
|
|
foreach (var key in CameraInfoValues)
|
|
{
|
|
if (NativeMethods.rs2_supports_sensor_info(m_sensor, key, out error) > 0)
|
|
{
|
|
var value = Marshal.PtrToStringAnsi(NativeMethods.rs2_get_sensor_info(m_sensor, key, out error));
|
|
yield return new KeyValuePair<CameraInfo, string>(key, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
|
|
public InfoCollection Info { get; private set; }
|
|
|
|
|
|
/// <inheritdoc/>
|
|
public IOptionsContainer Options { get; private set; }
|
|
|
|
/// <summary>open subdevice for exclusive access, by committing to a configuration</summary>
|
|
/// <param name="profile">stream profile that defines single stream configuration</param>
|
|
public void Open(StreamProfile profile)
|
|
{
|
|
object error;
|
|
NativeMethods.rs2_open(Handle, profile.Handle, out error);
|
|
}
|
|
|
|
/// <summary>open subdevice for exclusive access, by committing to composite configuration, specifying one or more stream profiles</summary>
|
|
/// <remarks>
|
|
/// this method should be used for interdependent streams, such as depth and infrared, that have to be configured together
|
|
/// </remarks>
|
|
/// <param name="profiles">list of stream profiles</param>
|
|
public void Open(params StreamProfile[] profiles)
|
|
{
|
|
object error;
|
|
IntPtr[] handles = new IntPtr[profiles.Length];
|
|
for (int i = 0; i < profiles.Length; i++)
|
|
{
|
|
handles[i] = profiles[i].Handle;
|
|
}
|
|
|
|
NativeMethods.rs2_open_multiple(Handle, handles, profiles.Length, out error);
|
|
}
|
|
|
|
/// <summary>
|
|
/// start streaming from specified configured sensor of specific stream to frame queue
|
|
/// </summary>
|
|
/// <param name="queue">frame-queue to store new frames into</param>
|
|
// TODO: overload with state object and Action<Frame, object> callback to avoid allocations
|
|
public void Start(FrameQueue queue)
|
|
{
|
|
object error;
|
|
NativeMethods.rs2_start_queue(Handle, queue.Handle, out error);
|
|
m_queue = queue;
|
|
m_callback = null;
|
|
}
|
|
|
|
/// <summary>start streaming from specified configured sensor</summary>
|
|
/// <param name="cb">delegate to register as per-frame callback</param>
|
|
// TODO: overload with state object and Action<Frame, object> callback to avoid allocations
|
|
public void Start(FrameCallback cb)
|
|
{
|
|
object error;
|
|
frame_callback cb2 = (IntPtr f, IntPtr u) =>
|
|
{
|
|
using (var frame = Frame.Create(f))
|
|
{
|
|
cb(frame);
|
|
}
|
|
};
|
|
m_callback = cb2;
|
|
m_queue = null;
|
|
NativeMethods.rs2_start(Handle, cb2, IntPtr.Zero, out error);
|
|
}
|
|
|
|
/// <summary>
|
|
/// stops streaming from specified configured device
|
|
/// </summary>
|
|
public void Stop()
|
|
{
|
|
object error;
|
|
NativeMethods.rs2_stop(Handle, out error);
|
|
m_callback = null;
|
|
m_queue = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// close subdevice for exclusive access this method should be used for releasing device resource
|
|
/// </summary>
|
|
public void Close()
|
|
{
|
|
object error;
|
|
NativeMethods.rs2_close(Handle, out error);
|
|
}
|
|
|
|
public bool Is(Extension ext)
|
|
{
|
|
object error;
|
|
return NativeMethods.rs2_is_sensor_extendable_to(Handle, ext, out error) != 0;
|
|
}
|
|
|
|
/// <summary>Returns a strongly-typed clone</summary>
|
|
/// <typeparam name="T"><see cref="Sensor"/> type or subclass</typeparam>
|
|
/// <returns>an instance of <typeparamref name="T"/></returns>
|
|
public T As<T>()
|
|
where T : Sensor
|
|
{
|
|
return Create<T>(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the mapping between the units of the depth image and meters
|
|
/// </summary>
|
|
/// <value>depth in meters corresponding to a depth value of 1</value>
|
|
public float DepthScale
|
|
{
|
|
get
|
|
{
|
|
object error;
|
|
return NativeMethods.rs2_get_depth_scale(Handle, out error);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the active region of interest to be used by auto-exposure algorithm
|
|
/// </summary>
|
|
public AutoExposureROI AutoExposureSettings
|
|
{
|
|
get
|
|
{
|
|
object error;
|
|
if (NativeMethods.rs2_is_sensor_extendable_to(Handle, Extension.Roi, out error) != 0)
|
|
{
|
|
return new AutoExposureROI { m_instance = Handle };
|
|
}
|
|
|
|
// TODO: consider making AutoExposureROI a struct and throwing instead
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the list of supported stream profiles</summary>
|
|
/// <value>list of stream profiles that given subdevice can provide</value>
|
|
public ReadOnlyCollection<StreamProfile> StreamProfiles
|
|
{
|
|
get
|
|
{
|
|
object error;
|
|
using (var pl = new StreamProfileList(NativeMethods.rs2_get_stream_profiles(Handle, out error)))
|
|
{
|
|
var profiles = new StreamProfile[pl.Count];
|
|
pl.CopyTo(profiles, 0);
|
|
return Array.AsReadOnly(profiles);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the list of recommended processing blocks for a specific sensor.</summary>
|
|
/// <remarks>
|
|
/// Order and configuration of the blocks are decided by the sensor
|
|
/// </remarks>
|
|
/// <value>list of supported sensor recommended processing blocks</value>
|
|
public ReadOnlyCollection<ProcessingBlock> ProcessingBlocks
|
|
{
|
|
get
|
|
{
|
|
object error;
|
|
using (var pl = new ProcessingBlockList(NativeMethods.rs2_get_recommended_processing_blocks(Handle, out error)))
|
|
{
|
|
var blocks = new ProcessingBlock[pl.Count];
|
|
pl.CopyTo(blocks, 0);
|
|
return Array.AsReadOnly(blocks);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|