Nerfed/Nerfed.Runtime/Video/VideoAV1Stream.cs

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);
}
}