Huge update to get on par with MediaPipeUnityPlugin (#39)

* Use new MediaPipe packages and update version

* Apply updates from MediaPipeUnityPlugin

All while keeping C pointers like `void*` instead of `IntPtr`
and various other practices.

* Add VSCode task to debug tests

* Fix unset freeHGlobal delegate

This can happen because the static code of the NativeMethods class
could have not run, for some reason...

* Fix all examples

* Fix import reordering
This commit is contained in:
Speykious
2022-07-30 08:37:17 +02:00
committed by GitHub
parent d562895694
commit b5f3b54b15
67 changed files with 1951 additions and 483 deletions

27
.vscode/tasks.json vendored
View File

@ -12,6 +12,31 @@
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
},
{
"label": ".NET Core Test with debugger (that one crashing test)",
"type": "process",
"isBackground": true,
"command": "dotnet",
"args": [
"test",
"--logger",
"console;verbosity=detailed"
],
"options": {
"cwd": "${workspaceFolder}/Mediapipe.Net.Tests",
"env": {
"VSTEST_HOST_DEBUG": "1"
},
},
"group": "test",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
},
"problemMatcher": []
},
]
}

View File

@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mediapipe.Net.Examples.Pose
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mediapipe.Net.Examples.OsuFrameworkVisualTests", "Mediapipe.Net.Examples.OsuFrameworkVisualTests\Mediapipe.Net.Examples.OsuFrameworkVisualTests.csproj", "{34F0FFCF-F81E-4556-BC74-ED9AEBA7F731}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mediapipe.Net.Examples.HandsGpu", "Mediapipe.Net.Examples.HandsGpu\Mediapipe.Net.Examples.HandsGpu.csproj", "{52AF90A3-E637-44F4-9FE8-15114829DD5D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -60,5 +62,9 @@ Global
{34F0FFCF-F81E-4556-BC74-ED9AEBA7F731}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34F0FFCF-F81E-4556-BC74-ED9AEBA7F731}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34F0FFCF-F81E-4556-BC74-ED9AEBA7F731}.Release|Any CPU.Build.0 = Release|Any CPU
{52AF90A3-E637-44F4-9FE8-15114829DD5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{52AF90A3-E637-44F4-9FE8-15114829DD5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{52AF90A3-E637-44F4-9FE8-15114829DD5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{52AF90A3-E637-44F4-9FE8-15114829DD5D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="1.0.0-alpha2" />
<PackageReference Include="SeeShark" Version="3.0.0" />
</ItemGroup>

View File

@ -85,7 +85,7 @@ namespace Mediapipe.Net.Examples.FaceMesh
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
using ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
using ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
List<NormalizedLandmarkList>? landmarks = calculator.Compute(imgframe);

View File

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="1.0.0-alpha2" />
<PackageReference Include="SeeShark" Version="3.0.0" />
</ItemGroup>

View File

@ -79,7 +79,7 @@ namespace Mediapipe.Net.Examples.FaceMeshGpu
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
using ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
using ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
List<NormalizedLandmarkList>? landmarks = calculator.Compute(imgframe);

View File

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="1.0.0-alpha2" />
<PackageReference Include="SeeShark" Version="3.0.0" />
</ItemGroup>

View File

@ -7,6 +7,7 @@ using CommandLine;
using FFmpeg.AutoGen;
using Mediapipe.Net.External;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Solutions;
using Mediapipe.Net.Util;
using SeeShark;
@ -93,7 +94,7 @@ namespace Mediapipe.Net.Examples.Hands
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
HandsOutput handsOutput = calculator.Compute(imgframe);

View File

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="1.0.0-alpha2" />
<PackageReference Include="SeeShark" Version="3.0.0" />
</ItemGroup>

View File

@ -8,6 +8,7 @@ using CommandLine;
using FFmpeg.AutoGen;
using Mediapipe.Net.External;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Solutions;
using Mediapipe.Net.Util;
using SeeShark;
@ -95,7 +96,7 @@ namespace Mediapipe.Net.Examples.HandsGpu
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
HandsOutput handsOutput = calculator.Compute(imgframe);

View File

@ -11,8 +11,8 @@
<ItemGroup Label="Package References">
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Framework.Protobuf" Version="0.8.9" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Framework.Protobuf" Version="1.0.0-alpha2" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="1.0.0-alpha2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="ppy.osu.Framework" Version="2022.707.0" />

View File

@ -18,6 +18,7 @@ using osu.Framework.Graphics.Textures;
using SeeShark;
using SeeShark.Device;
using SixLabors.ImageSharp.PixelFormats;
using Anchor = osu.Framework.Graphics.Anchor;
using Image = SixLabors.ImageSharp.Image;
namespace Mediapipe.Net.Examples.OsuFrameworkVisualTests
@ -72,7 +73,7 @@ namespace Mediapipe.Net.Examples.OsuFrameworkVisualTests
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
using ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
using ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
List<NormalizedLandmarkList>? landmarkList = calculator.Compute(imgframe);

View File

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="1.0.0-alpha2" />
<PackageReference Include="SeeShark" Version="3.0.0" />
</ItemGroup>

View File

@ -7,6 +7,7 @@ using CommandLine;
using FFmpeg.AutoGen;
using Mediapipe.Net.External;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Solutions;
using Mediapipe.Net.Util;
using SeeShark;
@ -86,7 +87,7 @@ namespace Mediapipe.Net.Examples.Pose
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
PoseOutput handsOutput = calculator.Compute(imgframe);

View File

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
<PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="0.8.9.1" />
<PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="1.0.0-alpha2" />
<PackageReference Include="SeeShark" Version="3.0.0" />
</ItemGroup>

View File

@ -7,6 +7,7 @@ using CommandLine;
using FFmpeg.AutoGen;
using Mediapipe.Net.External;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Solutions;
using Mediapipe.Net.Util;
using SeeShark;
@ -86,7 +87,7 @@ namespace Mediapipe.Net.Examples.PoseGpu
converter ??= new FrameConverter(frame, PixelFormat.Rgba);
Frame cFrame = converter.Convert(frame);
ImageFrame imgframe = new ImageFrame(ImageFormat.Srgba,
ImageFrame imgframe = new ImageFrame(ImageFormat.Types.Format.Srgba,
cFrame.Width, cFrame.Height, cFrame.WidthStep, cFrame.RawData);
PoseOutput handsOutput = calculator.Compute(imgframe);

View File

@ -43,8 +43,8 @@ output_stream: ""out""
{
using var graph = new CalculatorGraph(valid_config_text);
var config = graph.Config();
Assert.AreEqual(config.InputStream[0], "in");
Assert.AreEqual(config.OutputStream[0], "out");
Assert.AreEqual("in", config.InputStream[0]);
Assert.AreEqual("out", config.OutputStream[0]);
}
#endregion
@ -77,8 +77,8 @@ output_stream: ""out""
}
var config = graph.Config();
Assert.AreEqual(config.InputStream[0], "in");
Assert.AreEqual(config.OutputStream[0], "out");
Assert.AreEqual("in", config.InputStream[0]);
Assert.AreEqual("out", config.OutputStream[0]);
}
[Test]
@ -86,7 +86,7 @@ output_stream: ""out""
{
using var graph = new CalculatorGraph(valid_config_text);
using var status = graph.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(valid_config_text));
Assert.AreEqual(status.Code, Status.StatusCode.Internal);
Assert.AreEqual(Status.StatusCode.Internal, status.Code);
}
[Test]
@ -112,7 +112,7 @@ output_stream: ""out""
var config = CalculatorGraphConfig.Parser.ParseFromTextFormat(valid_config_text);
using var status = graph.Initialize(config, sidePackets);
Assert.AreEqual(status.Code, Status.StatusCode.Internal);
Assert.AreEqual(Status.StatusCode.Internal, status.Code);
}
#endregion
@ -137,7 +137,7 @@ output_stream: ""out""
using var graph = new CalculatorGraph(valid_config_text);
Assert.True(graph.StartRun().Ok());
graph.Cancel();
Assert.AreEqual(graph.WaitUntilDone().Code, Status.StatusCode.Cancelled);
Assert.AreEqual(Status.StatusCode.Cancelled, graph.WaitUntilDone().Code);
}
#endregion
}

View File

@ -6,67 +6,60 @@ using System;
using System.Linq;
using Mediapipe.Net.Core;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Tests;
using NUnit.Framework;
namespace Mediapipe.Net.Tests.Framework.Format
namespace Mediapipe.Tests
{
public class ImageFrameTest
{
#region Constructor
[Test, SignalAbort]
public void Ctor_ShouldInstantiateImageFrame_When_CalledWithNoArguments()
[Test]
public unsafe void Ctor_ShouldInstantiateImageFrame_When_CalledWithNoArguments()
{
using var imageFrame = new ImageFrame();
#pragma warning disable IDE0058
Assert.AreEqual(imageFrame.Format, ImageFormat.Unknown);
Assert.AreEqual(imageFrame.Width, 0);
Assert.AreEqual(imageFrame.Height, 0);
// As these are now properties, i had to ToString() them so that they are run.
Assert.Throws<FormatException>(() => imageFrame.ChannelSize.ToString());
Assert.Throws<FormatException>(() => imageFrame.NumberOfChannels.ToString());
Assert.Throws<FormatException>(() => imageFrame.ByteDepth.ToString());
Assert.AreEqual(imageFrame.WidthStep, 0);
Assert.AreEqual(imageFrame.PixelDataSize, 0);
Assert.Throws<FormatException>(() => imageFrame.PixelDataSizeStoredContiguously.ToString());
Assert.AreEqual(ImageFormat.Types.Format.Unknown, imageFrame.Format);
Assert.AreEqual(0, imageFrame.Width);
Assert.AreEqual(0, imageFrame.Height, 0);
Assert.AreEqual(0, imageFrame.ChannelSize);
Assert.AreEqual(0, imageFrame.NumberOfChannels);
Assert.AreEqual(0, imageFrame.ByteDepth);
Assert.AreEqual(0, imageFrame.WidthStep);
Assert.AreEqual(0, imageFrame.PixelDataSize);
Assert.AreEqual(0, imageFrame.PixelDataSizeStoredContiguously);
Assert.True(imageFrame.IsEmpty);
Assert.False(imageFrame.IsContiguous);
Assert.False(imageFrame.IsAligned(16));
unsafe
{
Assert.True(imageFrame.MutablePixelData == null);
}
#pragma warning restore IDE0058
}
[Test]
public void Ctor_ShouldInstantiateImageFrame_When_CalledWithFormat()
public unsafe void Ctor_ShouldInstantiateImageFrame_When_CalledWithFormat()
{
using var imageFrame = new ImageFrame(ImageFormat.Sbgra, 640, 480);
Assert.AreEqual(imageFrame.Format, ImageFormat.Sbgra);
Assert.AreEqual(imageFrame.Width, 640);
Assert.AreEqual(imageFrame.Height, 480);
Assert.AreEqual(imageFrame.ChannelSize, 1);
Assert.AreEqual(imageFrame.NumberOfChannels, 4);
Assert.AreEqual(imageFrame.ByteDepth, 1);
Assert.AreEqual(imageFrame.WidthStep, 640 * 4);
Assert.AreEqual(imageFrame.PixelDataSize, 640 * 480 * 4);
Assert.AreEqual(imageFrame.PixelDataSizeStoredContiguously, 640 * 480 * 4);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Sbgra, 640, 480);
Assert.AreEqual(ImageFormat.Types.Format.Sbgra, imageFrame.Format);
Assert.AreEqual(640, imageFrame.Width);
Assert.AreEqual(480, imageFrame.Height);
Assert.AreEqual(1, imageFrame.ChannelSize);
Assert.AreEqual(4, imageFrame.NumberOfChannels);
Assert.AreEqual(1, imageFrame.ByteDepth);
Assert.AreEqual(640 * 4, imageFrame.WidthStep);
Assert.AreEqual(640 * 480 * 4, imageFrame.PixelDataSize);
Assert.AreEqual(640 * 480 * 4, imageFrame.PixelDataSizeStoredContiguously);
Assert.False(imageFrame.IsEmpty);
Assert.True(imageFrame.IsContiguous);
Assert.True(imageFrame.IsAligned(16));
unsafe
{
Assert.True(imageFrame.MutablePixelData != null);
}
}
[Test]
public void Ctor_ShouldInstantiateImageFrame_When_CalledWithFormatAndAlignmentBoundary()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray8, 100, 100, 8);
Assert.AreEqual(imageFrame.Width, 100);
Assert.AreEqual(imageFrame.NumberOfChannels, 1);
Assert.AreEqual(imageFrame.WidthStep, 104);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 100, 100, 8);
Assert.AreEqual(100, imageFrame.Width);
Assert.AreEqual(1, imageFrame.NumberOfChannels);
Assert.AreEqual(104, imageFrame.WidthStep);
}
[Test]
@ -77,71 +70,83 @@ namespace Mediapipe.Net.Tests.Framework.Format
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
};
using var imageFrame = new ImageFrame(ImageFormat.Sbgra, 4, 2, 16, srcBytes);
Assert.AreEqual(imageFrame.Width, 4);
Assert.AreEqual(imageFrame.Height, 2);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Sbgra, 4, 2, 16, srcBytes);
Assert.AreEqual(4, imageFrame.Width);
Assert.AreEqual(2, imageFrame.Height);
Assert.False(imageFrame.IsEmpty);
byte[] bytes = imageFrame.CopyToByteBuffer(srcBytes.Length);
byte[] bytes = new byte[32];
imageFrame.CopyToBuffer(bytes);
Assert.IsEmpty(bytes.Where((x, i) => x != srcBytes[i]));
}
[Test, SignalAbort]
public void Ctor_ShouldThrowMediapipeException_When_CalledWithInvalidArgument()
public void Ctor_ShouldThrowMediaPipeException_When_CalledWithInvalidArgument()
{
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { new ImageFrame(ImageFormat.Sbgra, 640, 480, 0); });
Assert.Throws<MediapipeException>(() => { new ImageFrame(ImageFormat.Types.Format.Sbgra, 640, 480, 0); });
#pragma warning restore IDE0058
}
#endregion
#region IsDisposed
#region #isDisposed
[Test]
public void IsDisposed_ShouldReturnFalse_When_NotDisposedYet()
{
using var imageFrame = new ImageFrame();
using ImageFrame imageFrame = new ImageFrame();
Assert.False(imageFrame.IsDisposed);
}
[Test]
public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed()
{
var imageFrame = new ImageFrame();
ImageFrame imageFrame = new ImageFrame();
imageFrame.Dispose();
Assert.True(imageFrame.IsDisposed);
}
#endregion
#region SetToZero
#region #SetToZero
[Test]
public void SetToZero_ShouldSetZeroToAllBytes()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray8, 10, 10);
var origBytes = imageFrame.CopyToByteBuffer(100);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 10, 10);
imageFrame.SetToZero();
var bytes = imageFrame.CopyToByteBuffer(100);
var bytes = new byte[100];
imageFrame.CopyToBuffer(bytes);
Assert.True(bytes.All((x) => x == 0));
}
#endregion
#region SetAlignmentPaddingAreas
#region #SetAlignmentPaddingAreas
[Test]
public void SetAlignmentPaddingAreas_ShouldNotThrow()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray8, 10, 10, 16);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 10, 10, 16);
Assert.DoesNotThrow(() => { imageFrame.SetAlignmentPaddingAreas(); });
}
#endregion
#region CopyToBuffer
[Test, SignalAbort]
public void CopyToByteBuffer_ShouldThrowException_When_BufferDepthIsWrong()
{
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray16, 10, 10);
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToBuffer(new byte[100]); });
#pragma warning restore IDE0058
}
[Test]
public void CopyToByteBuffer_ShouldReturnByteArray_When_BufferSizeIsLargeEnough()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray8, 10, 10);
var normalBuffer = imageFrame.CopyToByteBuffer(100);
var largeBuffer = imageFrame.CopyToByteBuffer(120);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 10, 10);
var normalBuffer = new byte[100];
var largeBuffer = new byte[120];
imageFrame.CopyToBuffer(normalBuffer);
imageFrame.CopyToBuffer(largeBuffer);
Assert.IsEmpty(normalBuffer.Where((x, i) => x != largeBuffer[i]));
}
@ -149,18 +154,29 @@ namespace Mediapipe.Net.Tests.Framework.Format
[Test, SignalAbort]
public void CopyToByteBuffer_ShouldThrowException_When_BufferSizeIsTooSmall()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray8, 10, 10);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 10, 10);
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToByteBuffer(99); });
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToBuffer(new byte[99]); });
#pragma warning restore IDE0058
}
[Test, SignalAbort]
public void CopyToUshortBuffer_ShouldThrowException_When_BufferDepthIsWrong()
{
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 10, 10);
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToBuffer(new ushort[100]); });
#pragma warning restore IDE0058
}
[Test]
public void CopyToUshortBuffer_ShouldReturnUshortArray_When_BufferSizeIsLargeEnough()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray16, 10, 10);
var normalBuffer = imageFrame.CopyToUshortBuffer(100);
var largeBuffer = imageFrame.CopyToUshortBuffer(120);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray16, 10, 10);
var normalBuffer = new ushort[100];
var largeBuffer = new ushort[120];
imageFrame.CopyToBuffer(normalBuffer);
imageFrame.CopyToBuffer(largeBuffer);
Assert.IsEmpty(normalBuffer.Where((x, i) => x != largeBuffer[i]));
}
@ -168,18 +184,29 @@ namespace Mediapipe.Net.Tests.Framework.Format
[Test, SignalAbort]
public void CopyToUshortBuffer_ShouldThrowException_When_BufferSizeIsTooSmall()
{
using var imageFrame = new ImageFrame(ImageFormat.Gray16, 10, 10);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray16, 10, 10);
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToUshortBuffer(99); });
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToBuffer(new ushort[99]); });
#pragma warning restore IDE0058
}
[Test, SignalAbort]
public void CopyToFloatBuffer_ShouldThrowException_When_BufferDepthIsWrong()
{
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Gray8, 10, 10);
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToBuffer(new float[100]); });
#pragma warning restore IDE0058
}
[Test]
public void CopyToFloatBuffer_ShouldReturnFloatArray_When_BufferSizeIsLargeEnough()
{
using var imageFrame = new ImageFrame(ImageFormat.Vec32f1, 10, 10);
var normalBuffer = imageFrame.CopyToFloatBuffer(100);
var largeBuffer = imageFrame.CopyToFloatBuffer(120);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Vec32F1, 10, 10);
var normalBuffer = new float[100];
var largeBuffer = new float[120];
imageFrame.CopyToBuffer(normalBuffer);
imageFrame.CopyToBuffer(largeBuffer);
Assert.IsEmpty(normalBuffer.Where((x, i) => Math.Abs(x - largeBuffer[i]) > 1e-9));
}
@ -187,11 +214,11 @@ namespace Mediapipe.Net.Tests.Framework.Format
[Test, SignalAbort]
public void CopyToFloatBuffer_ShouldThrowException_When_BufferSizeIsTooSmall()
{
using var imageFrame = new ImageFrame(ImageFormat.Vec32f1, 10, 10);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Vec32F1, 10, 10);
#pragma warning disable IDE0058
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToFloatBuffer(99); });
Assert.Throws<MediapipeException>(() => { imageFrame.CopyToBuffer(new float[99]); });
#pragma warning restore IDE0058
}
#endregion
}
#endregion
}

