156 lines
2.8 KiB
C#
156 lines
2.8 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Threading;
|
|
using Nerfed.Runtime.Graphics;
|
|
|
|
namespace Nerfed.Runtime.Video;
|
|
|
|
// Note that all public methods are async.
|
|
internal class VideoAV1Stream : GraphicsResource
|
|
{
|
|
public IntPtr Handle => handle;
|
|
IntPtr handle;
|
|
|
|
public bool Loaded => handle != IntPtr.Zero;
|
|
public bool Ended => Dav1dfile.df_eos(Handle) == 1;
|
|
|
|
public IntPtr yDataHandle;
|
|
public IntPtr uDataHandle;
|
|
public IntPtr vDataHandle;
|
|
public uint yDataLength;
|
|
public uint uvDataLength;
|
|
public uint yStride;
|
|
public uint uvStride;
|
|
|
|
public bool FrameDataUpdated { get; set; }
|
|
|
|
private BlockingCollection<Action> Actions = new BlockingCollection<Action>();
|
|
|
|
private bool Running = false;
|
|
|
|
Thread Thread;
|
|
|
|
public VideoAV1Stream(GraphicsDevice device) : base(device)
|
|
{
|
|
handle = IntPtr.Zero;
|
|
|
|
Running = true;
|
|
|
|
Thread = new Thread(ThreadMain);
|
|
Thread.Start();
|
|
}
|
|
|
|
private void ThreadMain()
|
|
{
|
|
while (Running)
|
|
{
|
|
// block until we can take an action, then run it
|
|
Action action = Actions.Take();
|
|
action.Invoke();
|
|
}
|
|
|
|
// shutting down...
|
|
while (Actions.TryTake(out Action action))
|
|
{
|
|
action.Invoke();
|
|
}
|
|
}
|
|
|
|
public void Load(string filename)
|
|
{
|
|
Actions.Add(() => LoadHelper(filename));
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
Actions.Add(ResetHelper);
|
|
}
|
|
|
|
public void ReadNextFrame()
|
|
{
|
|
Actions.Add(ReadNextFrameHelper);
|
|
}
|
|
|
|
public void Unload()
|
|
{
|
|
Actions.Add(UnloadHelper);
|
|
}
|
|
|
|
private void LoadHelper(string filename)
|
|
{
|
|
if (!Loaded)
|
|
{
|
|
if (Dav1dfile.df_fopen(filename, out handle) == 0)
|
|
{
|
|
Log.Error("Failed to load video file: " + filename);
|
|
throw new Exception("Failed to load video file!");
|
|
}
|
|
|
|
Reset();
|
|
}
|
|
}
|
|
|
|
private void ResetHelper()
|
|
{
|
|
if (Loaded)
|
|
{
|
|
Dav1dfile.df_reset(handle);
|
|
ReadNextFrame();
|
|
}
|
|
}
|
|
|
|
private void ReadNextFrameHelper()
|
|
{
|
|
if (Loaded && !Ended)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (Dav1dfile.df_readvideo(
|
|
handle,
|
|
1,
|
|
out IntPtr yDataHandle,
|
|
out IntPtr uDataHandle,
|
|
out IntPtr vDataHandle,
|
|
out uint yDataLength,
|
|
out uint uvDataLength,
|
|
out uint yStride,
|
|
out uint uvStride) == 1
|
|
) {
|
|
this.yDataHandle = yDataHandle;
|
|
this.uDataHandle = uDataHandle;
|
|
this.vDataHandle = vDataHandle;
|
|
this.yDataLength = yDataLength;
|
|
this.uvDataLength = uvDataLength;
|
|
this.yStride = yStride;
|
|
this.uvStride = uvStride;
|
|
|
|
FrameDataUpdated = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UnloadHelper()
|
|
{
|
|
if (Loaded)
|
|
{
|
|
Dav1dfile.df_close(handle);
|
|
handle = IntPtr.Zero;
|
|
}
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (!IsDisposed)
|
|
{
|
|
Unload();
|
|
Running = false;
|
|
|
|
if (disposing)
|
|
{
|
|
Thread.Join();
|
|
}
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
} |