From 6e9ccca3deebf3ca74ed25c41e619c07c5febd94 Mon Sep 17 00:00:00 2001 From: Speykious Date: Sun, 10 Jul 2022 01:48:52 +0200 Subject: [PATCH] Attempt at thread-safe `Solution` implementation --- Mediapipe.Net/Solutions/Solution.cs | 33 +++++-------- Mediapipe.Net/Solutions/SolutionOutputs.cs | 57 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 Mediapipe.Net/Solutions/SolutionOutputs.cs diff --git a/Mediapipe.Net/Solutions/Solution.cs b/Mediapipe.Net/Solutions/Solution.cs index 3a5da7f..fc03a19 100644 --- a/Mediapipe.Net/Solutions/Solution.cs +++ b/Mediapipe.Net/Solutions/Solution.cs @@ -2,7 +2,6 @@ // 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.IO; using System.Runtime.InteropServices; @@ -25,7 +24,7 @@ namespace Mediapipe.Net.Solutions protected readonly CalculatorGraph Graph; protected readonly SidePackets? SidePackets; - protected readonly IDictionary GraphOutputs; + protected readonly SolutionOutputs SolutionOutputs; private readonly IDictionary observeStreamHandles; protected long SimulatedTimestamp = 0; @@ -39,16 +38,15 @@ namespace Mediapipe.Net.Solutions Graph = new CalculatorGraph(File.ReadAllText(GraphPath)); SidePackets = sidePackets; - GraphOutputs = new Dictionary(); - + SolutionOutputs = new SolutionOutputs(); observeStreamHandles = new Dictionary(); foreach ((string output, PacketType packetType) in outputs) { Graph.ObserveOutputStream(output, (packet) => { packet.PacketType = packetType; - lock (GraphOutputs) - GraphOutputs.Add(output, packet.Get()); + lock (SolutionOutputs) + SolutionOutputs.Put(packet.Timestamp().Microseconds, output, packet.Get()); return Status.Ok(); }, out GCHandle handle).AssertOk(); observeStreamHandles.Add(output, handle); @@ -64,19 +62,6 @@ namespace Mediapipe.Net.Solutions /// protected IDictionary Process(IDictionary inputs) { - // Set the timestamp increment to 16666 us to simulate 60 fps video input (?) - // That's what the Python API does so ¯\_(ツ)_/¯ - // Might have to find something better? - SimulatedTimestamp += 10000; - - // Dispose of the previous packets before processing - foreach (object? obj in GraphOutputs.Values) - { - if (obj is IDisposable disposable) - disposable.Dispose(); - } - GraphOutputs.Clear(); - foreach (KeyValuePair input in inputs) { if (input.Value != null) @@ -84,7 +69,15 @@ namespace Mediapipe.Net.Solutions } Graph.WaitUntilIdle(); - return GraphOutputs; + SolutionOutputs.Finish(SimulatedTimestamp); + var solutionOutput = SolutionOutputs.GetSolutionOutput(SimulatedTimestamp); + + // Set the timestamp increment to 16666 us to simulate 60 fps video input (?) + // That's what the Python API does so ¯\_(ツ)_/¯ + // Might have to find something better? + SimulatedTimestamp += 10000; + + return solutionOutput; } protected abstract IDictionary ProcessFrame(ImageFrame frame); diff --git a/Mediapipe.Net/Solutions/SolutionOutputs.cs b/Mediapipe.Net/Solutions/SolutionOutputs.cs new file mode 100644 index 0000000..d9e6b3f --- /dev/null +++ b/Mediapipe.Net/Solutions/SolutionOutputs.cs @@ -0,0 +1,57 @@ +// 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.Collections.Generic; +using System.Linq; + +namespace Mediapipe.Net.Solutions +{ + /// + /// Solution outputs queued by timestamp. + /// + public class SolutionOutputs + { + private readonly IDictionary> tempOutputs; + private readonly IDictionary> finishedOutputs; + + public SolutionOutputs() + { + tempOutputs = new Dictionary>(); + finishedOutputs = new Dictionary>(); + } + + public void Put(long timestamp, string output, object? packetOutput) + { + if (!tempOutputs.ContainsKey(timestamp)) + tempOutputs[timestamp] = new Dictionary(); + tempOutputs[timestamp][output] = packetOutput; + } + + public void Finish(long timestamp) + { + if (tempOutputs.ContainsKey(timestamp)) + { + finishedOutputs[timestamp] = tempOutputs[timestamp]; + tempOutputs.Remove(timestamp); + } + else + { + finishedOutputs[timestamp] = new Dictionary(); + } + } + + public IDictionary GetSolutionOutput(long timestamp) + { + IDictionary solutionOutput = finishedOutputs[timestamp]; + finishedOutputs.Remove(timestamp); + return solutionOutput; + } + + public IDictionary GetEarliestSolutionOutput() + { + long earliestTimestamp = finishedOutputs.Keys.Min(); + return GetSolutionOutput(earliestTimestamp); + } + } +}