View File

@ -6,6 +6,7 @@ using System;
using Mediapipe.Net.Framework;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Protobuf;
using NUnit.Framework;
namespace Mediapipe.Net.Tests.Framework.NewPacket
@ -26,8 +27,8 @@ namespace Mediapipe.Net.Tests.Framework.NewPacket
using var statusOrImageFrame = packet.ConsumeImageFrame();
Assert.True(statusOrImageFrame.Ok());
using var imageFrame = statusOrImageFrame.Value();
Assert.AreEqual(imageFrame.Format, ImageFormat.Unknown);
using ImageFrame? imageFrame = statusOrImageFrame.Value();
Assert.AreEqual(imageFrame?.Format, ImageFormat.Types.Format.Unknown);
}
[Test]
@ -47,7 +48,7 @@ namespace Mediapipe.Net.Tests.Framework.NewPacket
Assert.True(statusOrImageFrame.Ok());
using var imageFrame = statusOrImageFrame.Value();
Assert.AreEqual(imageFrame.Format, ImageFormat.Unknown);
Assert.AreEqual(imageFrame?.Format, ImageFormat.Types.Format.Unknown);
Assert.AreEqual(packet.Timestamp(), timestamp);
}
#endregion
@ -74,9 +75,9 @@ namespace Mediapipe.Net.Tests.Framework.NewPacket
[Test]
public void Get_ShouldReturnImageFrame_When_DataIsNotEmpty()
{
using var packet = PacketFactory.ImageFramePacket(new ImageFrame(ImageFormat.Sbgra, 10, 10));
using var packet = PacketFactory.ImageFramePacket(new ImageFrame(ImageFormat.Types.Format.Sbgra, 10, 10));
using var imageFrame = packet.GetImageFrame();
Assert.AreEqual(imageFrame.Format, ImageFormat.Sbgra);
Assert.AreEqual(imageFrame.Format, ImageFormat.Types.Format.Sbgra);
Assert.AreEqual(imageFrame.Width, 10);
Assert.AreEqual(imageFrame.Height, 10);
}
@ -86,14 +87,14 @@ namespace Mediapipe.Net.Tests.Framework.NewPacket
[Test]
public void Consume_ShouldReturnImageFrame()
{
using var packet = PacketFactory.ImageFramePacket(new ImageFrame(ImageFormat.Sbgra, 10, 10));
using var packet = PacketFactory.ImageFramePacket(new ImageFrame(ImageFormat.Types.Format.Sbgra, 10, 10));
using var statusOrImageFrame = packet.ConsumeImageFrame();
Assert.True(statusOrImageFrame.Ok());
using var imageFrame = statusOrImageFrame.Value();
Assert.AreEqual(imageFrame.Format, ImageFormat.Sbgra);
Assert.AreEqual(imageFrame.Width, 10);
Assert.AreEqual(imageFrame.Height, 10);
using ImageFrame? imageFrame = statusOrImageFrame.Value();
Assert.AreEqual(imageFrame?.Format, ImageFormat.Types.Format.Sbgra);
Assert.AreEqual(imageFrame?.Width, 10);
Assert.AreEqual(imageFrame?.Height, 10);
}
#endregion

View File

@ -15,7 +15,7 @@ namespace Mediapipe.Net.Tests.Framework.Port
public void Status_ShouldReturnOk_When_StatusIsOk()
{
using var statusOrGpuResources = GpuResources.Create();
Assert.AreEqual(statusOrGpuResources.Status.Code, Status.StatusCode.Ok);
Assert.AreEqual(Status.StatusCode.Ok, statusOrGpuResources.Status.Code);
}
#endregion

View File

