From d03895d1e63c1f4e60c4e080b8cd89fbd9a3e797 Mon Sep 17 00:00:00 2001 From: Junrou Nishida Date: Mon, 4 Apr 2022 19:24:37 +0900 Subject: [PATCH] fix: check Packet types at compile-time more properly (#509) * fix!(plugin): default constructors of Packet classes cause memory leak * test Packet#At --- .../Runtime/Scripts/Core/MpResourceHandle.cs | 21 +++++- .../Scripts/Framework/CalculatorGraph.cs | 6 +- .../Framework/Packet/Anchor3dVectorPacket.cs | 11 ++- .../Scripts/Framework/Packet/BoolPacket.cs | 10 ++- .../Packet/ClassificationListPacket.cs | 11 ++- .../Packet/ClassificationListVectorPacket.cs | 11 ++- .../Framework/Packet/DetectionPacket.cs | 11 ++- .../Framework/Packet/DetectionVectorPacket.cs | 11 ++- .../Framework/Packet/FaceGeometryPacket.cs | 11 ++- .../Packet/FaceGeometryVectorPacket.cs | 11 ++- .../Framework/Packet/FloatArrayPacket.cs | 10 ++- .../Scripts/Framework/Packet/FloatPacket.cs | 10 ++- .../Framework/Packet/FrameAnnotationPacket.cs | 11 ++- .../Framework/Packet/GpuBufferPacket.cs | 11 ++- .../Framework/Packet/ImageFramePacket.cs | 10 ++- .../Scripts/Framework/Packet/IntPacket.cs | 10 ++- .../Framework/Packet/LandmarkListPacket.cs | 11 ++- .../Packet/LandmarkListVectorPacket.cs | 11 ++- .../Packet/NormalizedLandmarkListPacket.cs | 11 ++- .../NormalizedLandmarkListVectorPacket.cs | 11 ++- .../Framework/Packet/NormalizedRectPacket.cs | 11 ++- .../Packet/NormalizedRectVectorPacket.cs | 11 ++- .../Scripts/Framework/Packet/Packet.cs | 69 ++++++++++++++----- .../Scripts/Framework/Packet/RectPacket.cs | 11 ++- .../Framework/Packet/RectVectorPacket.cs | 11 ++- .../Scripts/Framework/Packet/SidePacket.cs | 11 +-- .../Scripts/Framework/Packet/StringPacket.cs | 10 ++- .../Packet/TimedModelMatrixProtoListPacket.cs | 11 ++- .../Framework/Packet/BoolPacketTest.cs | 22 ++++++ .../Framework/Packet/FloatArrayPacketTest.cs | 23 +++++++ .../Framework/Packet/FloatPacketTest.cs | 22 ++++++ .../Framework/Packet/ImageFramePacketTest.cs | 22 ++++++ .../EditMode/Framework/Packet/PacketTest.cs | 24 ------- .../Framework/Packet/SidePacketTest.cs | 8 +-- .../Framework/Packet/StringPacketTest.cs | 23 +++++++ 35 files changed, 431 insertions(+), 78 deletions(-) diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Core/MpResourceHandle.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Core/MpResourceHandle.cs index f67e71310..e8d29fcc4 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Core/MpResourceHandle.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Core/MpResourceHandle.cs @@ -10,7 +10,19 @@ namespace Mediapipe { public abstract class MpResourceHandle : DisposableObject, IMpResourceHandle { - protected IntPtr ptr; + private IntPtr _ptr = IntPtr.Zero; + protected IntPtr ptr + { + get => _ptr; + set + { + if (value != IntPtr.Zero && OwnsResource()) + { + throw new InvalidOperationException($"This object owns another resource"); + } + _ptr = value; + } + } protected MpResourceHandle(bool isOwner = true) : this(IntPtr.Zero, isOwner) { } @@ -40,7 +52,7 @@ public void ReleaseMpResource() public bool OwnsResource() { - return isOwner && ptr != IntPtr.Zero; + return isOwner && IsResourcePresent(); } #endregion @@ -80,5 +92,10 @@ protected string MarshalStringFromNative(StringOutFunc f) return str; } + + protected bool IsResourcePresent() + { + return ptr != IntPtr.Zero; + } } } diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/CalculatorGraph.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/CalculatorGraph.cs index 25b20120a..5ae904a10 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/CalculatorGraph.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/CalculatorGraph.cs @@ -79,14 +79,14 @@ public Status ObserveOutputStream(string streamName, NativePacketCallback native return new Status(statusPtr); } - public Status ObserveOutputStream(string streamName, PacketCallback packetCallback, bool observeTimestampBounds, out GCHandle callbackHandle) where TPacket : Packet + public Status ObserveOutputStream(string streamName, PacketCallback packetCallback, bool observeTimestampBounds, out GCHandle callbackHandle) where TPacket : Packet, new() { NativePacketCallback nativePacketCallback = (IntPtr _, IntPtr packetPtr) => { Status status = null; try { - var packet = (TPacket)Activator.CreateInstance(typeof(TPacket), packetPtr, false); + var packet = Packet.Create(packetPtr, false); status = packetCallback(packet); } catch (Exception e) @@ -100,7 +100,7 @@ public Status ObserveOutputStream(string streamName, PacketCall return ObserveOutputStream(streamName, nativePacketCallback, observeTimestampBounds); } - public Status ObserveOutputStream(string streamName, PacketCallback packetCallback, out GCHandle callbackHandle) where TPacket : Packet + public Status ObserveOutputStream(string streamName, PacketCallback packetCallback, out GCHandle callbackHandle) where TPacket : Packet, new() { return ObserveOutputStream(streamName, packetCallback, false, out callbackHandle); } diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Anchor3dVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Anchor3dVectorPacket.cs index 1e44f3246..d25eeb4d9 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Anchor3dVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Anchor3dVectorPacket.cs @@ -11,7 +11,11 @@ namespace Mediapipe { public class Anchor3dVectorPacket : Packet> { - public Anchor3dVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public Anchor3dVectorPacket() : base(true) { } + public Anchor3dVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } public Anchor3dVectorPacket(Anchor3d[] value) : base() @@ -27,6 +31,11 @@ public Anchor3dVectorPacket(Anchor3d[] value, Timestamp timestamp) : base() this.ptr = ptr; } + public Anchor3dVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetAnchor3dVector(mpPtr, out var anchorVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/BoolPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/BoolPacket.cs index 9537e4a89..9e08f637b 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/BoolPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/BoolPacket.cs @@ -10,7 +10,10 @@ namespace Mediapipe { public class BoolPacket : Packet { - public BoolPacket() : base() { } + /// + /// Creates an empty instance. + /// + public BoolPacket() : base(true) { } public BoolPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } @@ -27,6 +30,11 @@ public BoolPacket(bool value, Timestamp timestamp) : base() this.ptr = ptr; } + public BoolPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override bool Get() { UnsafeNativeMethods.mp_Packet__GetBool(mpPtr, out var value).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListPacket.cs index 4118fee27..4982ba170 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class ClassificationListPacket : Packet { - public ClassificationListPacket() : base() { } + /// + /// Creates an empty instance. + /// + public ClassificationListPacket() : base(true) { } + public ClassificationListPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public ClassificationListPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override ClassificationList Get() { UnsafeNativeMethods.mp_Packet__GetClassificationList(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListVectorPacket.cs index 09949b60c..1c051d5d2 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ClassificationListVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class ClassificationListVectorPacket : Packet> { - public ClassificationListVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public ClassificationListVectorPacket() : base(true) { } + public ClassificationListVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public ClassificationListVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetClassificationListVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionPacket.cs index 2e547fccf..b0a915a2d 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class DetectionPacket : Packet { - public DetectionPacket() : base() { } + /// + /// Creates an empty instance. + /// + public DetectionPacket() : base(true) { } + public DetectionPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public DetectionPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override Detection Get() { UnsafeNativeMethods.mp_Packet__GetDetection(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionVectorPacket.cs index 24a420507..f2f43750b 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/DetectionVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class DetectionVectorPacket : Packet> { - public DetectionVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public DetectionVectorPacket() : base(true) { } + public DetectionVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public DetectionVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetDetectionVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryPacket.cs index ff51548b9..ddd65db59 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class FaceGeometryPacket : Packet { - public FaceGeometryPacket() : base() { } + /// + /// Creates an empty instance. + /// + public FaceGeometryPacket() : base(true) { } + public FaceGeometryPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public FaceGeometryPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override FaceGeometry.FaceGeometry Get() { UnsafeNativeMethods.mp_Packet__GetFaceGeometry(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryVectorPacket.cs index 3e1acee62..529d63347 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FaceGeometryVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class FaceGeometryVectorPacket : Packet> { - public FaceGeometryVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public FaceGeometryVectorPacket() : base(true) { } + public FaceGeometryVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public FaceGeometryVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetFaceGeometryVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatArrayPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatArrayPacket.cs index 5d203e5ac..18dbcca5e 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatArrayPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatArrayPacket.cs @@ -26,7 +26,10 @@ public int length } } - public FloatArrayPacket() : base() { } + /// + /// Creates an empty instance. + /// + public FloatArrayPacket() : base(true) { } public FloatArrayPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } @@ -45,6 +48,11 @@ public FloatArrayPacket(float[] value, Timestamp timestamp) : base() length = value.Length; } + public FloatArrayPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override float[] Get() { if (length < 0) diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatPacket.cs index 6aec47b1c..18f3aa026 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FloatPacket.cs @@ -10,7 +10,10 @@ namespace Mediapipe { public class FloatPacket : Packet { - public FloatPacket() : base() { } + /// + /// Creates an empty instance. + /// + public FloatPacket() : base(true) { } public FloatPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } @@ -27,6 +30,11 @@ public FloatPacket(float value, Timestamp timestamp) : base() this.ptr = ptr; } + public FloatPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override float Get() { UnsafeNativeMethods.mp_Packet__GetFloat(mpPtr, out var value).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FrameAnnotationPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FrameAnnotationPacket.cs index 1c1c3c315..7821825c3 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FrameAnnotationPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/FrameAnnotationPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class FrameAnnotationPacket : Packet { - public FrameAnnotationPacket() : base() { } + /// + /// Creates an empty instance. + /// + public FrameAnnotationPacket() : base(true) { } + public FrameAnnotationPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public FrameAnnotationPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override FrameAnnotation Get() { UnsafeNativeMethods.mp_Packet__GetFrameAnnotation(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/GpuBufferPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/GpuBufferPacket.cs index 9f3a63c5d..c578f99fc 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/GpuBufferPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/GpuBufferPacket.cs @@ -10,7 +10,11 @@ namespace Mediapipe { public class GpuBufferPacket : Packet { - public GpuBufferPacket() : base() { } + /// + /// Creates an empty instance. + /// + public GpuBufferPacket() : base(true) { } + public GpuBufferPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } public GpuBufferPacket(GpuBuffer gpuBuffer) : base() @@ -30,6 +34,11 @@ public GpuBufferPacket(GpuBuffer gpuBuffer, Timestamp timestamp) this.ptr = ptr; } + public GpuBufferPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override GpuBuffer Get() { UnsafeNativeMethods.mp_Packet__GetGpuBuffer(mpPtr, out var gpuBufferPtr).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ImageFramePacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ImageFramePacket.cs index 536d0ccba..69ce9e4aa 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ImageFramePacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/ImageFramePacket.cs @@ -10,7 +10,10 @@ namespace Mediapipe { public class ImageFramePacket : Packet { - public ImageFramePacket() : base() { } + /// + /// Creates an empty instance. + /// + public ImageFramePacket() : base(true) { } public ImageFramePacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } @@ -31,6 +34,11 @@ public ImageFramePacket(ImageFrame imageFrame, Timestamp timestamp) : base() this.ptr = ptr; } + public ImageFramePacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override ImageFrame Get() { UnsafeNativeMethods.mp_Packet__GetImageFrame(mpPtr, out var imageFramePtr).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/IntPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/IntPacket.cs index ce8ca2dcc..df703144b 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/IntPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/IntPacket.cs @@ -10,7 +10,10 @@ namespace Mediapipe { public class IntPacket : Packet { - public IntPacket() : base() { } + /// + /// Creates an empty instance. + /// + public IntPacket() : base(true) { } public IntPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } @@ -27,6 +30,11 @@ public IntPacket(int value, Timestamp timestamp) : base() this.ptr = ptr; } + public IntPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override int Get() { UnsafeNativeMethods.mp_Packet__GetInt(mpPtr, out var value).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListPacket.cs index 453053b55..39d52200e 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class LandmarkListPacket : Packet { - public LandmarkListPacket() : base() { } + /// + /// Creates an empty instance. + /// + public LandmarkListPacket() : base(true) { } + public LandmarkListPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public LandmarkListPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override LandmarkList Get() { UnsafeNativeMethods.mp_Packet__GetLandmarkList(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListVectorPacket.cs index 16696aebd..49b92f726 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/LandmarkListVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class LandmarkListVectorPacket : Packet> { - public LandmarkListVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public LandmarkListVectorPacket() : base(true) { } + public LandmarkListVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public LandmarkListVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetLandmarkListVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListPacket.cs index 1de614a03..10048e8e5 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class NormalizedLandmarkListPacket : Packet { - public NormalizedLandmarkListPacket() : base() { } + /// + /// Creates an empty instance. + /// + public NormalizedLandmarkListPacket() : base(true) { } + public NormalizedLandmarkListPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public NormalizedLandmarkListPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override NormalizedLandmarkList Get() { UnsafeNativeMethods.mp_Packet__GetNormalizedLandmarkList(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListVectorPacket.cs index c49471f07..1e643003f 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedLandmarkListVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class NormalizedLandmarkListVectorPacket : Packet> { - public NormalizedLandmarkListVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public NormalizedLandmarkListVectorPacket() : base(true) { } + public NormalizedLandmarkListVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public NormalizedLandmarkListVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetNormalizedLandmarkListVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectPacket.cs index 1062d360e..56647559e 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class NormalizedRectPacket : Packet { - public NormalizedRectPacket() : base() { } + /// + /// Creates an empty instance. + /// + public NormalizedRectPacket() : base(true) { } + public NormalizedRectPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public NormalizedRectPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override NormalizedRect Get() { UnsafeNativeMethods.mp_Packet__GetNormalizedRect(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectVectorPacket.cs index 56edcbcd9..dd5f1d896 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/NormalizedRectVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class NormalizedRectVectorPacket : Packet> { - public NormalizedRectVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public NormalizedRectVectorPacket() : base(true) { } + public NormalizedRectVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public NormalizedRectVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetNormalizedRectVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Packet.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Packet.cs index e9a231f64..eb110da71 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Packet.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/Packet.cs @@ -8,31 +8,53 @@ namespace Mediapipe { - public abstract class Packet : MpResourceHandle + public abstract class Packet : MpResourceHandle { - public Packet() : base() + /// + /// The native resource won't be initialized. + /// + protected Packet() : base() { } + + /// + /// If is set to false, the native resource won't be initialized. + /// + protected Packet(bool isOwner) : base(isOwner) { - UnsafeNativeMethods.mp_Packet__(out var ptr).Assert(); - this.ptr = ptr; + if (isOwner) + { + UnsafeNativeMethods.mp_Packet__(out var ptr).Assert(); + this.ptr = ptr; + } } - public Packet(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + protected Packet(IntPtr ptr, bool isOwner) : base(ptr, isOwner) { } - /// Thrown when the value is not set - public abstract T Get(); - - public abstract StatusOr Consume(); - - /// To avoid copying the value, instantiate the packet with timestamp - /// New packet with the given timestamp and the copied value - public Packet At(Timestamp timestamp) + /// + /// Creates a read-write instance. + /// + /// + /// This is a slow operation that makes use of internally, so you should avoid calling it in a loop.
+ /// If you need to call it in a loop and is set to false, call instead. + ///
+ public static TPacket Create(IntPtr packetPtr, bool isOwner) where TPacket : Packet, new() { - UnsafeNativeMethods.mp_Packet__At__Rt(mpPtr, timestamp.mpPtr, out var packetPtr).Assert(); + return (TPacket)Activator.CreateInstance(typeof(TPacket), packetPtr, isOwner); + } - GC.KeepAlive(timestamp); - return (Packet)Activator.CreateInstance(GetType(), packetPtr, true); + public void SwitchNativePtr(IntPtr packetPtr) + { + if (isOwner) + { + throw new InvalidOperationException("This operation is permitted only when the packet instance is for reference"); + } + ptr = packetPtr; } + /// Thrown when the value is not set + public abstract TValue Get(); + + public abstract StatusOr Consume(); + public bool IsEmpty() { return SafeNativeMethods.mp_Packet__IsEmpty(mpPtr); @@ -81,5 +103,20 @@ protected override void DeleteMpPtr() { UnsafeNativeMethods.mp_Packet__delete(ptr); } + + /// + /// This method will copy the value and create another packet internally. + /// To avoid copying the value, it's preferable to instantiate the packet with timestamp in the first place. + /// + /// New packet with the given timestamp and the copied value + protected TPacket At(Timestamp timestamp) where TPacket : Packet, new() + { + UnsafeNativeMethods.mp_Packet__At__Rt(mpPtr, timestamp.mpPtr, out var packetPtr).Assert(); + GC.KeepAlive(timestamp); + + var packet = Create(packetPtr, true); + Dispose(); + return packet; + } } } diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectPacket.cs index 359d53d2a..febbbca49 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class RectPacket : Packet { - public RectPacket() : base() { } + /// + /// Creates an empty instance. + /// + public RectPacket() : base(true) { } + public RectPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public RectPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override Rect Get() { UnsafeNativeMethods.mp_Packet__GetRect(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectVectorPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectVectorPacket.cs index b35f0abf2..1e727ebd7 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectVectorPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/RectVectorPacket.cs @@ -11,9 +11,18 @@ namespace Mediapipe { public class RectVectorPacket : Packet> { - public RectVectorPacket() : base() { } + /// + /// Creates an empty instance. + /// + public RectVectorPacket() : base(true) { } + public RectVectorPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public RectVectorPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override List Get() { UnsafeNativeMethods.mp_Packet__GetRectVector(mpPtr, out var serializedProtoVector).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/SidePacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/SidePacket.cs index ef289f767..aa10927a6 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/SidePacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/SidePacket.cs @@ -23,9 +23,11 @@ protected override void DeleteMpPtr() public int size => SafeNativeMethods.mp_SidePacket__size(mpPtr); - /// TODO: force T to be Packet - /// Make sure that the type of the returned packet value is correct - public T At(string key) + /// + /// This method cannot verify that the packet type corresponding to the is indeed a , + /// so you must make sure by youreself that it is. + /// + public TPacket At(string key) where TPacket : Packet, new() { UnsafeNativeMethods.mp_SidePacket__at__PKc(mpPtr, key, out var packetPtr).Assert(); @@ -33,9 +35,8 @@ public T At(string key) { return default; // null } - GC.KeepAlive(this); - return (T)Activator.CreateInstance(typeof(T), packetPtr, true); + return Packet.Create(packetPtr, true); } public void Emplace(string key, Packet packet) diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/StringPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/StringPacket.cs index c19a825e9..e7d879e4b 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/StringPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/StringPacket.cs @@ -11,7 +11,10 @@ namespace Mediapipe { public class StringPacket : Packet { - public StringPacket() : base() { } + /// + /// Creates an empty instance. + /// + public StringPacket() : base(true) { } public StringPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } @@ -41,6 +44,11 @@ public StringPacket(byte[] bytes, Timestamp timestamp) : base() this.ptr = ptr; } + public StringPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override string Get() { return MarshalStringFromNative(UnsafeNativeMethods.mp_Packet__GetString); diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/TimedModelMatrixProtoListPacket.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/TimedModelMatrixProtoListPacket.cs index 7d128d19c..aafeac1a7 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/TimedModelMatrixProtoListPacket.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Framework/Packet/TimedModelMatrixProtoListPacket.cs @@ -10,9 +10,18 @@ namespace Mediapipe { public class TimedModelMatrixProtoListPacket : Packet { - public TimedModelMatrixProtoListPacket() : base() { } + /// + /// Creates an empty instance. + /// + public TimedModelMatrixProtoListPacket() : base(true) { } + public TimedModelMatrixProtoListPacket(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { } + public TimedModelMatrixProtoListPacket At(Timestamp timestamp) + { + return At(timestamp); + } + public override TimedModelMatrixProtoList Get() { UnsafeNativeMethods.mp_Packet__GetTimedModelMatrixProtoList(mpPtr, out var serializedProto).Assert(); diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/BoolPacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/BoolPacketTest.cs index 59fd392b4..c9e20015e 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/BoolPacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/BoolPacketTest.cs @@ -84,6 +84,28 @@ public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed() } #endregion + #region #At + [Test] + public void At_ShouldReturnNewPacketWithTimestamp() + { + using (var timestamp = new Timestamp(1)) + { + var packet = new BoolPacket(true).At(timestamp); + Assert.True(packet.Get()); + Assert.AreEqual(packet.Timestamp(), timestamp); + + using (var newTimestamp = new Timestamp(2)) + { + var newPacket = packet.At(newTimestamp); + Assert.True(newPacket.Get()); + Assert.AreEqual(newPacket.Timestamp(), newTimestamp); + } + + Assert.True(packet.isDisposed); + } + } + #endregion + #region #Consume [Test] public void Consume_ShouldThrowNotSupportedException() diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatArrayPacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatArrayPacketTest.cs index 7545d85ad..122f9631d 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatArrayPacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatArrayPacketTest.cs @@ -87,6 +87,29 @@ public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed() } #endregion + #region #At + [Test] + public void At_ShouldReturnNewPacketWithTimestamp() + { + using (var timestamp = new Timestamp(1)) + { + float[] array = { 0.0f }; + var packet = new FloatArrayPacket(array).At(timestamp); + Assert.AreEqual(packet.Get(), array); + Assert.AreEqual(packet.Timestamp(), timestamp); + + using (var newTimestamp = new Timestamp(2)) + { + var newPacket = packet.At(newTimestamp); + Assert.AreEqual(newPacket.Get(), array); + Assert.AreEqual(newPacket.Timestamp(), newTimestamp); + } + + Assert.True(packet.isDisposed); + } + } + #endregion + #region #Consume [Test] public void Consume_ShouldThrowNotSupportedException() diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatPacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatPacketTest.cs index 598562fb3..6d36e343f 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatPacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/FloatPacketTest.cs @@ -72,6 +72,28 @@ public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed() } #endregion + #region #At + [Test] + public void At_ShouldReturnNewPacketWithTimestamp() + { + using (var timestamp = new Timestamp(1)) + { + var packet = new FloatPacket(0).At(timestamp); + Assert.AreEqual(packet.Get(), 0.0f); + Assert.AreEqual(packet.Timestamp(), timestamp); + + using (var newTimestamp = new Timestamp(2)) + { + var newPacket = packet.At(newTimestamp); + Assert.AreEqual(newPacket.Get(), 0.0f); + Assert.AreEqual(newPacket.Timestamp(), newTimestamp); + } + + Assert.True(packet.isDisposed); + } + } + #endregion + #region #Consume [Test] public void Consume_ShouldThrowNotSupportedException() diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/ImageFramePacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/ImageFramePacketTest.cs index 225062923..fcc5419e2 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/ImageFramePacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/ImageFramePacketTest.cs @@ -96,6 +96,28 @@ public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed() } #endregion + #region #At + [Test] + public void At_ShouldReturnNewPacketWithTimestamp() + { + using (var timestamp = new Timestamp(1)) + { + var packet = new ImageFramePacket(new ImageFrame(ImageFormat.Format.SRGBA, 10, 10)).At(timestamp); + Assert.AreEqual(packet.Get().Width(), 10); + Assert.AreEqual(packet.Timestamp(), timestamp); + + using (var newTimestamp = new Timestamp(2)) + { + var newPacket = packet.At(newTimestamp); + Assert.AreEqual(newPacket.Get().Width(), 10); + Assert.AreEqual(newPacket.Timestamp(), newTimestamp); + } + + Assert.True(packet.isDisposed); + } + } + #endregion + #region #Get [Test, SignalAbort] public void Get_ShouldThrowMediaPipeException_When_DataIsEmpty() diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/PacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/PacketTest.cs index 3b0b440c2..b0e3547f7 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/PacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/PacketTest.cs @@ -11,30 +11,6 @@ namespace Tests { public class PacketTest { - #region #At - [Test] - public void At_ShouldReturnNewPacketWithTimestamp() - { - using (var timestamp = new Timestamp(1)) - { - var packet = new BoolPacket(true).At(timestamp); - Assert.True(packet.Get()); - Assert.AreEqual(packet.Timestamp(), timestamp); - - using (var newTimestamp = new Timestamp(2)) - { - var newPacket = packet.At(newTimestamp); - Assert.IsInstanceOf(newPacket); - Assert.True(newPacket.Get()); - Assert.AreEqual(newPacket.Timestamp(), newTimestamp); - } - - Assert.True(packet.Get()); - Assert.AreEqual(packet.Timestamp(), timestamp); - } - } - #endregion - #region #DebugString [Test] public void DebugString_ShouldReturnDebugString_When_InstantiatedWithDefaultConstructor() diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/SidePacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/SidePacketTest.cs index f200a323e..2255dc910 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/SidePacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/SidePacketTest.cs @@ -45,13 +45,13 @@ public void Emplace_ShouldInsertAndDisposePacket() using (var sidePacket = new SidePacket()) { Assert.AreEqual(sidePacket.size, 0); - Assert.IsNull(sidePacket.At("value")); + Assert.IsNull(sidePacket.At("value")); var flagPacket = new FloatPacket(1.0f); sidePacket.Emplace("value", flagPacket); Assert.AreEqual(sidePacket.size, 1); - Assert.AreEqual(sidePacket.At("value").Get(), 1.0f); + Assert.AreEqual(sidePacket.At("value").Get(), 1.0f); Assert.True(flagPacket.isDisposed); } } @@ -63,11 +63,11 @@ public void Emplace_ShouldIgnoreValue_When_KeyExists() { var oldValuePacket = new FloatPacket(1.0f); sidePacket.Emplace("value", oldValuePacket); - Assert.AreEqual(sidePacket.At("value").Get(), 1.0f); + Assert.AreEqual(sidePacket.At("value").Get(), 1.0f); var newValuePacket = new FloatPacket(2.0f); sidePacket.Emplace("value", newValuePacket); - Assert.AreEqual(sidePacket.At("value").Get(), 1.0f); + Assert.AreEqual(sidePacket.At("value").Get(), 1.0f); } } #endregion diff --git a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/StringPacketTest.cs b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/StringPacketTest.cs index 9d82fdec1..5061b7c05 100644 --- a/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/StringPacketTest.cs +++ b/Packages/com.github.homuler.mediapipe/Tests/EditMode/Framework/Packet/StringPacketTest.cs @@ -99,6 +99,29 @@ public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed() } #endregion + #region #At + [Test] + public void At_ShouldReturnNewPacketWithTimestamp() + { + using (var timestamp = new Timestamp(1)) + { + var str = "str"; + var packet = new StringPacket(str).At(timestamp); + Assert.AreEqual(packet.Get(), str); + Assert.AreEqual(packet.Timestamp(), timestamp); + + using (var newTimestamp = new Timestamp(2)) + { + var newPacket = packet.At(newTimestamp); + Assert.AreEqual(newPacket.Get(), str); + Assert.AreEqual(newPacket.Timestamp(), newTimestamp); + } + + Assert.True(packet.isDisposed); + } + } + #endregion + #region #GetByteArray [Test] public void GetByteArray_ShouldReturnByteArray()