From ec44eb0673ca03f6a3a37ab1acb4ced17af097c7 Mon Sep 17 00:00:00 2001 From: Speykious Date: Fri, 4 Mar 2022 16:38:37 +0100 Subject: [PATCH] Fix deleter (#26) --- Mediapipe.Net/Framework/Format/ImageFrame.cs | 35 +++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/Mediapipe.Net/Framework/Format/ImageFrame.cs b/Mediapipe.Net/Framework/Format/ImageFrame.cs index a3f6cd39..df2c5ec5 100644 --- a/Mediapipe.Net/Framework/Format/ImageFrame.cs +++ b/Mediapipe.Net/Framework/Format/ImageFrame.cs @@ -3,6 +3,7 @@ // MediaPipe.NET is licensed under the MIT License. See LICENSE for details. using System; +using System.Runtime.InteropServices; using Mediapipe.Net.Core; using Mediapipe.Net.Native; @@ -14,6 +15,8 @@ public unsafe class ImageFrame : MpResourceHandle public static readonly uint GlDefaultAlignmentBoundary = 4; public delegate void Deleter(void* ptr); + private readonly Deleter? deleter; + private GCHandle? deleterHandle; public ImageFrame() : base() { @@ -39,35 +42,51 @@ public ImageFrame(ImageFormat format, int width, int height, uint alignmentBound // mediapipe::ImageFormat::Format format, // int width, int height, int width_step, uint8* pixel_data, // Deleter* deleter, mediapipe::ImageFrame** image_frame_out); - unsafe public ImageFrame(ImageFormat format, int width, int height, int widthStep, byte* pixelData) : base() + public unsafe ImageFrame(ImageFormat format, int width, int height, int widthStep, byte* pixelData) : base() { + deleter = new Deleter(releasePixelData); + deleterHandle = GCHandle.Alloc(deleter); + UnsafeNativeMethods.mp_ImageFrame__ui_i_i_i_Pui8_PF( format, width, height, widthStep, pixelData, - releasePixelData, + deleter, out var ptr).Assert(); Ptr = ptr; } public ImageFrame(ImageFormat format, int width, int height, int widthStep, ReadOnlySpan pixelData) - : this(format, width, height, widthStep, spanToBytePtr(pixelData)) { } - - private static byte* spanToBytePtr(ReadOnlySpan span) { - fixed (byte* ptr = span) + deleter = releasePixelData; + deleterHandle = GCHandle.Alloc(deleter); + + fixed (byte* pixelDataPtr = pixelData) { - return ptr; + UnsafeNativeMethods.mp_ImageFrame__ui_i_i_i_Pui8_PF( + format, width, height, widthStep, + pixelDataPtr, + deleter, + out var ptr).Assert(); + Ptr = ptr; } } protected override void DeleteMpPtr() => UnsafeNativeMethods.mp_ImageFrame__delete(Ptr); - // [AOT.MonoPInvokeCallback(typeof(Deleter))] (?) private static void releasePixelData(void* ptr) { // Do nothing (pixelData is moved) } + protected override void DisposeUnmanaged() + { + base.DisposeUnmanaged(); + + // `deleter` must not be garbage collected until unmanaged code calls it. + if (deleterHandle is GCHandle handle && handle.IsAllocated) + handle.Free(); + } + public bool IsEmpty => SafeNativeMethods.mp_ImageFrame__IsEmpty(MpPtr) > 0; public bool IsContiguous => SafeNativeMethods.mp_ImageFrame__IsContiguous(MpPtr) > 0;