@ -6,6 +6,7 @@ using Mediapipe.Net.Framework;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Port;
using Mediapipe.Net.Framework.Protobuf;
using NUnit.Framework;
namespace Mediapipe.Net.Tests.Framework.Port
@ -18,7 +19,7 @@ namespace Mediapipe.Net.Tests.Framework.Port
{
using var statusOrImageFrame = initializeSubject();
Assert.True(statusOrImageFrame.Ok());
Assert.AreEqual(statusOrImageFrame.Status.Code, Status.StatusCode.Ok);
Assert.AreEqual(Status.StatusCode.Ok, statusOrImageFrame.Status.Code);
}
#endregion
@ -48,15 +49,15 @@ namespace Mediapipe.Net.Tests.Framework.Port
Assert.True(statusOrImageFrame.Ok());
using var imageFrame = statusOrImageFrame.Value();
Assert.AreEqual(imageFrame.Width, 10);
Assert.AreEqual(imageFrame.Height, 10);
Assert.AreEqual(10, imageFrame.Width);
Assert.AreEqual(10, imageFrame.Height);
Assert.True(statusOrImageFrame.IsDisposed);
}
#endregion
private static StatusOrImageFrame initializeSubject()
{
var imageFrame = new ImageFrame(ImageFormat.Sbgra, 10, 10);
var imageFrame = new ImageFrame(ImageFormat.Types.Format.Sbgra, 10, 10);
var packet = PacketFactory.ImageFramePacket(imageFrame, new Timestamp(1));
return (StatusOrImageFrame)packet.ConsumeImageFrame();

View File

@ -0,0 +1,75 @@
// 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 Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Port;
using NUnit.Framework;
namespace Mediapipe.Net.Tests
{
public class StatusOrStringTest
{
#region #status
[Test]
public void Status_ShouldReturnOk_When_StatusIsOk()
{
using var statusOrString = initializeSubject("");
Assert.True(statusOrString.Ok());
Assert.AreEqual(Status.StatusCode.Ok, statusOrString.Status.Code);
}
#endregion
#region #isDisposed
[Test]
public void IsDisposed_ShouldReturnFalse_When_NotDisposedYet()
{
using var statusOrString = initializeSubject("");
Assert.False(statusOrString.IsDisposed);
}
[Test]
public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed()
{
var statusOrString = initializeSubject("");
statusOrString.Dispose();
Assert.True(statusOrString.IsDisposed);
}
#endregion
#region #Value
[Test]
public void Value_ShouldReturnString_When_StatusIsOk()
{
var bytes = new byte[] { (byte)'a', (byte)'b', 0, (byte)'c' };
using var statusOrString = initializeSubject(bytes);
Assert.True(statusOrString.Ok());
Assert.AreEqual("ab", statusOrString.Value());
}
#endregion
#region #ValueAsByteArray
[Test]
public void ValueAsByteArray_ShouldReturnByteArray_When_StatusIsOk()
{
var bytes = new byte[] { (byte)'a', (byte)'b', 0, (byte)'c' };
using var statusOrString = initializeSubject(bytes);
Assert.True(statusOrString.Ok());
Assert.AreEqual(bytes, statusOrString.ValueAsByteArray());
}
#endregion
private StatusOrString initializeSubject(string str)
{
using Packet packet = PacketFactory.StringPacket(str);
return (StatusOrString)packet.ConsumeString();
}
private StatusOrString initializeSubject(byte[] bytes)
{
using Packet packet = PacketFactory.StringPacket(bytes);
return (StatusOrString)packet.ConsumeString();
}
}
}

View File

@ -15,14 +15,14 @@ namespace Mediapipe.Net.Tests.Framework.Port
public void Code_ShouldReturnStatusCode_When_StatusIsOk()
{
using var status = Status.Ok();
Assert.AreEqual(status.Code, Status.StatusCode.Ok);
Assert.AreEqual(Status.StatusCode.Ok, status.Code);
}
[Test]
public void Code_ShouldReturnStatusCode_When_StatusIsFailedPrecondition()
{
using var status = Status.FailedPrecondition();
Assert.AreEqual(status.Code, Status.StatusCode.FailedPrecondition);
Assert.AreEqual(Status.StatusCode.FailedPrecondition, status.Code);
}
#endregion
@ -49,14 +49,14 @@ namespace Mediapipe.Net.Tests.Framework.Port
public void RawCode_ShouldReturnRawCode_When_StatusIsOk()
{
using var status = Status.Ok();
Assert.AreEqual(status.RawCode, 0);
Assert.AreEqual(0, status.RawCode);
}
[Test]
public void RawCode_ShouldReturnRawCode_When_StatusIsFailedPrecondition()
{
using var status = Status.FailedPrecondition();
Assert.AreEqual(status.RawCode, 9);
Assert.AreEqual(9, status.RawCode);
}
#endregion
@ -108,8 +108,64 @@ namespace Mediapipe.Net.Tests.Framework.Port
{
var message = "Some error";
using var status = Status.FailedPrecondition(message);
Assert.AreEqual(status.ToString(), $"FAILED_PRECONDITION: {message}");
Assert.AreEqual($"FAILED_PRECONDITION: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsAborted()
{
var message = "Some error";
using Status status = Status.Aborted(message);
Assert.AreEqual($"ABORTED: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsOutOfRange()
{
string message = "Some error";
using Status status = Status.OutOfRange(message);
Assert.AreEqual($"OUT_OF_RANGE: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsUnimplemented()
{
var message = "Some error";
using Status status = Status.Unimplemented(message);
Assert.AreEqual($"UNIMPLEMENTED: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsInternal()
{
var message = "Some error";
using Status status = Status.Internal(message);
Assert.AreEqual($"INTERNAL: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsUnavailable()
{
var message = "Some error";
using Status status = Status.Unavailable(message);
Assert.AreEqual($"UNAVAILABLE: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsDataLoss()
{
var message = "Some error";
using Status status = Status.DataLoss(message);
Assert.AreEqual($"DATA_LOSS: {message}", status.ToString());
}
[Test]
public void ToString_ShouldReturnMessage_When_StatusIsUnauthenticated()
{
var message = "Some error";
using Status status = Status.Unauthenticated(message);
Assert.AreEqual($"UNAUTHENTICATED: {message}", status.ToString());
}
}
#endregion
}
}

View File

@ -32,7 +32,7 @@ namespace Mediapipe.Net.Tests.Framework
public void Value_ShouldReturnValue()
{
using var timestamp = new Timestamp(10);
Assert.AreEqual(timestamp.Value, 10);
Assert.AreEqual(10, timestamp.Value);
}
#endregion
@ -41,7 +41,7 @@ namespace Mediapipe.Net.Tests.Framework
public void Seconds_ShouldReturnValueInSeconds()
{
using var timestamp = new Timestamp(1_000_000);
Assert.AreEqual(timestamp.Seconds, 1d, 1e-9);
Assert.AreEqual(1d, timestamp.Seconds, 1e-9);
}
#endregion
@ -50,7 +50,7 @@ namespace Mediapipe.Net.Tests.Framework
public void Microseconds_ShouldReturnValueInMicroseconds()
{
using var timestamp = new Timestamp(1_000_000);
Assert.AreEqual(timestamp.Microseconds, 1_000_000);
Assert.AreEqual(1_000_000, timestamp.Microseconds);
}
#endregion
@ -142,14 +142,14 @@ namespace Mediapipe.Net.Tests.Framework
public void DebugString_ShouldReturnDebugString()
{
using var timestamp = new Timestamp(1);
Assert.AreEqual(timestamp.DebugString, "1");
Assert.AreEqual("1", timestamp.DebugString);
}
[Test]
public void DebugString_ShouldReturnDebugString_When_TimestampIsUnset()
{
using var timestamp = Timestamp.Unset();
Assert.AreEqual(timestamp.DebugString, "Timestamp::Unset()");
Assert.AreEqual("Timestamp::Unset()", timestamp.DebugString);
}
#endregion
@ -159,7 +159,7 @@ namespace Mediapipe.Net.Tests.Framework
{
using var timestamp = new Timestamp(1);
using var nextTimestamp = timestamp.NextAllowedInStream();
Assert.AreEqual(nextTimestamp.Microseconds, 2);
Assert.AreEqual(2, nextTimestamp.Microseconds);
}
[Test]
@ -167,7 +167,7 @@ namespace Mediapipe.Net.Tests.Framework
{
using var timestamp = Timestamp.PostStream();
using var nextTimestamp = timestamp.NextAllowedInStream();
Assert.AreEqual(nextTimestamp, Timestamp.OneOverPostStream());
Assert.AreEqual(Timestamp.OneOverPostStream(), nextTimestamp);
}
#endregion
@ -177,7 +177,7 @@ namespace Mediapipe.Net.Tests.Framework
{
using var timestamp = new Timestamp(1);
using var nextTimestamp = timestamp.PreviousAllowedInStream();
Assert.AreEqual(nextTimestamp.Microseconds, 0);
Assert.AreEqual(0, nextTimestamp.Microseconds);
}
[Test]
@ -185,7 +185,7 @@ namespace Mediapipe.Net.Tests.Framework
{
using var timestamp = Timestamp.PreStream();
using var nextTimestamp = timestamp.PreviousAllowedInStream();
Assert.AreEqual(nextTimestamp, Timestamp.Unstarted());
Assert.AreEqual(Timestamp.Unstarted(), nextTimestamp);
}
#endregion
@ -194,7 +194,7 @@ namespace Mediapipe.Net.Tests.Framework
public void FromSeconds_ShouldReturnTimestamp()
{
using var timestamp = Timestamp.FromSeconds(1d);
Assert.AreEqual(timestamp.Microseconds, 1_000_000);
Assert.AreEqual(1_000_000, timestamp.Microseconds);
}
#endregion
}

View File

@ -18,7 +18,7 @@ namespace Mediapipe.Net.Tests.Framework.Tool
public void GetUnusedNodeName_ShouldReturnUniqueName(string configJson, string nameBase, string uniqueName)
{
var config = CalculatorGraphConfig.Parser.ParseJson(configJson);
Assert.AreEqual(GetUnusedNodeName(config, nameBase), uniqueName);
Assert.AreEqual(uniqueName, GetUnusedNodeName(config, nameBase));
}
[TestCase("{}", "base", "base")]
@ -28,7 +28,7 @@ namespace Mediapipe.Net.Tests.Framework.Tool
public void GetUnusedSidePacketName_ShouldReturnUniqueName(string configJson, string nameBase, string uniqueName)
{
var config = CalculatorGraphConfig.Parser.ParseJson(configJson);
Assert.AreEqual(GetUnusedSidePacketName(config, nameBase), uniqueName);
Assert.AreEqual(uniqueName, GetUnusedSidePacketName(config, nameBase));
}
[TestCase(@"{""node"":[{""name"":""x""}]}", 0, "x")]
@ -43,7 +43,7 @@ namespace Mediapipe.Net.Tests.Framework.Tool
public void CanonicalNodeName_ShouldReturnCanonicalNodeName_When_NodeIdIsValid(string configJson, int nodeId, string name)
{
var config = CalculatorGraphConfig.Parser.ParseJson(configJson);
Assert.AreEqual(CanonicalNodeName(config, nodeId), name);
Assert.AreEqual(name, CanonicalNodeName(config, nodeId));
}
[Test]
@ -78,7 +78,7 @@ namespace Mediapipe.Net.Tests.Framework.Tool
[TestCase("TAG:1:x", "x")]
public void ParseNameFromStream_ShouldReturnName_When_InputIsValid(string stream, string name)
{
Assert.AreEqual(ParseNameFromStream(stream), name);
Assert.AreEqual(name, ParseNameFromStream(stream));
}
[TestCase(":stream")]
@ -99,8 +99,8 @@ namespace Mediapipe.Net.Tests.Framework.Tool
{
var output = ParseTagIndex(tagIndex);
Assert.AreEqual(output.Item1, tag);
Assert.AreEqual(output.Item2, index);
Assert.AreEqual(tag, output.Item1);
Assert.AreEqual(index, output.Item2);
}
[TestCase("tag")]
@ -121,8 +121,8 @@ namespace Mediapipe.Net.Tests.Framework.Tool
{
var output = ParseTagIndexFromStream(stream);
Assert.AreEqual(output.Item1, tag);
Assert.AreEqual(output.Item2, index);
Assert.AreEqual(tag, output.Item1);
Assert.AreEqual(index, output.Item2);
}
[TestCase(":stream")]
@ -141,7 +141,7 @@ namespace Mediapipe.Net.Tests.Framework.Tool
[TestCase("TAG", 1, "TAG:1")]
public void CatTag_ShouldReturnTag(string tag, int index, string output)
{
Assert.AreEqual(CatTag(tag, index), output);
Assert.AreEqual(output, CatTag(tag, index));
}
[TestCase("", -1, "x", "x")]
@ -150,7 +150,7 @@ namespace Mediapipe.Net.Tests.Framework.Tool
[TestCase("TAG", 1, "x", "TAG:1:x")]
public void CatStream_ShouldReturnStream(string tag, int index, string name, string output)
{
Assert.AreEqual(CatStream((tag, index), name), output);
Assert.AreEqual(output, CatStream((tag, index), name));
}
}
}

View File

@ -112,8 +112,8 @@ namespace Mediapipe.Net.Tests.Framework.Tool
{
ParseTagAndName(input, out var tag, out var name);
Assert.AreEqual(tag, expectedTag);
Assert.AreEqual(name, expectedName);
Assert.AreEqual(expectedTag, tag);
Assert.AreEqual(expectedName, name);
}
[TestCase(":humphrey")]
@ -128,8 +128,8 @@ namespace Mediapipe.Net.Tests.Framework.Tool
#pragma warning disable IDE0058
Assert.Throws<ArgumentException>(() => { ParseTagAndName(input, out tag, out name); });
Assert.AreEqual(tag, "UNTOUCHED");
Assert.AreEqual(name, "untouched");
Assert.AreEqual("UNTOUCHED", tag);
Assert.AreEqual("untouched", name);
#pragma warning restore IDE0058
}
@ -156,9 +156,9 @@ namespace Mediapipe.Net.Tests.Framework.Tool
{
ParseTagIndexName(input, out var tag, out var index, out var name);
Assert.AreEqual(tag, expectedTag);
Assert.AreEqual(index, expectedIndex);
Assert.AreEqual(name, expectedName);
Assert.AreEqual(expectedTag, tag);
Assert.AreEqual(expectedIndex, index);
Assert.AreEqual(expectedName, name);
}
[TestCase("")]
@ -205,9 +205,9 @@ namespace Mediapipe.Net.Tests.Framework.Tool
#pragma warning disable IDE0058
Assert.Throws<ArgumentException>(() => { ParseTagIndexName(input, out tag, out index, out name); });
Assert.AreEqual(tag, "UNTOUCHED");
Assert.AreEqual(index, -1);
Assert.AreEqual(name, "untouched");
Assert.AreEqual("UNTOUCHED", tag);
Assert.AreEqual(-1, index);
Assert.AreEqual("untouched", name);
#pragma warning restore IDE0058
}
@ -235,8 +235,8 @@ namespace Mediapipe.Net.Tests.Framework.Tool
{
ParseTagIndex(input, out var tag, out var index);
Assert.AreEqual(tag, expectedTag);
Assert.AreEqual(index, expectedIndex);
Assert.AreEqual(expectedTag, tag);
Assert.AreEqual(expectedIndex, index);
}
[TestCase("a")]
@ -270,8 +270,8 @@ namespace Mediapipe.Net.Tests.Framework.Tool
#pragma warning disable IDE0058
Assert.Throws<ArgumentException>(() => { ParseTagIndex(input, out tag, out index); });
Assert.AreEqual(tag, "UNTOUCHED");
Assert.AreEqual(index, -1);
Assert.AreEqual("UNTOUCHED", tag);
Assert.AreEqual(-1, index);
#pragma warning restore IDE0058
}

View File

@ -0,0 +1,743 @@
// 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.Linq;
using Mediapipe.Net.Framework;
using Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Port;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Framework.ValidatedGraphConfig;
using NUnit.Framework;
namespace Mediapipe.Net.Tests
{
public class ValidatedGraphConfigTest
{
private const string pass_through_config_text = @"
node {
calculator: ""PassThroughCalculator""
input_stream: ""in""
output_stream: ""out1""
}
node {
calculator: ""PassThroughCalculator""
input_stream: ""out1""
output_stream: ""out""
}
input_stream: ""in""
output_stream: ""out""
";
private const string flow_limiter_config_text = @"
input_stream: ""input_video""
input_stream: ""output""
node {
calculator: ""FlowLimiterCalculator""
input_stream: ""input_video""
input_stream: ""FINISHED:output""
input_stream_info: {
tag_index: ""FINISHED""
back_edge: true
}
input_side_packet: ""MAX_IN_FLIGHT:max_in_flight""
input_side_packet: ""OPTIONS:flow_limiter_calculator_options""
output_stream: ""throttled_input_video""
}
";
private const string image_transformation_config_text = @"
input_stream: ""input_video""
node: {
calculator: ""ImageTransformationCalculator""
input_stream: ""IMAGE:input_video""
input_side_packet: ""ROTATION_DEGREES:input_rotation""
input_side_packet: ""FLIP_HORIZONTALLY:input_horizontally_flipped""
input_side_packet: ""FLIP_VERTICALLY:input_vertically_flipped""
output_stream: ""IMAGE:transformed_input_video""
}
";
private const string constant_side_packet_config_text = @"
node {
calculator: ""ConstantSidePacketCalculator""
output_side_packet: ""PACKET:0:int_packet""
output_side_packet: ""PACKET:1:float_packet""
output_side_packet: ""PACKET:2:bool_packet""
output_side_packet: ""PACKET:3:string_packet""
options: {
[mediapipe.ConstantSidePacketCalculatorOptions.ext]: {
packet { int_value: 256 }
packet { float_value: 0.5f }
packet { bool_value: false }
packet { string_value: ""string"" }
}
}
}
";
private const string face_detection_short_range_common_config_text = @"
input_stream: ""detection_tensors""
input_stream: ""transform_matrix""
node {
calculator: ""FaceDetectionShortRangeCommon""
input_stream: ""TENSORS:detection_tensors""
input_stream: ""MATRIX:transform_matrix""
output_stream: ""DETECTIONS:detections""
}
";
#region Constructor
[Test]
public void Ctor_ShouldInstantiateValidatedGraphConfig()
{
Assert.DoesNotThrow(() =>
{
var config = new ValidatedGraphConfig();
config.Dispose();
});
}
#endregion
#region #IsDisposed
[Test]
public void IsDisposed_ShouldReturnFalse_When_NotDisposedYet()
{
using (var config = new ValidatedGraphConfig())
{
Assert.False(config.IsDisposed);
}
}
[Test]
public void IsDisposed_ShouldReturnTrue_When_AlreadyDisposed()
{
var config = new ValidatedGraphConfig();
config.Dispose();
Assert.True(config.IsDisposed);
}
#endregion
#region #Initialize
[Test]
public void Initialize_ShouldReturnOk_When_CalledWithConfig()
{
using (var config = new ValidatedGraphConfig())
{
using (var status = config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)))
{
Assert.True(status.Ok());
}
Assert.True(config.Initialized());
}
}
[Test]
public void Initialize_ShouldReturnOk_When_CalledWithValidGraphType()
{
using (var config = new ValidatedGraphConfig())
{
using (var status = config.Initialize("SwitchContainer"))
{
Assert.True(status.Ok());
}
Assert.True(config.Initialized());
}
}
[Test]
public void Initialize_ShouldReturnInternalError_When_CalledWithInvalidGraphType()
{
using (var config = new ValidatedGraphConfig())
{
using (var status = config.Initialize("InvalidSubgraph"))
{
Assert.AreEqual(Status.StatusCode.NotFound, status.Code);
}
Assert.False(config.Initialized());
}
}
#endregion
#region #ValidateRequiredSidePackets
[Test]
public void ValidateRequiredSidePackets_ShouldReturnOk_When_TheConfigDoesNotRequireSidePackets_And_SidePacketIsEmpty()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.True(status.Ok());
}
}
}
}
[Test]
public void ValidateRequiredSidePackets_ShouldReturnOk_When_TheConfigDoesNotRequireSidePackets_And_SidePacketIsNotEmpty()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
sidePackets.Emplace("in", PacketFactory.IntPacket(0));
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.True(status.Ok());
}
}
}
}
[Test]
public void ValidateRequiredSidePackets_ShouldReturnOk_When_AllTheSidePacketsAreOptional_And_SidePacketIsEmpty()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(flow_limiter_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.True(status.Ok());
}
}
}
}
[Test]
public void ValidateRequiredSidePackets_ShouldReturnInvalidArgumentError_When_TheConfigRequiresSidePackets_And_SidePacketIsEmpty()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(image_transformation_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.AreEqual(Status.StatusCode.InvalidArgument, status.Code);
}
}
}
}
[Test]
public void ValidateRequiredSidePackets_ShouldReturnInvalidArgumentError_When_AllTheRequiredSidePacketsAreNotGiven()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(image_transformation_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
sidePackets.Emplace("input_horizontally_flipped", PacketFactory.BoolPacket(false));
sidePackets.Emplace("input_vertically_flipped", PacketFactory.BoolPacket(true));
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.AreEqual(Status.StatusCode.InvalidArgument, status.Code);
}
}
}
}
[Test]
public void ValidateRequiredSidePackets_ShouldReturnInvalidArgumentError_When_TheSidePacketValuesAreWrong()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(image_transformation_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
sidePackets.Emplace("input_horizontally_flipped", PacketFactory.BoolPacket(false));
sidePackets.Emplace("input_vertically_flipped", PacketFactory.BoolPacket(true));
sidePackets.Emplace("input_rotation", PacketFactory.StringPacket("0"));
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.AreEqual(Status.StatusCode.InvalidArgument, status.Code);
}
}
}
}
[Test]
public void ValidateRequiredSidePackets_ShouldReturnOk_When_AllTheRequiredSidePacketsAreGiven()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(image_transformation_config_text)).AssertOk();
using (var sidePackets = new SidePackets())
{
sidePackets.Emplace("input_horizontally_flipped", PacketFactory.BoolPacket(false));
sidePackets.Emplace("input_vertically_flipped", PacketFactory.BoolPacket(true));
sidePackets.Emplace("input_rotation", PacketFactory.IntPacket(0));
using (var status = config.ValidateRequiredSidePackets(sidePackets))
{
Assert.True(status.Ok());
}
}
}
}
#endregion
#region Config
[Test]
public void Config_ShouldReturnAnEmptyConfig_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
var canonicalizedConfig = config.Config();
Assert.AreEqual(canonicalizedConfig.CalculateSize(), 0);
}
}
[Test]
public void Config_ShouldReturnTheCanonicalizedConfig_When_TheConfigIsPassThroughConfig()
{
using (var config = new ValidatedGraphConfig())
{
var originalConfig = CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text);
config.Initialize(originalConfig).AssertOk();
var canonicalizedConfig = config.Config();
Assert.AreEqual(originalConfig.Node, canonicalizedConfig.Node);
Assert.AreEqual(originalConfig.InputStream, canonicalizedConfig.InputStream);
Assert.AreEqual(originalConfig.OutputStream, canonicalizedConfig.OutputStream);
Assert.IsEmpty(originalConfig.Executor);
Assert.AreEqual(1, canonicalizedConfig.Executor.Count);
Assert.AreEqual(0, canonicalizedConfig.Executor[0].CalculateSize());
Assert.AreEqual(80, originalConfig.CalculateSize());
Assert.AreEqual(82, canonicalizedConfig.CalculateSize());
}
}
[Test]
public void Config_ShouldReturnTheCanonicalizedConfig_When_TheConfigIsFaceDetectionShortRangeCommonConfig()
{
using (var config = new ValidatedGraphConfig())
{
var originalConfig = CalculatorGraphConfig.Parser.ParseFromTextFormat(face_detection_short_range_common_config_text);
config.Initialize(originalConfig).AssertOk();
var canonicalizedConfig = config.Config();
Assert.AreEqual(145, originalConfig.CalculateSize());
Assert.AreEqual(936, canonicalizedConfig.CalculateSize());
}
}
#endregion
#region InputStreamInfos
[Test]
public void InputStreamInfos_ShouldReturnEmptyList_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.IsEmpty(config.InputStreamInfos());
}
}
[Test]
public void InputStreamInfos_ShouldReturnEmptyList_When_NoInputStreamExists()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(constant_side_packet_config_text)).AssertOk();
Assert.IsEmpty(config.InputStreamInfos());
}
}
[Test]
public void InputStreamInfos_ShouldReturnEdgeInfoList_When_InputStreamsExist()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
var inputStreamInfos = config.InputStreamInfos();
Assert.AreEqual(inputStreamInfos.Count, 2);
var inStream = inputStreamInfos.First((edgeInfo) => edgeInfo.Name == "in");
Assert.AreEqual(0, inStream.Upstream);
Assert.AreEqual(NodeType.Calculator, inStream.ParentNode.Type);
Assert.AreEqual(0, inStream.ParentNode.Index);
Assert.False(inStream.BackEdge);
var out1Stream = inputStreamInfos.First((edgeInfo) => edgeInfo.Name == "out1");
Assert.AreEqual(1, out1Stream.Upstream);
Assert.AreEqual(NodeType.Calculator, out1Stream.ParentNode.Type);
Assert.AreEqual(1, out1Stream.ParentNode.Index);
Assert.False(out1Stream.BackEdge);
}
}
#endregion
#region OutputStreamInfos
[Test]
public void OutputStreamInfos_ShouldReturnEmptyList_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.IsEmpty(config.OutputStreamInfos());
}
}
[Test]
public void OutputStreamInfos_ShouldReturnEdgeInfoList_When_OutputStreamsExist()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
var outputStreamInfos = config.OutputStreamInfos();
Assert.AreEqual(3, outputStreamInfos.Count);
var inStream = outputStreamInfos.First((edgeInfo) => edgeInfo.Name == "in");
Assert.AreEqual(-1, inStream.Upstream);
Assert.AreEqual(NodeType.GraphInputStream, inStream.ParentNode.Type);
Assert.AreEqual(2, inStream.ParentNode.Index, 2);
Assert.False(inStream.BackEdge);
var out1Stream = outputStreamInfos.First((edgeInfo) => edgeInfo.Name == "out1");
Assert.AreEqual(-1, out1Stream.Upstream);
Assert.AreEqual(NodeType.Calculator, out1Stream.ParentNode.Type);
Assert.AreEqual(0, out1Stream.ParentNode.Index);
Assert.False(out1Stream.BackEdge);
var outStream = outputStreamInfos.First((edgeInfo) => edgeInfo.Name == "out");
Assert.AreEqual(-1, outStream.Upstream);
Assert.AreEqual(NodeType.Calculator, outStream.ParentNode.Type);
Assert.AreEqual(1, outStream.ParentNode.Index);
Assert.False(outStream.BackEdge);
}
}
#endregion
#region InputSidePacketInfos
[Test]
public void InputSidePacketInfos_ShouldReturnEmptyList_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.IsEmpty(config.InputSidePacketInfos());
}
}
[Test]
public void InputSidePacketInfos_ShouldReturnEmptyList_When_NoInputSidePacketExists()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.IsEmpty(config.InputSidePacketInfos());
}
}
[Test]
public void InputSidePacketInfos_ShouldReturnEdgeInfoList_When_InputSidePacketsExist()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(flow_limiter_config_text)).AssertOk();
var inputSidePacketInfos = config.InputSidePacketInfos();
Assert.True(inputSidePacketInfos.Count >= 2);
var maxInFlightPacket = inputSidePacketInfos.First((edgeInfo) => edgeInfo.Name == "max_in_flight");
Assert.AreEqual(-1, maxInFlightPacket.Upstream);
Assert.AreEqual(NodeType.Calculator, maxInFlightPacket.ParentNode.Type);
Assert.False(maxInFlightPacket.BackEdge);
var flowLimiterCalculatorOptionsPacket = inputSidePacketInfos.First((edgeInfo) => edgeInfo.Name == "flow_limiter_calculator_options");
Assert.AreEqual(-1, flowLimiterCalculatorOptionsPacket.Upstream);
Assert.AreEqual(NodeType.Calculator, flowLimiterCalculatorOptionsPacket.ParentNode.Type);
Assert.False(flowLimiterCalculatorOptionsPacket.BackEdge);
}
}
#endregion
#region OutputSidePacketInfos
[Test]
public void OutputSidePacketInfos_ShouldReturnEmptyList_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.IsEmpty(config.OutputSidePacketInfos());
}
}
[Test]
public void OutputSidePacketInfos_ShouldReturnEmptyList_When_NoOutputSidePacketExists()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.IsEmpty(config.OutputSidePacketInfos());
}
}
[Test]
public void OutputSidePacketInfos_ShouldReturnEdgeInfoList_When_OutputSidePacketsExist()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(constant_side_packet_config_text)).AssertOk();
var outputSidePacketInfos = config.OutputSidePacketInfos();
Assert.AreEqual(4, outputSidePacketInfos.Count);
var intPacket = outputSidePacketInfos.First((edgeInfo) => edgeInfo.Name == "int_packet");
Assert.AreEqual(-1, intPacket.Upstream);
Assert.AreEqual(NodeType.Calculator, intPacket.ParentNode.Type);
Assert.False(intPacket.BackEdge);
var floatPacket = outputSidePacketInfos.First((edgeInfo) => edgeInfo.Name == "float_packet");
Assert.AreEqual(-1, floatPacket.Upstream);
Assert.AreEqual(NodeType.Calculator, floatPacket.ParentNode.Type);
Assert.False(floatPacket.BackEdge);
var boolPacket = outputSidePacketInfos.First((edgeInfo) => edgeInfo.Name == "bool_packet");
Assert.AreEqual(-1, boolPacket.Upstream);
Assert.AreEqual(NodeType.Calculator, boolPacket.ParentNode.Type);
Assert.False(boolPacket.BackEdge);
var stringPacket = outputSidePacketInfos.First((edgeInfo) => edgeInfo.Name == "string_packet");
Assert.AreEqual(-1, stringPacket.Upstream);
Assert.AreEqual(NodeType.Calculator, stringPacket.ParentNode.Type);
Assert.False(stringPacket.BackEdge);
}
}
#endregion
#region OutputStreamIndex
[Test]
public void OutputStreamIndex_ShouldReturnNegativeValue_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.AreEqual(-1, config.OutputStreamIndex(""));
}
}
[Test]
public void OutputStreamIndex_ShouldReturnNegativeValue_When_TheNameIsInvalid()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.AreEqual(-1, config.OutputStreamIndex("unknown"));
}
}
[Test]
public void OutputStreamIndex_ShouldReturnIndex_When_TheNameIsValid()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.AreEqual(2, config.OutputStreamIndex("out"));
}
}
[Test]
public void OutputStreamIndex_ShouldReturnIndex_When_TheStreamIsNotPublic()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.AreEqual(1, config.OutputStreamIndex("out1"));
}
}
#endregion
#region OutputSidePacketIndex
[Test]
public void OutputSidePacketIndex_ShouldReturnNegativeValue_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.AreEqual(-1, config.OutputSidePacketIndex(""));
}
}
[Test]
public void OutputSidePacketIndex_ShouldReturnNegativeValue_When_TheNameIsInvalid()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(constant_side_packet_config_text)).AssertOk();
Assert.AreEqual(-1, config.OutputSidePacketIndex("unknown"));
}
}
[Test]
public void OutputSidePacketIndex_ShouldReturnIndex_When_TheNameIsValid()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(constant_side_packet_config_text)).AssertOk();
Assert.AreEqual(0, config.OutputSidePacketIndex("int_packet"));
}
}
#endregion
#region OutputStreamToNode
[Test]
public void OutputStreamToNode_ShouldReturnNegativeValue_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.AreEqual(-1, config.OutputStreamToNode(""));
}
}
[Test]
public void OutputStreamToNode_ShouldReturnNegativeValue_When_TheNameIsInvalid()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.AreEqual(-1, config.OutputStreamToNode("unknown"));
}
}
[Test]
public void OutputStreamToNode_ShouldReturnIndex_When_TheNameIsValid()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.AreEqual(0, config.OutputStreamToNode("out1"));
}
}
#endregion
#region RegisteredSidePacketTypeName
[Test]
public void RegisteredSidePacketTypeName_ShouldReturnInvalidArgumentError_When_TheSidePacketDoesNotExist()
{
using (var config = new ValidatedGraphConfig())
{
using (var statusOrString = config.RegisteredSidePacketTypeName("max_in_flight"))
{
Assert.AreEqual(Status.StatusCode.InvalidArgument, statusOrString.Status.Code);
}
}
}
[Test]
public void RegisteredSidePacketTypeName_ShouldReturnUnknownError_When_TheSidePacketTypeCannotBeDetermined()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(flow_limiter_config_text)).AssertOk();
using (var statusOrString = config.RegisteredSidePacketTypeName("max_in_flight"))
{
Assert.AreEqual(Status.StatusCode.Unknown, statusOrString.Status.Code);
}
}
}
#endregion
#region RegisteredStreamTypeName
[Test]
public void RegisteredStreamTypeName_ShouldReturnInvalidArgumentError_When_TheStreamDoesNotExist()
{
using (var config = new ValidatedGraphConfig())
{
using (var statusOrString = config.RegisteredStreamTypeName("in"))
{
Assert.AreEqual(Status.StatusCode.InvalidArgument, statusOrString.Status.Code);
}
}
}
[Test]
public void RegisteredStreamTypeName_ShouldReturnUnknownError_When_TheStreamTypeCannotBeDetermined()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
using (var statusOrString = config.RegisteredStreamTypeName("in"))
{
Assert.AreEqual(Status.StatusCode.Unknown, statusOrString.Status.Code);
}
}
}
#endregion
#region Package
[Test]
public void Package_ShouldReturnNull_When_NotInitialized()
{
using var config = new ValidatedGraphConfig();
Assert.IsNull(config.Package());
}
[Test]
public void Package_ShouldReturnNull_When_TheNamespaceIsNotSet()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(pass_through_config_text)).AssertOk();
Assert.IsNull(config.Package());
}
}
#endregion
#region IsReservedExecutorName
[Test]
public void IsReservedExecutorName_ShouldReturnFalse_When_TheNameIsNotReserved()
{
Assert.False(ValidatedGraphConfig.IsReservedExecutorName("unknown"));
}
[Test]
public void IsReservedExecutorName_ShouldReturnFalse_When_TheNameIsReserved()
{
Assert.True(ValidatedGraphConfig.IsReservedExecutorName("default"));
Assert.True(ValidatedGraphConfig.IsReservedExecutorName("gpu"));
Assert.True(ValidatedGraphConfig.IsReservedExecutorName("__gpu"));
}
#endregion
#region IsExternalSidePacket
[Test]
public void IsExternalSidePacket_ShouldReturnFalse_When_NotInitialized()
{
using (var config = new ValidatedGraphConfig())
{
Assert.False(config.IsExternalSidePacket("max_in_flight"));
}
}
[Test]
public void IsExternalSidePacket_ShouldReturnFalse_When_TheSidePacketIsInternal()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(constant_side_packet_config_text)).AssertOk();
Assert.False(config.IsExternalSidePacket("int_packet"));
}
}
[Test]
public void IsExternalSidePacket_ShouldReturnTrue_When_TheSidePacketIsExternal()
{
using (var config = new ValidatedGraphConfig())
{
config.Initialize(CalculatorGraphConfig.Parser.ParseFromTextFormat(flow_limiter_config_text)).AssertOk();
Assert.True(config.IsExternalSidePacket("max_in_flight"));
}
}
#endregion
}
}

