JD2022-TU1/main/tools/apps/TempoBlaster/Source/FrameVideo/FrameLoader.cs

134 lines
4 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using JD.Kernel.Structs;
using TeaBox;
namespace TempoBlaster.FrameVideo
{
internal partial class FrameCache
{
public event EventHandler CurrentFrameLoaded;
internal class FrameLoader : IDisposable
{
private readonly FrameCache _cache;
private readonly Thread _backgroundThread;
public Frame FrameCurrentlyLoading { get; private set; }
public bool Disposed { get; set; }
public FrameLoader(FrameCache cache)
{
_cache = cache;
_backgroundThread = new Thread(Load) { IsBackground = true };
_backgroundThread.Start();
}
public void Dispose()
{
Disposed = true;
}
private void Load()
{
while (!Disposed)
{
Frame frame;
if (_cache.ToBeLoaded.TryPop(out frame))
{
try
{
FrameCurrentlyLoading = frame;
Stopwatch timer = new Stopwatch();
timer.Start();
if (frame.Load())
{
if (frame.FrameNumber == _cache.CurrentFrame)
{
_cache.CurrentFrameLoaded?.Invoke(_cache, EventArgs.Empty);
}
timer.Stop();
Interlocked.Increment(ref _cache._frameDebugInfo.TotalLoadFrameCount);
Interlocked.Add(ref _cache._frameDebugInfo.TotalLoadTime, (int)timer.Elapsed.TotalMilliseconds);
}
}
finally
{
FrameCurrentlyLoading = null;
}
}
else
{
Thread.Sleep(1);
}
}
}
}
/// <summary>
/// Range of frame to keep in memory.
/// </summary>
public List<Range<int>> FramesAliveRanges
{
get
{
var ranges = new List<Range<int>> { new Range<int>(CurrentFrame - 20, CurrentFrame + BufferSize + 5) };
if (Loop != null && Loop.Value.Contains(CurrentFrame))
{
var distance = Math.Min(Loop.Value.Max - CurrentFrame, BufferSize);
if (distance < BufferSize)
{
ranges.Add(new Range<int>(Loop.Value.Min, Loop.Value.Min + BufferSize - distance));
}
}
return ranges;
}
}
internal class FrameJanitor : IDisposable
{
private readonly FrameCache _cache;
private readonly Thread _backgroundThread;
private bool Disposed { get; set; }
public FrameJanitor(FrameCache cache)
{
_cache = cache;
_backgroundThread = new Thread(OnDoWork) { IsBackground = true };
_backgroundThread.Start();
}
public void Dispose()
{
Disposed = true;
}
private void OnDoWork()
{
while (!Disposed)
{
var ranges = _cache.FramesAliveRanges;
foreach (var frame in _cache.Frames.Values)
{
if (!ranges.Any(r => r.Contains(frame.FrameNumber)))
{
frame.Invalidate();
}
}
Thread.Sleep(1);
}
}
}
}
}