diff --git a/Mediapipe.Net.Examples.FaceMesh/DummyResourceManager.cs b/Mediapipe.Net.Examples.FaceMesh/DummyResourceManager.cs
new file mode 100644
index 00000000..78d197fb
--- /dev/null
+++ b/Mediapipe.Net.Examples.FaceMesh/DummyResourceManager.cs
@@ -0,0 +1,26 @@
+// Copyright (c) homuler and The Vignette Authors
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+using System.IO;
+using Mediapipe.Net.Util;
+
+namespace Mediapipe.Net.Examples.FaceMesh
+{
+ public class DummyResourceManager : ResourceManager
+ {
+ public override PathResolver ResolvePath => (path) =>
+ {
+ Console.WriteLine($"PathResolver: (not) resolving path '{path}'");
+ return path;
+ };
+
+ public unsafe override ResourceProvider ProvideResource => (path) =>
+ {
+ Console.WriteLine($"ResourceProvider: providing resource '{path}'");
+ byte[] bytes = File.ReadAllBytes(path);
+ return bytes;
+ };
+ }
+}
diff --git a/Mediapipe.Net.Examples.FaceMesh/Options.cs b/Mediapipe.Net.Examples.FaceMesh/Options.cs
index 1dbe41bb..dd8af3b2 100644
--- a/Mediapipe.Net.Examples.FaceMesh/Options.cs
+++ b/Mediapipe.Net.Examples.FaceMesh/Options.cs
@@ -22,5 +22,8 @@ public class Options
[Option('h', "height", Default = null, HelpText = "The height of the camera input")]
public int? Height { get; set; }
+
+ [Option("use-resource-manager", Default = false, HelpText = "Whether to use a resource manager.")]
+ public bool UseResourceManager { get; set; }
}
}
diff --git a/Mediapipe.Net.Examples.FaceMesh/Program.cs b/Mediapipe.Net.Examples.FaceMesh/Program.cs
index 28fe04b2..81dfdbb9 100644
--- a/Mediapipe.Net.Examples.FaceMesh/Program.cs
+++ b/Mediapipe.Net.Examples.FaceMesh/Program.cs
@@ -10,6 +10,7 @@
using Mediapipe.Net.External;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
+using Mediapipe.Net.Util;
using SeeShark;
using SeeShark.Device;
using SeeShark.FFmpeg;
@@ -21,6 +22,7 @@ public static class Program
private static Camera? camera;
private static FrameConverter? converter;
private static FaceMeshCpuCalculator? calculator;
+ private static ResourceManager? resourceManager;
public static void Main(string[] args)
{
@@ -37,6 +39,8 @@ public static void Main(string[] args)
FFmpegManager.SetupFFmpeg("/usr/lib");
Glog.Initialize("stuff");
+ if (parsed.UseResourceManager)
+ resourceManager = new DummyResourceManager();
// Get a camera device
using (CameraManager manager = new CameraManager())
diff --git a/Mediapipe.Net/Native/SafeNativeMethods/Utils/ResourceUtil.cs b/Mediapipe.Net/Native/SafeNativeMethods/Utils/ResourceUtil.cs
index 324a0790..f83c345e 100644
--- a/Mediapipe.Net/Native/SafeNativeMethods/Utils/ResourceUtil.cs
+++ b/Mediapipe.Net/Native/SafeNativeMethods/Utils/ResourceUtil.cs
@@ -9,9 +9,10 @@ namespace Mediapipe.Net.Native
{
internal unsafe partial class SafeNativeMethods : NativeMethods
{
+ public delegate bool UnsafeResourceProvider(string path, void* output);
+
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
- public static extern void mp__SetCustomGlobalResourceProvider__P(
- ResourceManager.ResourceProvider provider);
+ public static extern void mp__SetCustomGlobalResourceProvider__P(UnsafeResourceProvider provider);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void mp__SetCustomGlobalPathResolver__P(
diff --git a/Mediapipe.Net/Native/UnsafeNativeMethods/External/Stdlib.cs b/Mediapipe.Net/Native/UnsafeNativeMethods/External/Stdlib.cs
index bbebaf59..262f1055 100644
--- a/Mediapipe.Net/Native/UnsafeNativeMethods/External/Stdlib.cs
+++ b/Mediapipe.Net/Native/UnsafeNativeMethods/External/Stdlib.cs
@@ -13,10 +13,10 @@ internal unsafe partial class UnsafeNativeMethods : NativeMethods
#region String
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
- public static extern void std_string__delete(sbyte* str);
+ public static extern void std_string__delete(void* str);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
- public static extern MpReturnCode std_string__PKc_i(byte[] bytes, int size, out sbyte* str);
+ public static extern MpReturnCode std_string__PKc_i(byte[] bytes, int size, out void* str);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void std_string__swap__Rstr(void* src, void* dst);
diff --git a/Mediapipe.Net/Util/ResourceManager.cs b/Mediapipe.Net/Util/ResourceManager.cs
index c305d332..b77d6af4 100644
--- a/Mediapipe.Net/Util/ResourceManager.cs
+++ b/Mediapipe.Net/Util/ResourceManager.cs
@@ -3,14 +3,13 @@
// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
using System;
-using System.Collections;
-using System.IO;
+using Mediapipe.Net.External;
using Mediapipe.Net.Native;
namespace Mediapipe.Net.Util
{
///
- /// Class to manage assets that MediaPipe accesses.
+ /// Class to manage MediaPipe resources, such as `.tflite` and `.pbtxt` files that it requests.
///
///
/// There must not be more than one instance at the same time.
@@ -18,8 +17,19 @@ namespace Mediapipe.Net.Util
public unsafe abstract class ResourceManager
{
public delegate string PathResolver(string path);
+
+ ///
+ /// Resolves a path to a resource name.
+ /// If the resource name returned is different from the path, the delegate will receive the resource name instead of the file path.
+ ///
public abstract PathResolver ResolvePath { get; }
- public delegate bool ResourceProvider(string path, void* output);
+
+ ///
+ /// Reads a resource that MediaPipe requests.
+ ///
+ /// File path or name of the resource.
+ /// Content of the MediaPipe resource as a byte array.
+ public delegate byte[] ResourceProvider(string path);
public abstract ResourceProvider ProvideResource { get; }
private static readonly object initLock = new object();
@@ -33,42 +43,27 @@ public ResourceManager()
throw new InvalidOperationException("ResourceManager can be initialized only once");
SafeNativeMethods.mp__SetCustomGlobalPathResolver__P(ResolvePath);
- SafeNativeMethods.mp__SetCustomGlobalResourceProvider__P(ProvideResource);
+ SafeNativeMethods.mp__SetCustomGlobalResourceProvider__P(provideResource);
isInitialized = true;
}
}
- /// Asset name
- ///
- /// Returns true if is already prepared (saved locally on the device).
- ///
- public abstract bool IsPrepared(string name);
-
- ///
- /// Saves as asynchronously.
- ///
- ///
- /// Specifies whether will be overwritten if it already exists.
- ///
- public abstract IEnumerator PrepareAssetAsync(string name, string uniqueKey, bool overwrite = true);
-
- public IEnumerator PrepareAssetAsync(string name, bool overwrite = true)
- => PrepareAssetAsync(name, name, overwrite);
-
- protected static string GetAssetNameFromPath(string assetPath)
+ private bool provideResource(string path, void* output)
{
- var assetName = Path.GetFileNameWithoutExtension(assetPath);
- var extension = Path.GetExtension(assetPath);
+ try
+ {
+ byte[] bytes = ProvideResource(path);
+
+ StdString strOutput = new StdString(output, isOwner: false);
+ StdString strSpan = new StdString(bytes);
+ strOutput.Swap(strSpan);
- switch (extension)
+ return true;
+ }
+ catch (Exception ex)
{
- case ".binarypb":
- case ".tflite":
- return $"{assetName}.bytes";
- case ".pbtxt":
- return $"{assetName}.txt";
- default:
- return $"{assetName}{extension}";
+ Glog.Log(Glog.Severity.Error, $"Error while trying to provide resource '{path}': {ex}");
+ return false;
}
}
}