View File

@ -5,6 +5,7 @@
using System;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Port;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Gpu;
using NUnit.Framework;
using NUnit.Framework.Internal;
@ -61,31 +62,18 @@ namespace Mediapipe.Net.Tests.Gpu
using var glCalculatorHelper = new GlCalculatorHelper();
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
var status = glCalculatorHelper.RunInGlContext(() => { return Status.Ok(); });
Status status = glCalculatorHelper.RunInGlContext(() => { });
Assert.True(status.Ok());
}
[Test, GpuOnly]
public void RunInGlContext_ShouldReturnInternal_When_FunctionReturnsInternal()
public void RunInGlContext_ShouldReturnInternal_When_FunctionThrows()
{
using var glCalculatorHelper = new GlCalculatorHelper();
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
var status = glCalculatorHelper.RunInGlContext(() => { return Status.Build(Status.StatusCode.Internal, "error"); });
Assert.AreEqual(status.Code, Status.StatusCode.Internal);
}
[Test, GpuOnly]
public void RunInGlContext_ShouldReturnFailedPreCondition_When_FunctionThrows()
{
using var glCalculatorHelper = new GlCalculatorHelper();
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
#pragma warning disable IDE0039
GlCalculatorHelper.GlStatusFunction glStatusFunction = () => { throw new InvalidProgramException(); };
#pragma warning restore IDE0039
var status = glCalculatorHelper.RunInGlContext(glStatusFunction);
Assert.AreEqual(status.Code, Status.StatusCode.FailedPrecondition);
Status status = glCalculatorHelper.RunInGlContext((GlCalculatorHelper.GlFunction)(() => { throw new Exception("Function Throws"); }));
Assert.AreEqual(Status.StatusCode.Internal, status.Code);
}
#endregion
@ -96,16 +84,15 @@ namespace Mediapipe.Net.Tests.Gpu
using var glCalculatorHelper = new GlCalculatorHelper();
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
using var imageFrame = new ImageFrame(ImageFormat.Srgba, 32, 24);
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Srgba, 32, 24);
var status = glCalculatorHelper.RunInGlContext(() =>
{
var texture = glCalculatorHelper.CreateSourceTexture(imageFrame);
Assert.AreEqual(texture.Width, 32);
Assert.AreEqual(texture.Height, 24);
Assert.AreEqual(32, texture.Width);
Assert.AreEqual(24, texture.Height);
texture.Dispose();
return Status.Ok();
});
Assert.True(status.Ok());
@ -113,21 +100,19 @@ namespace Mediapipe.Net.Tests.Gpu
}
[Test, GpuOnly]
[Ignore("Skip because a thread will hang")]
public void CreateSourceTexture_ShouldFail_When_ImageFrameFormatIsInvalid()
{
using var glCalculatorHelper = new GlCalculatorHelper();
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
using var imageFrame = new ImageFrame(ImageFormat.Sbgra, 32, 24);
var status = glCalculatorHelper.RunInGlContext(() =>
{
using (var texture = glCalculatorHelper.CreateSourceTexture(imageFrame))
using var imageFrame = new ImageFrame(ImageFormat.Types.Format.Sbgra, 32, 24);
Status status = glCalculatorHelper.RunInGlContext(() =>
{
using GlTexture texture = glCalculatorHelper.CreateSourceTexture(imageFrame);
texture.Release();
}
return Status.Ok();
});
Assert.AreEqual(status.Code, Status.StatusCode.FailedPrecondition);
Assert.AreEqual(Status.StatusCode.FailedPrecondition, status.Code);
status.Dispose();
}
@ -140,20 +125,19 @@ namespace Mediapipe.Net.Tests.Gpu
using var glCalculatorHelper = new GlCalculatorHelper();
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
var status = glCalculatorHelper.RunInGlContext(() =>
Status status = glCalculatorHelper.RunInGlContext(() =>
{
var glTexture = glCalculatorHelper.CreateDestinationTexture(32, 24, GpuBufferFormat.KBgra32);
GlTexture glTexture = glCalculatorHelper.CreateDestinationTexture(32, 24, GpuBufferFormat.KBgra32);
Assert.AreEqual(glTexture.Width, 32);
Assert.AreEqual(glTexture.Height, 24);
return Status.Ok();
Assert.AreEqual(32, glTexture.Width);
Assert.AreEqual(24, glTexture.Height);
});
Assert.True(status.Ok());
}
#endregion
#region Framebuffer
#region framebuffer
[Test, GpuOnly]
public void Framebuffer_ShouldReturnGLName()
{
@ -161,7 +145,7 @@ namespace Mediapipe.Net.Tests.Gpu
glCalculatorHelper.InitializeForTest(GpuResources.Create().Value());
// default frame buffer
Assert.AreEqual(glCalculatorHelper.Framebuffer, 0);
Assert.AreEqual(0, glCalculatorHelper.Framebuffer);
}
#endregion

View File

@ -3,7 +3,6 @@
// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
using System;
using Mediapipe.Net.Framework.Port;
using Mediapipe.Net.Gpu;
using NUnit.Framework;
@ -28,10 +27,9 @@ namespace Mediapipe.Net.Tests.Gpu
glCalculatorHelper.RunInGlContext(() =>
{
using var glContext = GlContext.GetCurrent();
using GlContext? glContext = GlContext.GetCurrent();
Assert.NotNull(glContext);
Assert.True(glContext?.IsCurrent());
return Status.Ok();
}).AssertOk();
}
#endregion
@ -56,9 +54,9 @@ namespace Mediapipe.Net.Tests.Gpu
Assert.True(glContext.EglDisplay != null);
Assert.True(glContext.EglConfig != null);
Assert.True(glContext.EglContext != null);
Assert.AreEqual(glContext.GlMajorVersion, 3);
Assert.AreEqual(glContext.GlMinorVersion, 2);
Assert.AreEqual(glContext.GlFinishCount, 0);
Assert.AreEqual(3, glContext.GlMajorVersion);
Assert.AreEqual(2, glContext.GlMinorVersion);
Assert.AreEqual(0, glContext.GlFinishCount);
}
else if (OperatingSystem.IsMacOS())
{

View File

@ -14,8 +14,8 @@ namespace Mediapipe.Net.Tests.Gpu
public void Ctor_ShouldInstantiateGlTexture_When_CalledWithNoArguments()
{
using var glTexture = new GlTexture();
Assert.AreEqual(glTexture.Width, 0);
Assert.AreEqual(glTexture.Height, 0);
Assert.AreEqual(0, glTexture.Width);
Assert.AreEqual(0, glTexture.Height);
}
#endregion
@ -42,7 +42,7 @@ namespace Mediapipe.Net.Tests.Gpu
public void Target_ShouldReturnTarget()
{
using var glTexture = new GlTexture();
Assert.AreEqual(glTexture.Target, Gl.GL_TEXTURE_2D);
Assert.AreEqual(Gl.GL_TEXTURE_2D, glTexture.Target);
}
#endregion
}

