Attempt at thread-safe Solution implementation

This commit is contained in:
Speykious
2022-07-10 01:48:52 +02:00
parent 5150a90005
commit 6e9ccca3de
2 changed files with 70 additions and 20 deletions

View File

@@ -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<string, object?> GraphOutputs;
protected readonly SolutionOutputs SolutionOutputs;
private readonly IDictionary<string, GCHandle> observeStreamHandles;
protected long SimulatedTimestamp = 0;
@@ -39,16 +38,15 @@ namespace Mediapipe.Net.Solutions
Graph = new CalculatorGraph(File.ReadAllText(GraphPath));
SidePackets = sidePackets;
GraphOutputs = new Dictionary<string, object?>();
SolutionOutputs = new SolutionOutputs();
observeStreamHandles = new Dictionary<string, GCHandle>();
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
/// <returns></returns>
protected IDictionary<string, object?> Process(IDictionary<string, Packet> 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<string, Packet> 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<string, object?> ProcessFrame(ImageFrame frame);

View File

@@ -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
{
/// <summary>
/// Solution outputs queued by timestamp.
/// </summary>
public class SolutionOutputs
{
private readonly IDictionary<long, IDictionary<string, object?>> tempOutputs;
private readonly IDictionary<long, IDictionary<string, object?>> finishedOutputs;
public SolutionOutputs()
{
tempOutputs = new Dictionary<long, IDictionary<string, object?>>();
finishedOutputs = new Dictionary<long, IDictionary<string, object?>>();
}
public void Put(long timestamp, string output, object? packetOutput)
{
if (!tempOutputs.ContainsKey(timestamp))
tempOutputs[timestamp] = new Dictionary<string, object?>();
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<string, object?>();
}
}
public IDictionary<string, object?> GetSolutionOutput(long timestamp)
{
IDictionary<string, object?> solutionOutput = finishedOutputs[timestamp];
finishedOutputs.Remove(timestamp);
return solutionOutput;
}
public IDictionary<string, object?> GetEarliestSolutionOutput()
{
long earliestTimestamp = finishedOutputs.Keys.Min();
return GetSolutionOutput(earliestTimestamp);
}
}
}