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.
337 lines
11 KiB
337 lines
11 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.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
|
|
public class FrameSet : Frame, ICompositeDisposable, IEnumerable<Frame>
|
|
{
|
|
private readonly List<IDisposable> disposables = new List<IDisposable>();
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
private readonly Enumerator enumerator;
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
private int count;
|
|
|
|
/// <summary>
|
|
/// Create a new <see cref="FrameSet"/> from <see cref="Frame"/>
|
|
/// </summary>
|
|
/// <param name="composite">a composite frame</param>
|
|
/// <returns>a new <see cref="FrameSet"/> to be disposed</returns>
|
|
/// <exception cref="ArgumentException">Thrown when frame is not a composite frame</exception>
|
|
public static FrameSet FromFrame(Frame composite)
|
|
{
|
|
if (composite.IsComposite)
|
|
{
|
|
object error;
|
|
NativeMethods.rs2_frame_add_ref(composite.Handle, out error);
|
|
return Create(composite.Handle);
|
|
}
|
|
|
|
throw new ArgumentException("The frame is a not composite frame", nameof(composite));
|
|
}
|
|
|
|
[Obsolete("This method is obsolete. Use DisposeWith method instead")]
|
|
public static FrameSet FromFrame(Frame composite, FramesReleaser releaser)
|
|
{
|
|
return FromFrame(composite).DisposeWith(releaser);
|
|
}
|
|
|
|
internal override void Initialize()
|
|
{
|
|
object error;
|
|
count = NativeMethods.rs2_embedded_frames_count(Handle, out error);
|
|
enumerator.Reset();
|
|
disposables.Clear();
|
|
}
|
|
|
|
internal FrameSet(IntPtr ptr)
|
|
: base(ptr)
|
|
{
|
|
object error;
|
|
count = NativeMethods.rs2_embedded_frames_count(Handle, out error);
|
|
enumerator = new Enumerator(this);
|
|
}
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
public new bool IsComposite => true;
|
|
|
|
/// <summary>
|
|
/// Cast this to a <see cref="Frame"/>
|
|
/// </summary>
|
|
/// <returns>a frame to be disposed</returns>
|
|
public Frame AsFrame()
|
|
{
|
|
object error;
|
|
NativeMethods.rs2_frame_add_ref(Handle, out error);
|
|
return Frame.Create(Handle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invoke the <paramref name="action"/> delegate on each frame in the set
|
|
/// </summary>
|
|
/// <param name="action">Delegate to invoke</param>
|
|
public void ForEach(Action<Frame> action)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
using (var frame = this[i])
|
|
{
|
|
action(frame);
|
|
}
|
|
}
|
|
}
|
|
|
|
public T FirstOrDefault<T>(Stream stream, Format format = Format.Any)
|
|
where T : Frame
|
|
{
|
|
return FirstOrDefault(stream, format)?.Cast<T>();
|
|
}
|
|
|
|
public Frame FirstOrDefault(Stream stream, Format format = Format.Any)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var frame = this[i];
|
|
using (var fp = frame.Profile)
|
|
if (fp.Stream == stream && (format == Format.Any || fp.Format == format))
|
|
{
|
|
return frame;
|
|
}
|
|
|
|
frame.Dispose();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public T FirstOrDefault<T>(Predicate<T> predicate)
|
|
where T : Frame
|
|
{
|
|
object error;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var ptr = NativeMethods.rs2_extract_frame(Handle, i, out error);
|
|
var frame = Frame.Create<T>(ptr);
|
|
if (predicate(frame))
|
|
{
|
|
return frame;
|
|
}
|
|
|
|
frame.Dispose();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve back the first frame of specific stream type, if no frame found, error will be thrown
|
|
/// </summary>
|
|
/// <typeparam name="T"><see cref="Frame"/> type or subclass</typeparam>
|
|
/// <param name="stream">stream type of frame to be retrieved</param>
|
|
/// <param name="format">format type of frame to be retrieved, defaults to <see cref="Format.Any"/></param>
|
|
/// <returns>first found frame with <paramref name="stream"/> type and <paramref name="format"/> type</returns>
|
|
/// <exception cref="ArgumentException">Thrown when requested type not found</exception>
|
|
public T First<T>(Stream stream, Format format = Format.Any)
|
|
where T : Frame
|
|
{
|
|
var f = FirstOrDefault<T>(stream, format);
|
|
if (f == null)
|
|
{
|
|
throw new ArgumentException("Frame of requested stream type was not found!");
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve back the first frame of specific stream type, if no frame found, error will be thrown
|
|
/// </summary>
|
|
/// <param name="stream">stream type of frame to be retrieved</param>
|
|
/// <param name="format">format type of frame to be retrieved, defaults to <see cref="Format.Any"/></param>
|
|
/// <returns>first found frame with <paramref name="stream"/> type and <paramref name="format"/> type</returns>
|
|
/// <exception cref="ArgumentException">Thrown when requested type not found</exception>
|
|
/// <seealso cref="First{T}(Stream, Format)"/>
|
|
public Frame First(Stream stream, Format format = Format.Any) => First<Frame>(stream, format);
|
|
|
|
/// <summary>Gets the first depth frame</summary>
|
|
public DepthFrame DepthFrame => FirstOrDefault<DepthFrame>(Stream.Depth, Format.Z16);
|
|
|
|
/// <summary>Gets the first color frame</summary>
|
|
public VideoFrame ColorFrame => FirstOrDefault<VideoFrame>(Stream.Color);
|
|
|
|
/// <summary>Gets the first infrared frame</summary>
|
|
public VideoFrame InfraredFrame => FirstOrDefault<VideoFrame>(Stream.Infrared);
|
|
|
|
/// <summary>Gets the first fisheye frame</summary>
|
|
public VideoFrame FishEyeFrame => FirstOrDefault<VideoFrame>(Stream.Fisheye);
|
|
|
|
/// <summary>Gets the first pose frame</summary>
|
|
public PoseFrame PoseFrame => FirstOrDefault<PoseFrame>(Stream.Pose);
|
|
|
|
/// <inheritdoc/>
|
|
public IEnumerator<Frame> GetEnumerator()
|
|
{
|
|
enumerator.Reset();
|
|
return enumerator;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
enumerator.Reset();
|
|
return enumerator;
|
|
}
|
|
|
|
/// <summary>Gets the number of frames embedded within a composite frame</summary>
|
|
/// <value>Number of embedded frames</value>
|
|
public int Count => count;
|
|
|
|
/// <summary>Extract frame from within a composite frame</summary>
|
|
/// <param name="index">Index of the frame to extract within the composite frame</param>
|
|
/// <returns>returns reference to a frame existing within the composite frame</returns>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="index"/> is out of range</exception>
|
|
public Frame this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index < count)
|
|
{
|
|
object error;
|
|
var ptr = NativeMethods.rs2_extract_frame(Handle, index, out error);
|
|
return Frame.Create(ptr);
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(index));
|
|
}
|
|
}
|
|
|
|
public Frame this[Stream stream, int index = 0]
|
|
{
|
|
get
|
|
{
|
|
return FirstOrDefault<Frame>(f =>
|
|
{
|
|
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<Frame>(f =>
|
|
{
|
|
using (var p = f.Profile)
|
|
{
|
|
return p.Stream == stream && p.Format == format && p.Index == index;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public static new FrameSet Create(IntPtr ptr)
|
|
{
|
|
return ObjectPool.Get<FrameSet>(ptr);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
disposables.ForEach(d => d?.Dispose());
|
|
disposables.Clear();
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public void AddDisposable(IDisposable disposable)
|
|
{
|
|
if (disposable == this)
|
|
{
|
|
return;
|
|
}
|
|
|
|
disposables.Add(disposable);
|
|
}
|
|
|
|
internal sealed class Enumerator : IEnumerator<Frame>
|
|
{
|
|
private readonly FrameSet fs;
|
|
private Frame current;
|
|
private int index;
|
|
|
|
public Enumerator(FrameSet fs)
|
|
{
|
|
this.fs = fs;
|
|
index = 0;
|
|
current = default(Frame);
|
|
}
|
|
|
|
public Frame Current
|
|
{
|
|
get
|
|
{
|
|
return current;
|
|
}
|
|
}
|
|
|
|
object IEnumerator.Current
|
|
{
|
|
get
|
|
{
|
|
if (index == 0 || index == fs.count + 1)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
return Current;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// Method intentionally left empty.
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
if ((uint)index < (uint)fs.count)
|
|
{
|
|
object error;
|
|
var ptr = NativeMethods.rs2_extract_frame(fs.Handle, index, out error);
|
|
current = Frame.Create(ptr);
|
|
index++;
|
|
return true;
|
|
}
|
|
|
|
index = fs.count + 1;
|
|
current = null;
|
|
return false;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
index = 0;
|
|
current = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class FrameSetExtensions
|
|
{
|
|
public static FrameSet AsFrameSet(this Frame frame)
|
|
{
|
|
return FrameSet.FromFrame(frame);
|
|
}
|
|
}
|
|
}
|