View File

@ -9,9 +9,9 @@
</PropertyGroup>
<ItemGroup Label="Package references">
<PackageReference Include="Mediapipe.Net.Framework.Protobuf" Version="0.8.9" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="0.8.9.1" />
<!-- <PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="0.8.9.1" /> -->
<PackageReference Include="Mediapipe.Net.Framework.Protobuf" Version="1.0.0-alpha2" />
<PackageReference Include="Mediapipe.Net.Runtime.CPU" Version="1.0.0-alpha2" />
<!-- <PackageReference Include="Mediapipe.Net.Runtime.GPU" Version="1.0.0-alpha2" /> -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />

View File

@ -10,7 +10,17 @@ namespace Mediapipe.Net.Core
{
public unsafe abstract class MpResourceHandle : Disposable, IMpResourceHandle
{
protected void* Ptr;
private void* ptr = null;
protected void* Ptr
{
get => ptr;
set
{
if (value != null && OwnsResource)
throw new InvalidOperationException($"This object owns another resource");
ptr = value;
}
}
protected MpResourceHandle(bool isOwner = true) : this(null, isOwner) { }
@ -34,10 +44,12 @@ namespace Mediapipe.Net.Core
if (OwnsResource)
DeleteMpPtr();
ReleaseMpPtr();
TransferOwnership();
}
public bool OwnsResource => IsOwner && Ptr != null;
protected bool IsResourcePresent => Ptr != null;
public bool OwnsResource => IsOwner && IsResourcePresent;
#endregion
protected override void DisposeUnmanaged()
@ -62,11 +74,14 @@ namespace Mediapipe.Net.Core
protected abstract void DeleteMpPtr();
protected delegate MpReturnCode StringOutFunc(void* ptr, out sbyte* strPtr);
protected string MarshalStringFromNative(StringOutFunc func)
protected string? MarshalStringFromNative(StringOutFunc func)
{
func(MpPtr, out sbyte* strPtr).Assert();
GC.KeepAlive(this);
if (strPtr == null)
return null;
string str = new string(strPtr);
UnsafeNativeMethods.delete_array__PKc(strPtr);

View File

@ -2,11 +2,47 @@
// This file is part of MediaPipe.NET.
// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
using System;
using Mediapipe.Net.Native;
namespace Mediapipe.Net.External
{
internal static class Protobuf
public static class Protobuf
{
public delegate void ProtobufLogHandler(int level, string filename, int line, string message);
// TODO: (from homuler) Overwrite protobuf logger to show logs in Console Window.
public delegate void LogHandler(int level, string filename, int line, string message);
public static readonly LogHandler DefaultLogHandler = logProtobufMessage;
public static void SetLogHandler(LogHandler logHandler)
{
UnsafeNativeMethods.google_protobuf__SetLogHandler__PF(logHandler).Assert();
}
/// <summary>
/// Reset the <see cref="LogHandler" />.
/// If <see cref="SetLogHandler" /> is called, this method should be called before the program exits.
/// </summary>
public static void ResetLogHandler()
{
UnsafeNativeMethods.google_protobuf__ResetLogHandler().Assert();
}
private static void logProtobufMessage(int level, string filename, int line, string message)
{
switch (level)
{
case 1:
Console.Error.WriteLine($"[libprotobuf WARN {filename}:{line}] {message}");
break;
case 2:
Console.Error.WriteLine($"[libprotobuf ERROR {filename}:{line}] {message}");
break;
case 3:
Console.Error.WriteLine($"[libprotobuf FATAL {filename}:{line}] {message}");
break;
default:
Console.Error.WriteLine($"[libprotobuf INFO {filename}:{line}] {message}");
break;
}
}
}
}

View File

@ -10,10 +10,10 @@ using Mediapipe.Net.Util;
namespace Mediapipe.Net.External
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct SerializedProto
internal unsafe readonly struct SerializedProto
{
public sbyte* StrPtr;
public int Length;
public readonly sbyte* StrPtr;
public readonly int Length;
// TODO: That Dispose() method is looking very sus...
// Might wanna investigate if it's better as a child of Disposable.

View File

@ -10,19 +10,13 @@ using Mediapipe.Net.Native;
namespace Mediapipe.Net.External
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct SerializedProtoVector
internal unsafe readonly struct SerializedProtoVector
{
public SerializedProto* Data;
public int Size;
public readonly SerializedProto* Data;
public readonly int Size;
// TODO: This is looking just as sus as SerializedProto.Dispose().
// Should be investigated in the same way.
public void Dispose()
{
for (int i = 0; i < Size; i++)
Data[i].Dispose();
UnsafeNativeMethods.mp_api_SerializedProtoArray__delete(Data);
}
// The array element freeing loop has been moved to MediaPipe.NET.Runtime.
public void Dispose() => UnsafeNativeMethods.mp_api_SerializedProtoArray__delete(Data, Size);
public List<T> Deserialize<T>(MessageParser<T> parser) where T : IMessage<T>
{

View File

@ -17,8 +17,8 @@ namespace Mediapipe.Net.Framework
{
public unsafe class CalculatorGraph : MpResourceHandle
{
public delegate void* NativePacketCallback(void* graphPtr, void* packetPtr);
public delegate Status PacketCallback(Packet packet);
public delegate Status.StatusArgs NativePacketCallback(void* graphPtr, int streamId, void* packetPtr);
public delegate void PacketCallback(Packet packet);
public CalculatorGraph() : base()
{
@ -26,13 +26,7 @@ namespace Mediapipe.Net.Framework
Ptr = ptr;
}
public CalculatorGraph(string textFormatConfig) : base()
{
UnsafeNativeMethods.mp_CalculatorGraph__PKc(textFormatConfig, out var ptr).Assert();
Ptr = ptr;
}
public CalculatorGraph(byte[] serializedConfig) : base()
private CalculatorGraph(byte[] serializedConfig) : base()
{
UnsafeNativeMethods.mp_CalculatorGraph__PKc_i(serializedConfig, serializedConfig.Length, out var ptr).Assert();
Ptr = ptr;
@ -40,6 +34,8 @@ namespace Mediapipe.Net.Framework
public CalculatorGraph(CalculatorGraphConfig config) : this(config.ToByteArray()) { }
public CalculatorGraph(string textFormatConfig) : this(CalculatorGraphConfig.Parser.ParseFromTextFormat(textFormatConfig)) { }
protected override void DeleteMpPtr() => UnsafeNativeMethods.mp_CalculatorGraph__delete(Ptr);
public Status Initialize(CalculatorGraphConfig config)
@ -72,9 +68,9 @@ namespace Mediapipe.Net.Framework
return config;
}
public Status ObserveOutputStream(string streamName, NativePacketCallback nativePacketCallback, bool observeTimestampBounds = false)
public Status ObserveOutputStream(string streamName, int streamId, NativePacketCallback nativePacketCallback, bool observeTimestampBounds = false)
{
UnsafeNativeMethods.mp_CalculatorGraph__ObserveOutputStream__PKc_PF_b(MpPtr, streamName, nativePacketCallback, observeTimestampBounds, out var statusPtr).Assert();
UnsafeNativeMethods.mp_CalculatorGraph__ObserveOutputStream__PKc_PF_b(MpPtr, streamName, streamId, nativePacketCallback, observeTimestampBounds, out var statusPtr).Assert();
GC.KeepAlive(this);
return new Status(statusPtr);
@ -82,24 +78,25 @@ namespace Mediapipe.Net.Framework
public Status ObserveOutputStream(string streamName, PacketCallback packetCallback, bool observeTimestampBounds, out GCHandle callbackHandle)
{
NativePacketCallback nativePacketCallback = (_, packetPtr) =>
NativePacketCallback nativePacketCallback = (void* graphPtr, int streamId, void* packetPtr) =>
{
Status status;
try
{
Packet packet = new Packet(packetPtr, false);
status = packetCallback(packet);
packetCallback(packet);
// This packet is not being disposed in MediaPipeUnityPlugin?
packet.Dispose();
return Status.StatusArgs.Ok();
}
catch (Exception e)
{
status = Status.FailedPrecondition(e.ToString());
return Status.StatusArgs.Internal(e.ToString());
}
return status.MpPtr;
};
callbackHandle = GCHandle.Alloc(nativePacketCallback, GCHandleType.Normal);
return ObserveOutputStream(streamName, nativePacketCallback, observeTimestampBounds);
// Thought: why have a streamId at all if we just put 0 in there?
return ObserveOutputStream(streamName, 0, nativePacketCallback, observeTimestampBounds);
}
public Status ObserveOutputStream(string streamName, PacketCallback packetCallback, out GCHandle callbackHandle)

View File

@ -1,23 +0,0 @@
// 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.
namespace Mediapipe.Net.Framework.Format
{
public enum ImageFormat : int
{
Unknown = 0,
Srgb = 1,
Srgba = 2,
Gray8 = 3,
Gray16 = 4,
Ycbcr420p = 5,
Ycbcr420p10 = 6,
Srgb48 = 7,
Srgba64 = 8,
Vec32f1 = 9,
Vec32f2 = 12,
Lab8 = 10,
Sbgra = 11,
}
}

View File

@ -3,8 +3,8 @@
// 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.Framework.Protobuf;
using Mediapipe.Net.Native;
namespace Mediapipe.Net.Framework.Format
@ -22,15 +22,15 @@ namespace Mediapipe.Net.Framework.Format
public ImageFrame(void* imageFramePtr, bool isOwner = true) : base(imageFramePtr, isOwner) { }
public ImageFrame(ImageFormat format, int width, int height) : this(format, width, height, DefaultAlignmentBoundary) { }
public ImageFrame(ImageFormat.Types.Format format, int width, int height) : this(format, width, height, DefaultAlignmentBoundary) { }
public ImageFrame(ImageFormat format, int width, int height, uint alignmentBoundary) : base()
public ImageFrame(ImageFormat.Types.Format format, int width, int height, uint alignmentBoundary) : base()
{
UnsafeNativeMethods.mp_ImageFrame__ui_i_i_ui(format, width, height, alignmentBoundary, out var ptr).Assert();
Ptr = ptr;
}
public unsafe ImageFrame(ImageFormat format, int width, int height, int widthStep, byte[] pixelData) : base()
public unsafe ImageFrame(ImageFormat.Types.Format format, int width, int height, int widthStep, byte[] pixelData) : base()
{
fixed (byte* pixelDataPtr = pixelData)
{
@ -42,7 +42,7 @@ namespace Mediapipe.Net.Framework.Format
}
}
public ImageFrame(ImageFormat format, int width, int height, int widthStep, ReadOnlySpan<byte> pixelData) : base()
public ImageFrame(ImageFormat.Types.Format format, int width, int height, int widthStep, ReadOnlySpan<byte> pixelData) : base()
{
fixed (byte* pixelDataPtr = pixelData)
{
@ -56,6 +56,111 @@ namespace Mediapipe.Net.Framework.Format
protected override void DeleteMpPtr() => UnsafeNativeMethods.mp_ImageFrame__delete(Ptr);
/// <returns>
/// The number of channels for a <paramref name="format" />.
/// If channels don't make sense in the <paramref name="format" />, returns <c>0</c>.
/// </returns>
/// <remarks>
/// Unlike the original implementation, this API won't signal SIGABRT.
/// </remarks>
public static int NumberOfChannelsForFormat(ImageFormat.Types.Format format)
{
switch (format)
{
case ImageFormat.Types.Format.Srgb:
case ImageFormat.Types.Format.Srgb48:
return 3;
case ImageFormat.Types.Format.Srgba:
case ImageFormat.Types.Format.Srgba64:
case ImageFormat.Types.Format.Sbgra:
return 4;
case ImageFormat.Types.Format.Gray8:
case ImageFormat.Types.Format.Gray16:
return 1;
case ImageFormat.Types.Format.Vec32F1:
return 1;
case ImageFormat.Types.Format.Vec32F2:
return 2;
case ImageFormat.Types.Format.Lab8:
return 3;
case ImageFormat.Types.Format.Ycbcr420P:
case ImageFormat.Types.Format.Ycbcr420P10:
case ImageFormat.Types.Format.Unknown:
default:
return 0;
}
}
/// <returns>
/// The channel size for a <paramref name="format" />.
/// If channels don't make sense in the <paramref name="format" />, returns <c>0</c>.
/// </returns>
/// <remarks>
/// Unlike the original implementation, this API won't signal SIGABRT.
/// </remarks>
public static int ChannelSizeForFormat(ImageFormat.Types.Format format)
{
switch (format)
{
case ImageFormat.Types.Format.Srgb:
case ImageFormat.Types.Format.Srgba:
case ImageFormat.Types.Format.Sbgra:
return sizeof(byte);
case ImageFormat.Types.Format.Srgb48:
case ImageFormat.Types.Format.Srgba64:
return sizeof(ushort);
case ImageFormat.Types.Format.Gray8:
return sizeof(byte);
case ImageFormat.Types.Format.Gray16:
return sizeof(ushort);
case ImageFormat.Types.Format.Vec32F1:
case ImageFormat.Types.Format.Vec32F2:
// sizeof float may be wrong since it's platform-dependent, but we assume that it's constant across all supported platforms.
return sizeof(float);
case ImageFormat.Types.Format.Lab8:
return sizeof(byte);
case ImageFormat.Types.Format.Ycbcr420P:
case ImageFormat.Types.Format.Ycbcr420P10:
case ImageFormat.Types.Format.Unknown:
default:
return 0;
}
}
/// <returns>
/// The depth of each channel in bytes for a <paramref name="format" />.
/// If channels don't make sense in the <paramref name="format" />, returns <c>0</c>.
/// </returns>
/// <remarks>
/// Unlike the original implementation, this API won't signal SIGABRT.
/// </remarks>
public static int ByteDepthForFormat(ImageFormat.Types.Format format)
{
switch (format)
{
case ImageFormat.Types.Format.Srgb:
case ImageFormat.Types.Format.Srgba:
case ImageFormat.Types.Format.Sbgra:
return 1;
case ImageFormat.Types.Format.Srgb48:
case ImageFormat.Types.Format.Srgba64:
return 2;
case ImageFormat.Types.Format.Gray8:
return 1;
case ImageFormat.Types.Format.Gray16:
return 2;
case ImageFormat.Types.Format.Vec32F1:
case ImageFormat.Types.Format.Vec32F2:
return 4;
case ImageFormat.Types.Format.Lab8:
return 1;
case ImageFormat.Types.Format.Ycbcr420P:
case ImageFormat.Types.Format.Ycbcr420P10:
case ImageFormat.Types.Format.Unknown:
default:
return 0;
}
}
public bool IsEmpty => SafeNativeMethods.mp_ImageFrame__IsEmpty(MpPtr) > 0;
public bool IsContiguous => SafeNativeMethods.mp_ImageFrame__IsContiguous(MpPtr) > 0;
@ -68,61 +173,46 @@ namespace Mediapipe.Net.Framework.Format
return value;
}
public ImageFormat Format => SafeNativeMethods.mp_ImageFrame__Format(MpPtr);
public ImageFormat.Types.Format Format => SafeNativeMethods.mp_ImageFrame__Format(MpPtr);
public int Width => SafeNativeMethods.mp_ImageFrame__Width(MpPtr);
public int Height => SafeNativeMethods.mp_ImageFrame__Height(MpPtr);
public int ChannelSize
{
get
{
var code = SafeNativeMethods.mp_ImageFrame__ChannelSize(MpPtr, out var value);
/// <returns>
/// The channel size.
/// If channels don't make sense, returns <c>0</c>.
/// </returns>
/// <remarks>
/// Unlike the original implementation, this API won't signal SIGABRT.
/// </remarks>
public int ChannelSize => ChannelSizeForFormat(Format);
GC.KeepAlive(this);
return valueOrFormatException(code, value);
}
}
/// <returns>
/// The Number of channels.
/// If channels don't make sense, returns <c>0</c>.
/// </returns>
/// <remarks>
/// Unlike the original implementation, this API won't signal SIGABRT.
/// </remarks>
public int NumberOfChannels => NumberOfChannelsForFormat(Format);
public int NumberOfChannels
{
get
{
var code = SafeNativeMethods.mp_ImageFrame__NumberOfChannels(MpPtr, out var value);
GC.KeepAlive(this);
return valueOrFormatException(code, value);
}
}
public int ByteDepth
{
get
{
var code = SafeNativeMethods.mp_ImageFrame__ByteDepth(MpPtr, out var value);
GC.KeepAlive(this);
return valueOrFormatException(code, value);
}
}
/// <returns>
/// The depth of each image channel in bytes.
/// If channels don't make sense, returns <c>0</c>.
/// </returns>
/// <remarks>
/// Unlike the original implementation, this API won't signal SIGABRT.
/// </remarks>
public int ByteDepth => ByteDepthForFormat(Format);
public int WidthStep => SafeNativeMethods.mp_ImageFrame__WidthStep(MpPtr);
public byte* MutablePixelData => SafeNativeMethods.mp_ImageFrame__MutablePixelData(MpPtr);
public int PixelDataSize => SafeNativeMethods.mp_ImageFrame__PixelDataSize(MpPtr);
public int PixelDataSize => Height * WidthStep;
public int PixelDataSizeStoredContiguously
{
get
{
var code = SafeNativeMethods.mp_ImageFrame__PixelDataSizeStoredContiguously(MpPtr, out var value);
GC.KeepAlive(this);
return valueOrFormatException(code, value);
}
}
public int PixelDataSizeStoredContiguously => Width * Height * ByteDepth * NumberOfChannels;
public void SetToZero()
{
@ -136,140 +226,30 @@ namespace Mediapipe.Net.Framework.Format
GC.KeepAlive(this);
}
public byte[] CopyToByteBuffer(int bufferSize)
=> copyToBuffer<byte>(UnsafeNativeMethods.mp_ImageFrame__CopyToBuffer__Pui8_i, bufferSize);
public void CopyToBuffer(byte[] buffer)
=> copyToBuffer(UnsafeNativeMethods.mp_ImageFrame__CopyToBuffer__Pui8_i, buffer);
public ushort[] CopyToUshortBuffer(int bufferSize)
=> copyToBuffer<ushort>(UnsafeNativeMethods.mp_ImageFrame__CopyToBuffer__Pui16_i, bufferSize);
public void CopyToBuffer(ushort[] buffer)
=> copyToBuffer(UnsafeNativeMethods.mp_ImageFrame__CopyToBuffer__Pui16_i, buffer);
public float[] CopyToFloatBuffer(int bufferSize)
=> copyToBuffer<float>(UnsafeNativeMethods.mp_ImageFrame__CopyToBuffer__Pf_i, bufferSize);
/// <summary>
/// Get the value of a specific channel only.
/// It's useful when only one channel is used (e.g. Hair Segmentation mask).
/// </summary>
/// <param name="channelNumber">
/// Specify from which channel the data will be retrieved.
/// For example, if the format is RGB, 0 means R channel, 1 means G channel, and 2 means B channel.
/// </param>
/// <param name="colors" >
/// The array to which the output data will be written.
/// </param>
public byte[] GetChannel(int channelNumber, bool flipVertically, byte[] colors)
{
var format = Format;
switch (format)
{
case ImageFormat.Srgb:
if (channelNumber < 0 || channelNumber > 3)
throw new ArgumentException($"There are only 3 channels, but No. {channelNumber} is specified");
readChannel(MutablePixelData, channelNumber, 3, Width, Height, WidthStep, flipVertically, colors);
return colors;
case ImageFormat.Srgba:
if (channelNumber < 0 || channelNumber > 4)
throw new ArgumentException($"There are only 4 channels, but No. {channelNumber} is specified");
readChannel(MutablePixelData, channelNumber, 4, Width, Height, WidthStep, flipVertically, colors);
return colors;
default:
throw new NotImplementedException($"Currently only SRGB and SRGBA format are supported: {format}");
}
}
/// <summary>
/// Get the value of a specific channel only.
/// It's useful when only one channel is used (e.g. Hair Segmentation mask).
/// </summary>
/// <param name="channelNumber">
/// Specify from which channel the data will be retrieved.
/// For example, if the format is RGB, 0 means R channel, 1 means G channel, and 2 means B channel.
/// </param>
public byte[] GetChannel(int channelNumber, bool flipVertically)
=> GetChannel(channelNumber, flipVertically, new byte[Width * Height]);
public void CopyToBuffer(float[] buffer)
=> copyToBuffer(UnsafeNativeMethods.mp_ImageFrame__CopyToBuffer__Pf_i, buffer);
private delegate MpReturnCode CopyToBufferHandler<T>(void* ptr, T* buffer, int bufferSize)
where T : unmanaged;
private T[] copyToBuffer<T>(CopyToBufferHandler<T> handler, int bufferSize)
private void copyToBuffer<T>(CopyToBufferHandler<T> handler, T[] buffer)
where T : unmanaged
{
var buffer = new T[bufferSize];
unsafe
{
fixed (T* bufferPtr = buffer)
{
handler(MpPtr, bufferPtr, bufferSize).Assert();
handler(MpPtr, bufferPtr, buffer.Length).Assert();
}
}
GC.KeepAlive(this);
return buffer;
}
private T valueOrFormatException<T>(MpReturnCode code, T value)
{
try
{
code.Assert();
return value;
}
catch (MediapipeException)
{
throw new FormatException($"Invalid image format: {Format}");
}
}
/// <remarks>
/// In the source array, pixels are laid out left to right, top to bottom,
/// but in the returned array, left to right, top to bottom.
/// </remarks>
private static void readChannel(byte* ptr, int channelNumber, int channelCount, int width, int height, int widthStep, bool flipVertically, byte[] colors)
{
if (colors.Length != width * height)
throw new ArgumentException("colors length is invalid");
var padding = widthStep - channelCount * width;
unsafe
{
fixed (byte* dest = colors)
{
var pSrc = ptr;
pSrc += channelNumber;
if (flipVertically)
{
var pDest = dest + colors.Length - 1;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
*pDest-- = *pSrc;
pSrc += channelCount;
}
pSrc += padding;
}
}
else
{
var pDest = dest + width * (height - 1);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
*pDest++ = *pSrc;
pSrc += channelCount;
}
pSrc += padding;
pDest -= 2 * width;
}
}
}
}
}
}
}

View File

@ -136,6 +136,14 @@ namespace Mediapipe.Net.Framework.Packets
GC.KeepAlive(this);
return new StatusOrGpuBuffer(statusOrGpuBufferPtr);
}
public StatusOr<string> ConsumeString()
{
UnsafeNativeMethods.mp_Packet__ConsumeString(MpPtr, out var statusOrStringPtr).Assert();
GC.KeepAlive(this);
return new StatusOrString(statusOrStringPtr);
}
#endregion
#region Validators

View File

@ -2,6 +2,8 @@
// This file is part of MediaPipe.NET.
// 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;
@ -30,6 +32,69 @@ namespace Mediapipe.Net.Framework.Port
Unauthenticated = 16,
}
[StructLayout(LayoutKind.Sequential)]
public readonly struct StatusArgs
{
private readonly StatusCode code;
private readonly IntPtr message;
private StatusArgs(StatusCode code, string? message = null)
{
this.code = code;
this.message = Marshal.StringToHGlobalAnsi(message);
}
public static StatusArgs Ok() => new StatusArgs(StatusCode.Ok);
public static StatusArgs Cancelled(string? message = null)
=> new StatusArgs(StatusCode.Cancelled, message);
public static StatusArgs Unknown(string? message = null)
=> new StatusArgs(StatusCode.Unknown, message);
public static StatusArgs InvalidArgument(string? message = null)
=> new StatusArgs(StatusCode.InvalidArgument, message);
public static StatusArgs DeadlineExceeded(string? message = null)
=> new StatusArgs(StatusCode.DeadlineExceeded, message);
public static StatusArgs NotFound(string? message = null)
=> new StatusArgs(StatusCode.NotFound, message);
public static StatusArgs AlreadyExists(string? message = null)
=> new StatusArgs(StatusCode.AlreadyExists, message);
public static StatusArgs PermissionDenied(string? message = null)
=> new StatusArgs(StatusCode.PermissionDenied, message);
public static StatusArgs ResourceExhausted(string? message = null)
=> new StatusArgs(StatusCode.ResourceExhausted, message);
public static StatusArgs FailedPrecondition(string? message = null)
=> new StatusArgs(StatusCode.FailedPrecondition, message);
public static StatusArgs Aborted(string? message = null)
=> new StatusArgs(StatusCode.Aborted, message);
public static StatusArgs OutOfRange(string? message = null)
=> new StatusArgs(StatusCode.OutOfRange, message);
public static StatusArgs Unimplemented(string? message = null)
=> new StatusArgs(StatusCode.Unimplemented, message);
public static StatusArgs Internal(string? message = null)
=> new StatusArgs(StatusCode.Internal, message);
public static StatusArgs Unavailable(string? message = null)
=> new StatusArgs(StatusCode.Unavailable, message);
public static StatusArgs DataLoss(string? message = null)
=> new StatusArgs(StatusCode.DataLoss, message);
public static StatusArgs Unauthenticated(string? message = null)
=> new StatusArgs(StatusCode.Unauthenticated, message);
}
public Status(void* ptr, bool isOwner = true) : base(ptr, isOwner) { }
protected override void DeleteMpPtr() => UnsafeNativeMethods.absl_Status__delete(Ptr);
@ -76,7 +141,52 @@ namespace Mediapipe.Net.Framework.Port
public static Status Ok(bool isOwner = true) => Build(StatusCode.Ok, "", isOwner);
public static Status Cancelled(string message = "", bool isOwner = true)
=> Build(StatusCode.Cancelled, message, isOwner);
public static Status Unknown(string message = "", bool isOwner = true)
=> Build(StatusCode.Unknown, message, isOwner);
public static Status InvalidArgument(string message = "", bool isOwner = true)
=> Build(StatusCode.InvalidArgument, message, isOwner);
public static Status DeadlineExceeded(string message = "", bool isOwner = true)
=> Build(StatusCode.DeadlineExceeded, message, isOwner);
public static Status NotFound(string message = "", bool isOwner = true)
=> Build(StatusCode.NotFound, message, isOwner);
public static Status AlreadyExists(string message = "", bool isOwner = true)
=> Build(StatusCode.AlreadyExists, message, isOwner);
public static Status PermissionDenied(string message = "", bool isOwner = true)
=> Build(StatusCode.PermissionDenied, message, isOwner);
public static Status ResourceExhausted(string message = "", bool isOwner = true)
=> Build(StatusCode.ResourceExhausted, message, isOwner);
public static Status FailedPrecondition(string message = "", bool isOwner = true)
=> Build(StatusCode.FailedPrecondition, message, isOwner);
public static Status Aborted(string message = "", bool isOwner = true)
=> Build(StatusCode.Aborted, message, isOwner);
public static Status OutOfRange(string message = "", bool isOwner = true)
=> Build(StatusCode.OutOfRange, message, isOwner);
public static Status Unimplemented(string message = "", bool isOwner = true)
=> Build(StatusCode.Unimplemented, message, isOwner);
public static Status Internal(string message = "", bool isOwner = true)
=> Build(StatusCode.Internal, message, isOwner);
public static Status Unavailable(string message = "", bool isOwner = true)
=> Build(StatusCode.Unavailable, message, isOwner);
public static Status DataLoss(string message = "", bool isOwner = true)
=> Build(StatusCode.DataLoss, message, isOwner);
public static Status Unauthenticated(string message = "", bool isOwner = true)
=> Build(StatusCode.Unauthenticated, message, isOwner);
}
}

