mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-23 00:52:01 +00:00
Callbacks added on post image processing.
This commit is contained in:
parent
36b9343269
commit
3457aa6816
@ -68,10 +68,7 @@ public partial class JobViewModel : ObservableObject
|
|||||||
: "";
|
: "";
|
||||||
|
|
||||||
public override string ToString() => $"{FileName}: {TextDesc}";
|
public override string ToString() => $"{FileName}: {TextDesc}";
|
||||||
|
public ObservableCollection<ParameterEntry> ParametersList { get; } = new();
|
||||||
public ObservableCollection<ParameterEntry> ParametersList { get; }
|
|
||||||
= new();
|
|
||||||
|
|
||||||
public ObservableCollection<Segment> Segments { get; } = new();
|
public ObservableCollection<Segment> Segments { get; } = new();
|
||||||
|
|
||||||
public string CropText
|
public string CropText
|
||||||
|
|||||||
@ -72,7 +72,7 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
jobs.AddRange(fileJobs);
|
jobs.AddRange(fileJobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _processor.ProcessJobs(jobs, jobs.First().Job.Enhance, _cancellationTokenSource.Token);
|
await _processor.ProcessJobs(jobs, jobs.First().Job.Enhance, null, _cancellationTokenSource.Token);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,5 +3,5 @@
|
|||||||
public interface IJobProcessor
|
public interface IJobProcessor
|
||||||
{
|
{
|
||||||
Task<List<SingleTask>> GenerateJobs(SingleJob job, bool estimateOnly, IReadOnlyCollection<Segment> predefinedSegments, CancellationToken token);
|
Task<List<SingleTask>> GenerateJobs(SingleJob job, bool estimateOnly, IReadOnlyCollection<Segment> predefinedSegments, CancellationToken token);
|
||||||
Task<bool> ProcessJobs(List<SingleTask> tasks, bool singleThreaded, CancellationToken token);
|
Task<bool> ProcessJobs(List<SingleTask> tasks, bool singleThreaded, Action<SingleTask, FrameProcessingResult>? onFrameProcessed, CancellationToken token);
|
||||||
}
|
}
|
||||||
@ -105,18 +105,18 @@ public class JobProcessor(ILogger logger) : LoggingBase(logger, 0), IJobProcesso
|
|||||||
).ToList();
|
).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ProcessJobs(List<SingleTask> tasks, bool singleThreaded, CancellationToken token)
|
public async Task<bool> ProcessJobs(List<SingleTask> tasks, bool singleThreaded, Action<SingleTask, FrameProcessingResult>? onFrameProcessed, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (singleThreaded)
|
if (singleThreaded)
|
||||||
{
|
{
|
||||||
LogInfo("Starting single-threaded splitting...");
|
LogInfo("Starting single-threaded splitting...");
|
||||||
await RunSingleThreaded(tasks, token);
|
await RunSingleThreaded(tasks, onFrameProcessed, token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogInfo("Starting multi-threaded splitting...");
|
LogInfo("Starting multi-threaded splitting...");
|
||||||
await RunMultiThreaded(tasks, token);
|
await RunMultiThreaded(tasks, onFrameProcessed, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogInfo("Done.");
|
LogInfo("Done.");
|
||||||
@ -133,7 +133,7 @@ public class JobProcessor(ILogger logger) : LoggingBase(logger, 0), IJobProcesso
|
|||||||
// Multi-threaded splitting
|
// Multi-threaded splitting
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
private async Task RunMultiThreaded(List<SingleTask> jobs, CancellationToken token)
|
private async Task RunMultiThreaded(List<SingleTask> jobs, Action<SingleTask,FrameProcessingResult>? onFrameProcessed, CancellationToken token)
|
||||||
{
|
{
|
||||||
LogProgress(0.0, TimeSpan.Zero, 0.0);
|
LogProgress(0.0, TimeSpan.Zero, 0.0);
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ public class JobProcessor(ILogger logger) : LoggingBase(logger, 0), IJobProcesso
|
|||||||
return;
|
return;
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
}
|
}
|
||||||
await ProcessSegment(job, slot + 1, token);
|
await ProcessSegment(job, slot + 1, onFrameProcessed, token);
|
||||||
|
|
||||||
var processed = Interlocked.Increment(ref processedSegments);
|
var processed = Interlocked.Increment(ref processedSegments);
|
||||||
var elapsed = sw.Elapsed;
|
var elapsed = sw.Elapsed;
|
||||||
@ -194,21 +194,21 @@ public class JobProcessor(ILogger logger) : LoggingBase(logger, 0), IJobProcesso
|
|||||||
// Single-threaded splitting
|
// Single-threaded splitting
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
private async Task RunSingleThreaded(List<SingleTask> jobs, CancellationToken token)
|
private async Task RunSingleThreaded(List<SingleTask> jobs, Action<SingleTask, FrameProcessingResult>? onFrameProcessed, CancellationToken token)
|
||||||
{
|
{
|
||||||
foreach (var job in jobs)
|
foreach (var job in jobs)
|
||||||
{
|
{
|
||||||
await ProcessSegment(job, 0, token);
|
await ProcessSegment(job, 0, onFrameProcessed, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessSegment(SingleTask t, int slot, CancellationToken token)
|
private async Task ProcessSegment(SingleTask t, int slot, Action<SingleTask, FrameProcessingResult>? onFrameProcessed, CancellationToken token)
|
||||||
{
|
{
|
||||||
var processor = t.ProcessorFactory(slot);
|
var processor = t.ProcessorFactory(slot);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await processor.ProcessSegment(t, token);
|
await processor.ProcessSegment(t, x=>onFrameProcessed?.Invoke(t, x), token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@ -58,12 +58,12 @@ public sealed class SimpleSplitter : LoggingBase, ISegmentProcessor
|
|||||||
// GetNextProcessedFrame
|
// GetNextProcessedFrame
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
public Mat? GetNextProcessedFrame(IFrameProcessingState processorState, CancellationToken token)
|
public FrameProcessingResult GetNextProcessedFrame(IFrameProcessingState processorState, CancellationToken token)
|
||||||
{
|
{
|
||||||
var state = (State)processorState;
|
var state = (State)processorState;
|
||||||
|
|
||||||
if (state.DecodeStdout == null)
|
if (state.DecodeStdout == null)
|
||||||
return null;
|
return new FrameProcessingResult(null, [], null);
|
||||||
|
|
||||||
// SimpleSplitter does not modify frames; it only copies or rotates.
|
// SimpleSplitter does not modify frames; it only copies or rotates.
|
||||||
// For preview, we decode raw frames and return them as-is.
|
// For preview, we decode raw frames and return them as-is.
|
||||||
@ -76,12 +76,12 @@ public sealed class SimpleSplitter : LoggingBase, ISegmentProcessor
|
|||||||
var buffer = new byte[bytes];
|
var buffer = new byte[bytes];
|
||||||
var read = state.DecodeStdout.Read(buffer, 0, bytes);
|
var read = state.DecodeStdout.Read(buffer, 0, bytes);
|
||||||
if (read != bytes)
|
if (read != bytes)
|
||||||
return null;
|
return new FrameProcessingResult(null, [], null);
|
||||||
|
|
||||||
var mat = new Mat(h, w, MatType.CV_8UC3);
|
var mat = new Mat(h, w, MatType.CV_8UC3);
|
||||||
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, mat.Data, bytes);
|
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, mat.Data, bytes);
|
||||||
|
|
||||||
return mat;
|
return new FrameProcessingResult(mat, [], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@ -111,7 +111,7 @@ public sealed class SimpleSplitter : LoggingBase, ISegmentProcessor
|
|||||||
// ProcessSegment (now uses preview API)
|
// ProcessSegment (now uses preview API)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
public async Task ProcessSegment(SingleTask job, CancellationToken token)
|
public async Task ProcessSegment(SingleTask job, Action<FrameProcessingResult>? onFrameProcessed, CancellationToken token)
|
||||||
{
|
{
|
||||||
var state = (State)InitSegment(job, token);
|
var state = (State)InitSegment(job, token);
|
||||||
|
|
||||||
@ -125,7 +125,8 @@ public sealed class SimpleSplitter : LoggingBase, ISegmentProcessor
|
|||||||
{
|
{
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var frame = GetNextProcessedFrame(state, token);
|
var res = GetNextProcessedFrame(state, token);
|
||||||
|
var frame = res.Image;
|
||||||
if (frame == null)
|
if (frame == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -134,6 +135,8 @@ public sealed class SimpleSplitter : LoggingBase, ISegmentProcessor
|
|||||||
var buffer = new byte[bytes];
|
var buffer = new byte[bytes];
|
||||||
System.Runtime.InteropServices.Marshal.Copy(frame.Data, buffer, 0, bytes);
|
System.Runtime.InteropServices.Marshal.Copy(frame.Data, buffer, 0, bytes);
|
||||||
encodeStdin.Write(buffer, 0, bytes);
|
encodeStdin.Write(buffer, 0, bytes);
|
||||||
|
|
||||||
|
onFrameProcessed?.Invoke(res);
|
||||||
|
|
||||||
frame.Dispose();
|
frame.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,17 +103,17 @@ public sealed class TrackingSplitter : LoggingBase, ISegmentProcessor
|
|||||||
// GetNextProcessedFrame
|
// GetNextProcessedFrame
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
public Mat? GetNextProcessedFrame(
|
public FrameProcessingResult GetNextProcessedFrame(
|
||||||
IFrameProcessingState processorState,
|
IFrameProcessingState processorState,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
var state = (FrameProcessingState)processorState;
|
var state = (FrameProcessingState)processorState;
|
||||||
|
|
||||||
if (state.DecodeStdout == null)
|
if (state.DecodeStdout == null)
|
||||||
return null;
|
return new FrameProcessingResult(null, [], null);
|
||||||
|
|
||||||
if (!TryReadNextFrame(state.DecodeStdout, state, token))
|
if (!TryReadNextFrame(state.DecodeStdout, state, token))
|
||||||
return null;
|
return new FrameProcessingResult(null, [], null);
|
||||||
|
|
||||||
return ProcessFrame(state.FrameMat, state, state.Job, token);
|
return ProcessFrame(state.FrameMat, state, state.Job, token);
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ public sealed class TrackingSplitter : LoggingBase, ISegmentProcessor
|
|||||||
// PROCESSSEGMENT (full pipeline)
|
// PROCESSSEGMENT (full pipeline)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
public async Task ProcessSegment(SingleTask job, CancellationToken token)
|
public async Task ProcessSegment(SingleTask job, Action<FrameProcessingResult>? onFrameProcessed, CancellationToken token)
|
||||||
{
|
{
|
||||||
var name = Path.GetFileNameWithoutExtension(job.OutputFileName);
|
var name = Path.GetFileNameWithoutExtension(job.OutputFileName);
|
||||||
var fps = job.Info.Fps;
|
var fps = job.Info.Fps;
|
||||||
@ -180,12 +180,14 @@ public sealed class TrackingSplitter : LoggingBase, ISegmentProcessor
|
|||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var frame = GetNextProcessedFrame(state, token);
|
var frame = GetNextProcessedFrame(state, token);
|
||||||
if (frame == null)
|
if (frame.Image == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
frameIndex++;
|
frameIndex++;
|
||||||
|
|
||||||
EncodeFrame(frame, state, encodeStdin);
|
EncodeFrame(frame.Image, state, encodeStdin);
|
||||||
|
|
||||||
|
onFrameProcessed?.Invoke(frame);
|
||||||
|
|
||||||
var elapsed = DateTime.UtcNow - startTime;
|
var elapsed = DateTime.UtcNow - startTime;
|
||||||
var progress = totalFrames > 0 ? (double)frameIndex / totalFrames : 0.0;
|
var progress = totalFrames > 0 ? (double)frameIndex / totalFrames : 0.0;
|
||||||
@ -272,7 +274,7 @@ public sealed class TrackingSplitter : LoggingBase, ISegmentProcessor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mat ProcessFrame(
|
private FrameProcessingResult ProcessFrame(
|
||||||
Mat inputFrame,
|
Mat inputFrame,
|
||||||
FrameProcessingState state,
|
FrameProcessingState state,
|
||||||
SingleTask job,
|
SingleTask job,
|
||||||
@ -298,12 +300,12 @@ public sealed class TrackingSplitter : LoggingBase, ISegmentProcessor
|
|||||||
if (state.Enhancer != null)
|
if (state.Enhancer != null)
|
||||||
{
|
{
|
||||||
if (state.Enhancer.TryProcessFrame(state.OutMat, out var enhanced, token))
|
if (state.Enhancer.TryProcessFrame(state.OutMat, out var enhanced, token))
|
||||||
return enhanced;
|
return new FrameProcessingResult(enhanced, objects, primary);
|
||||||
|
|
||||||
return state.OutMat;
|
return new FrameProcessingResult(state.OutMat, objects, primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.OutMat;
|
return new FrameProcessingResult(state.OutMat, objects, primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EncodeFrame(
|
private void EncodeFrame(
|
||||||
|
|||||||
@ -4,11 +4,13 @@ public interface IFrameProcessingState
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed record FrameProcessingResult(Mat? Image, List<DetectedPerson> Detected, DetectedPerson? Primary);
|
||||||
|
|
||||||
public interface ISegmentProcessor
|
public interface ISegmentProcessor
|
||||||
{
|
{
|
||||||
IFrameProcessingState InitSegment(SingleTask job, CancellationToken token);
|
IFrameProcessingState InitSegment(SingleTask job, CancellationToken token);
|
||||||
Mat? GetNextProcessedFrame( IFrameProcessingState processorState, CancellationToken token);
|
FrameProcessingResult GetNextProcessedFrame(IFrameProcessingState processorState, CancellationToken token);
|
||||||
void FinishSegment(IFrameProcessingState processorState);
|
void FinishSegment(IFrameProcessingState processorState);
|
||||||
|
|
||||||
Task ProcessSegment( SingleTask job, CancellationToken token);
|
Task ProcessSegment( SingleTask job, Action<FrameProcessingResult>? onFrameProcessed, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ static partial class Program
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var success = await processor.ProcessJobs(allJobs, cmd.Master.SingleThreaded, CancellationToken.None);
|
var success = await processor.ProcessJobs(allJobs, cmd.Master.SingleThreaded, null, CancellationToken.None);
|
||||||
if (uiTask != null)
|
if (uiTask != null)
|
||||||
{
|
{
|
||||||
if ( cts != null )
|
if ( cts != null )
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user