// 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 { private readonly List disposables = new List(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Enumerator enumerator; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private int count; /// /// Create a new from /// /// a composite frame /// a new to be disposed /// Thrown when frame is not a composite frame 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; /// /// Cast this to a /// /// a frame to be disposed public Frame AsFrame() { object error; NativeMethods.rs2_frame_add_ref(Handle, out error); return Frame.Create(Handle); } /// /// Invoke the delegate on each frame in the set /// /// Delegate to invoke public void ForEach(Action action) { for (int i = 0; i < count; i++) { using (var frame = this[i]) { action(frame); } } } public T FirstOrDefault(Stream stream, Format format = Format.Any) where T : Frame { return FirstOrDefault(stream, format)?.Cast(); } 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(Predicate 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(ptr); if (predicate(frame)) { return frame; } frame.Dispose(); } return null; } /// /// Retrieve back the first frame of specific stream type, if no frame found, error will be thrown /// /// type or subclass /// stream type of frame to be retrieved /// format type of frame to be retrieved, defaults to /// first found frame with type and type /// Thrown when requested type not found public T First(Stream stream, Format format = Format.Any) where T : Frame { var f = FirstOrDefault(stream, format); if (f == null) { throw new ArgumentException("Frame of requested stream type was not found!"); } return f; } /// /// Retrieve back the first frame of specific stream type, if no frame found, error will be thrown /// /// stream type of frame to be retrieved /// format type of frame to be retrieved, defaults to /// first found frame with type and type /// Thrown when requested type not found /// public Frame First(Stream stream, Format format = Format.Any) => First(stream, format); /// Gets the first depth frame public DepthFrame DepthFrame => FirstOrDefault(Stream.Depth, Format.Z16); /// Gets the first color frame public VideoFrame ColorFrame => FirstOrDefault(Stream.Color); /// Gets the first infrared frame public VideoFrame InfraredFrame => FirstOrDefault(Stream.Infrared); /// Gets the first fisheye frame public VideoFrame FishEyeFrame => FirstOrDefault(Stream.Fisheye); /// Gets the first pose frame public PoseFrame PoseFrame => FirstOrDefault(Stream.Pose); /// public IEnumerator GetEnumerator() { enumerator.Reset(); return enumerator; } /// IEnumerator IEnumerable.GetEnumerator() { enumerator.Reset(); return enumerator; } /// Gets the number of frames embedded within a composite frame /// Number of embedded frames public int Count => count; /// Extract frame from within a composite frame /// Index of the frame to extract within the composite frame /// returns reference to a frame existing within the composite frame /// Thrown when is out of range 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(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(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(ptr); } protected override void Dispose(bool disposing) { disposables.ForEach(d => d?.Dispose()); disposables.Clear(); base.Dispose(disposing); } /// public void AddDisposable(IDisposable disposable) { if (disposable == this) { return; } disposables.Add(disposable); } internal sealed class Enumerator : IEnumerator { 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); } } }