View File

@ -16,6 +16,6 @@ namespace Mediapipe.Net.Framework.Port
public virtual T? ValueOr(T? defaultValue = default) => Ok() ? Value() : defaultValue;
/// <exception cref="MediapipeNetException">Thrown when status is not ok</exception>
public abstract T Value();
public abstract T? Value();
}
}

View File

@ -0,0 +1,58 @@
// 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 Mediapipe.Net.Native;
using Mediapipe.Net.Util;
namespace Mediapipe.Net.Framework.Port
{
public unsafe class StatusOrString : StatusOr<string>
{
public StatusOrString(void* ptr) : base(ptr) { }
protected override void DeleteMpPtr()
{
UnsafeNativeMethods.mp_StatusOrString__delete(Ptr);
}
private Status? status;
public override Status Status
{
get
{
if (status == null || status.IsDisposed)
{
UnsafeNativeMethods.mp_StatusOrString__status(MpPtr, out var statusPtr).Assert();
GC.KeepAlive(this);
status = new Status(statusPtr);
}
return status;
}
}
public override bool Ok() => SafeNativeMethods.mp_StatusOrString__ok(MpPtr) > 0;
public override string? Value()
{
var str = MarshalStringFromNative(UnsafeNativeMethods.mp_StatusOrString__value);
Dispose(); // respect move semantics
return str;
}
public byte[] ValueAsByteArray()
{
UnsafeNativeMethods.mp_StatusOrString__bytearray(MpPtr, out var strPtr, out var size).Assert();
GC.KeepAlive(this);
byte[] bytes = UnsafeUtil.SafeArrayCopy((byte*)strPtr, size);
UnsafeNativeMethods.delete_array__PKc(strPtr);
Dispose();
return bytes;
}
}
}

View File

@ -0,0 +1,25 @@
// 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.Runtime.InteropServices;
namespace Mediapipe.Net.Framework.ValidatedGraphConfig
{
[StructLayout(LayoutKind.Sequential)]
public readonly struct EdgeInfo
{
public readonly int Upstream;
public readonly NodeRef ParentNode;
public readonly string? Name;
public readonly bool BackEdge;
internal EdgeInfo(int upstream, NodeRef parentNode, string? name, bool backEdge)
{
Upstream = upstream;
ParentNode = parentNode;
Name = name;
BackEdge = backEdge;
}
}
}

View File

@ -0,0 +1,55 @@
// 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.Collections.Generic;
using System.Runtime.InteropServices;
using Mediapipe.Net.Native;
namespace Mediapipe.Net.Framework.ValidatedGraphConfig
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe readonly struct EdgeInfoVector
{
private readonly void* data;
private readonly int size;
public void Dispose() => UnsafeNativeMethods.mp_api_EdgeInfoArray__delete(data, size);
public List<EdgeInfo> Copy()
{
var edgeInfos = new List<EdgeInfo>(size);
unsafe
{
var edgeInfoPtr = (EdgeInfoTmp*)data;
for (int i = 0; i < size; i++)
{
EdgeInfoTmp edgeInfoTmp = Marshal.PtrToStructure<EdgeInfoTmp>((IntPtr)edgeInfoPtr++);
edgeInfos.Add(edgeInfoTmp.Copy());
}
}
return edgeInfos;
}
[StructLayout(LayoutKind.Sequential)]
private readonly struct EdgeInfoTmp
{
private readonly int upstream;
private readonly NodeRef parentNode;
private readonly IntPtr name;
[MarshalAs(UnmanagedType.U1)]
private readonly bool backEdge;
public EdgeInfo Copy()
{
string? name = Marshal.PtrToStringAnsi(this.name);
return new EdgeInfo(upstream, parentNode, name, backEdge);
}
}
}
}

View File

@ -0,0 +1,15 @@
// 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.Runtime.InteropServices;
namespace Mediapipe.Net.Framework.ValidatedGraphConfig
{
[StructLayout(LayoutKind.Sequential)]
public readonly struct NodeRef
{
public readonly NodeType Type;
public readonly int Index;
}
}

View File

@ -0,0 +1,15 @@
// 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.
namespace Mediapipe.Net.Framework.ValidatedGraphConfig
{
public enum NodeType : int
{
Unknown = 0,
Calculator = 1,
PacketGenerator = 2,
GraphInputStream = 3,
StatusHandler = 4,
};
}

View File

@ -0,0 +1,139 @@
// 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.Collections.Generic;
using Google.Protobuf;
using Mediapipe.Net.Core;
using Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Port;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Native;
namespace Mediapipe.Net.Framework.ValidatedGraphConfig
{
public unsafe class ValidatedGraphConfig : MpResourceHandle
{
public ValidatedGraphConfig() : base()
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__(out var ptr).Assert();
Ptr = ptr;
}
protected override void DeleteMpPtr() => UnsafeNativeMethods.mp_ValidatedGraphConfig__delete(Ptr);
public Status Initialize(CalculatorGraphConfig config)
{
var bytes = config.ToByteArray();
UnsafeNativeMethods.mp_ValidatedGraphConfig__Initialize__Rcgc(MpPtr, bytes, bytes.Length, out var statusPtr).Assert();
GC.KeepAlive(this);
return new Status(statusPtr);
}
public Status Initialize(string graphType)
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__Initialize__PKc(MpPtr, graphType, out var statusPtr).Assert();
GC.KeepAlive(this);
return new Status(statusPtr);
}
public bool Initialized() => SafeNativeMethods.mp_ValidatedGraphConfig__Initialized(MpPtr) > 0;
public Status ValidateRequiredSidePackets(SidePackets sidePackets)
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__ValidateRequiredSidePackets__Rsp(MpPtr, sidePackets.MpPtr, out var statusPtr).Assert();
GC.KeepAlive(sidePackets);
GC.KeepAlive(this);
return new Status(statusPtr);
}
public CalculatorGraphConfig Config(ExtensionRegistry? extensionRegistry = null)
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__Config(MpPtr, out var serializedProto).Assert();
GC.KeepAlive(this);
var parser = extensionRegistry == null ? CalculatorGraphConfig.Parser : CalculatorGraphConfig.Parser.WithExtensionRegistry(extensionRegistry);
var config = serializedProto.Deserialize(parser);
serializedProto.Dispose();
return config;
}
public List<EdgeInfo> InputStreamInfos()
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__InputStreamInfos(MpPtr, out var edgeInfoVector).Assert();
GC.KeepAlive(this);
var edgeInfos = edgeInfoVector.Copy();
edgeInfoVector.Dispose();
return edgeInfos;
}
public List<EdgeInfo> OutputStreamInfos()
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__OutputStreamInfos(MpPtr, out var edgeInfoVector).Assert();
GC.KeepAlive(this);
var edgeInfos = edgeInfoVector.Copy();
edgeInfoVector.Dispose();
return edgeInfos;
}
public List<EdgeInfo> InputSidePacketInfos()
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__InputSidePacketInfos(MpPtr, out var edgeInfoVector).Assert();
GC.KeepAlive(this);
var edgeInfos = edgeInfoVector.Copy();
edgeInfoVector.Dispose();
return edgeInfos;
}
public List<EdgeInfo> OutputSidePacketInfos()
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__OutputSidePacketInfos(MpPtr, out var edgeInfoVector).Assert();
GC.KeepAlive(this);
var edgeInfos = edgeInfoVector.Copy();
edgeInfoVector.Dispose();
return edgeInfos;
}
public int OutputStreamIndex(string name)
=> SafeNativeMethods.mp_ValidatedGraphConfig__OutputStreamIndex__PKc(MpPtr, name);
public int OutputSidePacketIndex(string name)
=> SafeNativeMethods.mp_ValidatedGraphConfig__OutputSidePacketIndex__PKc(MpPtr, name);
public int OutputStreamToNode(string name)
=> SafeNativeMethods.mp_ValidatedGraphConfig__OutputStreamToNode__PKc(MpPtr, name);
public StatusOrString RegisteredSidePacketTypeName(string name)
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__RegisteredSidePacketTypeName(MpPtr, name, out var statusOrStringPtr).Assert();
GC.KeepAlive(this);
return new StatusOrString(statusOrStringPtr);
}
public StatusOrString RegisteredStreamTypeName(string name)
{
UnsafeNativeMethods.mp_ValidatedGraphConfig__RegisteredStreamTypeName(MpPtr, name, out var statusOrStringPtr).Assert();
GC.KeepAlive(this);
return new StatusOrString(statusOrStringPtr);
}
public string? Package() => MarshalStringFromNative(UnsafeNativeMethods.mp_ValidatedGraphConfig__Package);
public static bool IsReservedExecutorName(string name)
=> SafeNativeMethods.mp_ValidatedGraphConfig_IsReservedExecutorName(name) > 0;
public bool IsExternalSidePacket(string name)
=> SafeNativeMethods.mp_ValidatedGraphConfig__IsExternalSidePacket__PKc(MpPtr, name) > 0;
}
}

View File

@ -3,7 +3,6 @@
// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Mediapipe.Net.Core;
using Mediapipe.Net.Framework.Format;
@ -14,8 +13,8 @@ namespace Mediapipe.Net.Gpu
{
public unsafe class GlCalculatorHelper : MpResourceHandle
{
public delegate void* NativeGlStatusFunction();
public delegate Status GlStatusFunction();
public delegate Status.StatusArgs NativeGlStatusFunction();
public delegate void GlFunction();
public GlCalculatorHelper() : base()
{
@ -45,34 +44,20 @@ namespace Mediapipe.Net.Gpu
return new Status(statusPtr);
}
public Status RunInGlContext(GlStatusFunction glStatusFunc)
public Status RunInGlContext(GlFunction glFunction)
{
Status? tmpStatus = null;
NativeGlStatusFunction nativeGlStatusFunc = () =>
return RunInGlContext(() =>
{
try
{
tmpStatus = glStatusFunc();
glFunction();
return Status.StatusArgs.Ok();
}
catch (Exception e)
{
tmpStatus = Status.FailedPrecondition(e.ToString());
return Status.StatusArgs.Internal(e.ToString());
}
return tmpStatus.MpPtr;
};
// Was previously `GCHandleType.Pinned`. It had to be changed because
// the `NativeGlStatusFunction` delegate type is non-blittable.
// Using `GCHandleType.Normal` should be fine as it seems that all we
// need to do is to make sure that the delegate doesn't get garbage-collected.
var nativeGlStatusFuncHandle = GCHandle.Alloc(nativeGlStatusFunc, GCHandleType.Normal);
var status = RunInGlContext(nativeGlStatusFunc);
nativeGlStatusFuncHandle.Free();
if (tmpStatus != null)
tmpStatus.Dispose();
return status;
});
}
public GlTexture CreateSourceTexture(ImageFrame imageFrame)

View File

@ -12,7 +12,7 @@ namespace Mediapipe.Net.Gpu
{
private SharedPtrHandle? sharedPtrHandle;
public GlSyncPoint(void* ptr) : base(ptr)
public GlSyncPoint(void* ptr) : base()
{
sharedPtrHandle = new SharedGlSyncPointPtr(ptr);
Ptr = sharedPtrHandle.Get();

View File

@ -29,7 +29,7 @@ namespace Mediapipe.Net.Gpu
/// Make sure that this function doesn't throw exceptions and won't be GCed.
/// </param>
public GlTextureBuffer(uint target, uint name, int width, int height,
GpuBufferFormat format, DeletionCallback callback, GlContext? glContext)
GpuBufferFormat format, DeletionCallback callback, GlContext? glContext) : base()
{
var sharedContextPtr = glContext == null ? null : glContext.SharedPtr;
UnsafeNativeMethods.mp_SharedGlTextureBuffer__ui_ui_i_i_ui_PF_PSgc(

View File

@ -22,10 +22,6 @@ namespace Mediapipe.Net.Gpu
protected override void DeleteMpPtr() => UnsafeNativeMethods.mp_GpuBuffer__delete(Ptr);
[SupportedOSPlatform("Linux"), SupportedOSPlatform("Android")]
public GlTextureBuffer GetGlTextureBuffer()
=> new GlTextureBuffer(SafeNativeMethods.mp_GpuBuffer__GetGlTextureBufferSharedPtr(MpPtr), false);
public GpuBufferFormat Format => SafeNativeMethods.mp_GpuBuffer__format(MpPtr);
public int Width => SafeNativeMethods.mp_GpuBuffer__width(MpPtr);

View File

@ -2,14 +2,14 @@
// This file is part of MediaPipe.NET.
// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Native;
namespace Mediapipe.Net.Gpu
{
public static class GpuBufferFormatExtension
{
public static ImageFormat ImageFormatFor(this GpuBufferFormat gpuBufferFormat)
public static ImageFormat.Types.Format ImageFormatFor(this GpuBufferFormat gpuBufferFormat)
=> SafeNativeMethods.mp__ImageFormatForGpuBufferFormat__ui(gpuBufferFormat);
public static GlTextureInfo GlTextureInfoFor(this GpuBufferFormat gpuBufferFormat, int plane, GlVersion glVersion = GlVersion.KGles3)

View File

@ -11,7 +11,7 @@
<PropertyGroup Label="Nuget">
<IsPackable>true</IsPackable>
<PackageId>Mediapipe.Net</PackageId>
<Version>0.8.9.1</Version>
<Version>1.0.0-alpha2</Version>
<Authors>homuler;Vignette</Authors>
<PackageTags>Google;Mediapipe;Tracking;Media Analysis</PackageTags>
<Title>Mediapipe.Net</Title>
@ -22,8 +22,8 @@
</PropertyGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Google.Protobuf" Version="3.19.4" />
<PackageReference Include="Mediapipe.Net.Framework.Protobuf" Version="0.8.9" />
<PackageReference Include="Google.Protobuf" Version="3.21.3" />
<PackageReference Include="Mediapipe.Net.Framework.Protobuf" Version="1.0.0-alpha2" />
</ItemGroup>
<ItemGroup Label="Documents">

View File

@ -0,0 +1,15 @@
// 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.Diagnostics.Contracts;
using System.Runtime.InteropServices;
namespace Mediapipe.Net.Native
{
internal unsafe partial class SafeNativeMethods
{
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern byte mp_StatusOrString__ok(void* statusOrString);
}
}

View File

@ -4,7 +4,7 @@
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
namespace Mediapipe.Net.Native
{
@ -21,7 +21,7 @@ namespace Mediapipe.Net.Native
void* imageFrame, uint alignmentBoundary, out bool value);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern ImageFormat mp_ImageFrame__Format(void* imageFrame);
public static extern ImageFormat.Types.Format mp_ImageFrame__Format(void* imageFrame);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern int mp_ImageFrame__Width(void* imageFrame);

View File

@ -0,0 +1,33 @@
// 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.Diagnostics.Contracts;
using System.Runtime.InteropServices;
namespace Mediapipe.Net.Native
{
internal unsafe partial class SafeNativeMethods
{
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern byte mp_ValidatedGraphConfig__Initialized(void* config);
#pragma warning disable CA2101
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern int mp_ValidatedGraphConfig__OutputStreamIndex__PKc(void* config, string name);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern int mp_ValidatedGraphConfig__OutputSidePacketIndex__PKc(void* config, string name);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern int mp_ValidatedGraphConfig__OutputStreamToNode__PKc(void* config, string name);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern byte mp_ValidatedGraphConfig_IsReservedExecutorName(string name);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern byte mp_ValidatedGraphConfig__IsExternalSidePacket__PKc(void* config, string name);
#pragma warning restore CA2101
}
}

View File

@ -4,17 +4,12 @@
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Mediapipe.Net.Gpu;
namespace Mediapipe.Net.Native
{
internal unsafe partial class SafeNativeMethods : NativeMethods
{
[SupportedOSPlatform("Linux"), SupportedOSPlatform("Android")]
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void* mp_GpuBuffer__GetGlTextureBufferSharedPtr(void* gpuBuffer);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern int mp_GpuBuffer__width(void* gpuBuffer);

View File

@ -4,7 +4,7 @@
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
using Mediapipe.Net.Gpu;
namespace Mediapipe.Net.Native
@ -12,9 +12,9 @@ namespace Mediapipe.Net.Native
internal unsafe partial class SafeNativeMethods : NativeMethods
{
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern ImageFormat mp__ImageFormatForGpuBufferFormat__ui(GpuBufferFormat format);
public static extern ImageFormat.Types.Format mp__ImageFormatForGpuBufferFormat__ui(GpuBufferFormat format);
[Pure, DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern ImageFormat mp__GpuBufferFormatForImageFormat__ui(ImageFormat format);
public static extern ImageFormat.Types.Format mp__GpuBufferFormatForImageFormat__ui(ImageFormat.Types.Format format);
}
}

View File

@ -10,11 +10,13 @@ namespace Mediapipe.Net.Native
internal unsafe partial class UnsafeNativeMethods : NativeMethods
{
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode google_protobuf__SetLogHandler__PF(
Protobuf.ProtobufLogHandler logHandler);
public static extern MpReturnCode google_protobuf__SetLogHandler__PF(Protobuf.LogHandler logHandler);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void mp_api_SerializedProtoArray__delete(void* serializedProtoVectorData);
public static extern MpReturnCode google_protobuf__ResetLogHandler();
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void mp_api_SerializedProtoArray__delete(void* serializedProtoVectorData, int size);
#region MessageProto
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]

View File

@ -21,5 +21,19 @@ namespace Mediapipe.Net.Native
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void std_string__swap__Rstr(void* src, void* dst);
#endregion
#region StatusOrString
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void mp_StatusOrString__delete(void* statusOrString);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_StatusOrString__status(void* statusOrString, out void* status);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_StatusOrString__value(void* statusOrString, out sbyte* value);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_StatusOrString__bytearray(void* statusOrString, out sbyte* value, out int size);
#endregion
}
}

View File

@ -14,9 +14,6 @@ namespace Mediapipe.Net.Native
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_CalculatorGraph__(out void* graph);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern MpReturnCode mp_CalculatorGraph__PKc(string textFormatConfig, out void* graph);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_CalculatorGraph__PKc_i(byte[] serializedConfig, int size, out void* graph);
@ -35,7 +32,7 @@ namespace Mediapipe.Net.Native
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern MpReturnCode mp_CalculatorGraph__ObserveOutputStream__PKc_PF_b(void* graph, string streamName,
CalculatorGraph.NativePacketCallback packetCallback,
int streamId, CalculatorGraph.NativePacketCallback packetCallback,
bool observeTimestampBounds, out void* status);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]

View File

@ -3,7 +3,7 @@
// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
using System.Runtime.InteropServices;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Protobuf;
namespace Mediapipe.Net.Native
{
@ -14,11 +14,11 @@ namespace Mediapipe.Net.Native
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ImageFrame__ui_i_i_ui(
ImageFormat format, int width, int height, uint alignmentBoundary, out void* imageFrame);
ImageFormat.Types.Format format, int width, int height, uint alignmentBoundary, out void* imageFrame);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ImageFrame__ui_i_i_i_Pui8(
ImageFormat format, int width, int height, int widthStep, byte* pixelData,
ImageFormat.Types.Format format, int width, int height, int widthStep, byte* pixelData,
out void* imageFrame);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]

View File

@ -31,6 +31,9 @@ namespace Mediapipe.Net.Native
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_Packet__RegisteredTypeName(void* packet, out sbyte* str);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_Packet__ConsumeString(void* packet, out void* statusOrValue);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_Packet__DebugTypeName(void* packet, out sbyte* str);
#endregion

View File

@ -0,0 +1,59 @@
// 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.Runtime.InteropServices;
using Mediapipe.Net.External;
using Mediapipe.Net.Framework.ValidatedGraphConfig;
namespace Mediapipe.Net.Native
{
internal unsafe partial class UnsafeNativeMethods
{
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__(out void* config);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void mp_ValidatedGraphConfig__delete(void* config);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__Initialize__Rcgc(void* config, byte[] serializedConfig, int size, out void* status);
#pragma warning disable CA2101
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern MpReturnCode mp_ValidatedGraphConfig__Initialize__PKc(void* config, string graphType, out void* status);
#pragma warning restore CA2101
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__ValidateRequiredSidePackets__Rsp(void* config, void* sidePackets, out void* status);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__Config(void* config, out SerializedProto serializedProto);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__InputStreamInfos(void* config, out EdgeInfoVector edgeInfoVector);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__OutputStreamInfos(void* config, out EdgeInfoVector edgeInfoVector);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__InputSidePacketInfos(void* config, out EdgeInfoVector edgeInfoVector);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__OutputSidePacketInfos(void* config, out EdgeInfoVector edgeInfoVector);
#pragma warning disable CA2101
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern MpReturnCode mp_ValidatedGraphConfig__RegisteredSidePacketTypeName(void* config, string name, out void* statusOrString);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern MpReturnCode mp_ValidatedGraphConfig__RegisteredStreamTypeName(void* config, string name, out void* statusOrString);
#pragma warning restore CA2101
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern MpReturnCode mp_ValidatedGraphConfig__Package(void* config, out sbyte* str);
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
public static extern void mp_api_EdgeInfoArray__delete(void* data, int size);
}
}

View File

@ -0,0 +1,31 @@
// 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.Runtime.InteropServices;
namespace Mediapipe.Net.Native
{
internal unsafe partial class UnsafeNativeMethods : NativeMethods
{
// This is required to be a field in order to bypass the GC.
private static readonly FreeHGlobalDelegate freeHGlobalDelegate;
static UnsafeNativeMethods()
{
freeHGlobalDelegate = new FreeHGlobalDelegate(freeHGlobal);
mp_api__SetFreeHGlobal(freeHGlobalDelegate);
}
private delegate void FreeHGlobalDelegate(IntPtr hglobal);
private static void freeHGlobal(IntPtr hglobal)
{
Marshal.FreeHGlobal(hglobal);
}
[DllImport(MEDIAPIPE_LIBRARY, ExactSpelling = true)]
private static extern void mp_api__SetFreeHGlobal(FreeHGlobalDelegate freeHGlobal);
}
}

View File

@ -8,7 +8,6 @@ using Mediapipe.Net.Core;
using Mediapipe.Net.Framework;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Port;
using Mediapipe.Net.Gpu;
namespace Mediapipe.Net.Solutions
@ -50,8 +49,6 @@ namespace Mediapipe.Net.Solutions
Timestamp timestamp = new Timestamp(SimulatedTimestamp);
Packet packet = PacketFactory.GpuBufferPacket(gpuBuffer, timestamp);
inputs.Add(GpuBufferInput, packet);
return Status.Ok();
}).AssertOk();
return Process(inputs);
@ -74,8 +71,6 @@ namespace Mediapipe.Net.Solutions
}
Gl.Flush();
texture.Release();
return Status.Ok();
}).AssertOk();
if (outFrame == null)

View File

@ -10,7 +10,6 @@ using Mediapipe.Net.Core;
using Mediapipe.Net.Framework;
using Mediapipe.Net.Framework.Format;
using Mediapipe.Net.Framework.Packets;
using Mediapipe.Net.Framework.Port;
namespace Mediapipe.Net.Solutions
{
@ -49,7 +48,6 @@ namespace Mediapipe.Net.Solutions
packet.PacketType = packetType;
lock (GraphOutputs)
GraphOutputs.Add(output, packet.Get());
return Status.Ok();
}, out GCHandle handle).AssertOk();
observeStreamHandles.Add(output, handle);
}