Added CFramebuffer.cs
Introduced Thread waiting for unused videos
This commit is contained in:
1 parent
1c2f67fce2
commit
517db7d43b
4 files changed
+147
-78
No files matched your search
@@ -15,9 +15,8 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
|
|
||||||
private readonly Stopwatch _LoopTimer = new Stopwatch();
|
private readonly Stopwatch _LoopTimer = new Stopwatch();
|
||||||
private readonly Thread _Thread;
|
private readonly Thread _Thread;
|
||||||
//AutoResetEvent EventDecode = new AutoResetEvent(false);
|
|
||||||
private readonly Object _MutexFramebuffer = new Object();
|
private readonly Object _MutexFramebuffer = new Object();
|
||||||
private readonly SFrameBuffer[] _FrameBuffer = new SFrameBuffer[5];
|
private readonly CFramebuffer _Framebuffer;
|
||||||
private readonly Object _MutexSyncSignals = new Object();
|
private readonly Object _MutexSyncSignals = new Object();
|
||||||
|
|
||||||
private bool _FileOpened;
|
private bool _FileOpened;
|
||||||
@@ -25,7 +24,6 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
private float _FrameDuration; // frame time in s
|
private float _FrameDuration; // frame time in s
|
||||||
private float _LastDecodedTime; // time of last decoded frame
|
private float _LastDecodedTime; // time of last decoded frame
|
||||||
private float _LastShownTime; // current video position
|
private float _LastShownTime; // current video position
|
||||||
private bool _BufferFull; // buffer is full, waiting for free frame slot
|
|
||||||
|
|
||||||
private float _Time;
|
private float _Time;
|
||||||
private float _Gap;
|
private float _Gap;
|
||||||
@@ -40,6 +38,9 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
private bool _Terminated;
|
private bool _Terminated;
|
||||||
private bool _FrameAvailable;
|
private bool _FrameAvailable;
|
||||||
private bool _NoMoreFrames;
|
private bool _NoMoreFrames;
|
||||||
|
private AutoResetEvent _EvWakeUp = new AutoResetEvent(false);
|
||||||
|
private bool _IsSleeping;
|
||||||
|
private int _WaitCount;
|
||||||
|
|
||||||
private float _SkipTime; // = Start + VideoGap
|
private float _SkipTime; // = Start + VideoGap
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
public CDecoder()
|
public CDecoder()
|
||||||
{
|
{
|
||||||
_Thread = new Thread(_Execute);
|
_Thread = new Thread(_Execute);
|
||||||
|
_Framebuffer = new CFramebuffer(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Length { get; private set; }
|
public float Length { get; private set; }
|
||||||
@@ -173,11 +175,9 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
|
|
||||||
lock (_MutexFramebuffer)
|
lock (_MutexFramebuffer)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
_Framebuffer.Clear();
|
||||||
_FrameBuffer[i].Displayed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_BufferFull = false;
|
|
||||||
_FrameAvailable = false;
|
_FrameAvailable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,9 +202,25 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
if (!_FrameAvailable)
|
if (!_FrameAvailable)
|
||||||
_Decode();
|
_Decode();
|
||||||
|
|
||||||
if (_FrameAvailable && !_BufferFull)
|
if (_FrameAvailable)
|
||||||
_Copy();
|
{
|
||||||
Thread.Sleep(1);
|
if (!_Framebuffer.IsFull())
|
||||||
|
{
|
||||||
|
_Copy();
|
||||||
|
_WaitCount = 0;
|
||||||
|
Thread.Sleep(1);
|
||||||
|
}
|
||||||
|
else if (_WaitCount > 3)
|
||||||
|
{
|
||||||
|
_IsSleeping = true;
|
||||||
|
_EvWakeUp.WaitOne();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Thread.Sleep((int)((_Framebuffer.Size - 2) * _FrameDuration * 1000));
|
||||||
|
_WaitCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_Free();
|
_Free();
|
||||||
@@ -261,14 +277,9 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
_FrameDuration = 1f / (float)videodecoder.StreamInfo.VideoInfo.FramesPerSecond;
|
_FrameDuration = 1f / (float)videodecoder.StreamInfo.VideoInfo.FramesPerSecond;
|
||||||
|
|
||||||
_LastDecodedTime = 0f;
|
_LastDecodedTime = 0f;
|
||||||
_Time = 0f;
|
_SetTime = 0f;
|
||||||
|
|
||||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
_Framebuffer.Init(_Width * _Height * 4);
|
||||||
{
|
|
||||||
_FrameBuffer[i].Displayed = true;
|
|
||||||
_FrameBuffer[i].Data = new byte[_Width * _Height * 4];
|
|
||||||
}
|
|
||||||
_BufferFull = false;
|
|
||||||
_FrameAvailable = false;
|
_FrameAvailable = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -277,7 +288,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
{
|
{
|
||||||
const int framedropcount = 4;
|
const int framedropcount = 4;
|
||||||
|
|
||||||
if (_Paused || _NoMoreFrames || _BufferFull)
|
if (_Paused || _NoMoreFrames)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float myTime = _Time + _Gap;
|
float myTime = _Time + _Gap;
|
||||||
@@ -335,43 +346,12 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
{
|
{
|
||||||
lock (_MutexFramebuffer)
|
lock (_MutexFramebuffer)
|
||||||
{
|
{
|
||||||
int num = -1;
|
var videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
||||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
if (videodecoder.Buffer == IntPtr.Zero)
|
||||||
{
|
return;
|
||||||
if (_FrameBuffer[i].Displayed)
|
_LastDecodedTime = (float)videodecoder.Timecode;
|
||||||
{
|
_Framebuffer.Put(videodecoder.Buffer, _LastDecodedTime);
|
||||||
num = i;
|
_FrameAvailable = false;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num == -1)
|
|
||||||
_BufferFull = true; //Should not happen
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
|
||||||
|
|
||||||
_LastDecodedTime = (float)videodecoder.Timecode;
|
|
||||||
_FrameBuffer[num].Time = _LastDecodedTime;
|
|
||||||
|
|
||||||
if (videodecoder.Buffer != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Marshal.Copy(videodecoder.Buffer, _FrameBuffer[num].Data, 0, _Width * _Height * 4);
|
|
||||||
_FrameBuffer[num].Displayed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_BufferFull = true;
|
|
||||||
for (int i = num + 1; i < _FrameBuffer.Length; i++)
|
|
||||||
{
|
|
||||||
if (_FrameBuffer[i].Displayed)
|
|
||||||
{
|
|
||||||
_BufferFull = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_FrameAvailable = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,50 +359,50 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
|||||||
{
|
{
|
||||||
lock (_MutexFramebuffer)
|
lock (_MutexFramebuffer)
|
||||||
{
|
{
|
||||||
int num = _FindFrame();
|
CFrame curFrame = _FindFrame();
|
||||||
|
|
||||||
if (num >= 0)
|
if (curFrame != null)
|
||||||
{
|
{
|
||||||
CDraw.UpdateOrAddTexture(ref frame, _Width, _Height, _FrameBuffer[num].Data);
|
CDraw.UpdateOrAddTexture(ref frame, _Width, _Height, curFrame.Data);
|
||||||
|
|
||||||
lock (_MutexSyncSignals)
|
lock (_MutexSyncSignals)
|
||||||
{
|
{
|
||||||
_LastShownTime = _FrameBuffer[num].Time;
|
_LastShownTime = curFrame.Time;
|
||||||
|
}
|
||||||
|
if (_IsSleeping)
|
||||||
|
{
|
||||||
|
_IsSleeping = false;
|
||||||
|
_EvWakeUp.Set();
|
||||||
}
|
}
|
||||||
Finished = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_NoMoreFrames)
|
if (_NoMoreFrames && _Framebuffer.IsEmpty())
|
||||||
Finished = true;
|
Finished = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int _FindFrame()
|
private CFrame _FindFrame()
|
||||||
{
|
{
|
||||||
int result = -1;
|
CFrame result = null;
|
||||||
float now = _SetTime + _Gap;
|
float now = _SetTime + _Gap;
|
||||||
float maxEnd = now - _FrameDuration * 2; //Get only frames younger than 2
|
float maxEnd = now - _FrameDuration * 2; //Get only frames younger than 2
|
||||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
CFrame frame;
|
||||||
|
while ((frame = _Framebuffer.Get()) != null)
|
||||||
{
|
{
|
||||||
if (_FrameBuffer[i].Displayed)
|
float frameEnd = frame.Time + _FrameDuration;
|
||||||
continue;
|
|
||||||
|
|
||||||
float frameEnd = _FrameBuffer[i].Time + _FrameDuration;
|
|
||||||
//Don't show frames that are shown during or after now
|
//Don't show frames that are shown during or after now
|
||||||
if (frameEnd >= now)
|
if (frameEnd >= now)
|
||||||
continue;
|
break; //All following frames are after that one
|
||||||
|
|
||||||
_FrameBuffer[i].Displayed = true;
|
_Framebuffer.SetRead();
|
||||||
_BufferFull = false;
|
|
||||||
//Get the last(newest) possible frame and skip the rest to force in-order showing
|
//Get the last(newest) possible frame and skip the rest to force in-order showing
|
||||||
if (frameEnd <= maxEnd)
|
if (frameEnd <= maxEnd)
|
||||||
continue;
|
continue;
|
||||||
maxEnd = frameEnd;
|
maxEnd = frameEnd;
|
||||||
result = i;
|
result = frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Vocaluxe.Lib.Video.Acinerella
|
||||||
|
{
|
||||||
|
class CFrame
|
||||||
|
{
|
||||||
|
public readonly byte[] Data;
|
||||||
|
public float Time = -1;
|
||||||
|
|
||||||
|
public CFrame(int dataSize)
|
||||||
|
{
|
||||||
|
Data = new byte[dataSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CFramebuffer
|
||||||
|
{
|
||||||
|
private readonly CFrame[] _Frames;
|
||||||
|
private readonly int _Size;
|
||||||
|
private int _DataSize;
|
||||||
|
private int _Last;
|
||||||
|
private int _First;
|
||||||
|
private bool _Initialized;
|
||||||
|
|
||||||
|
public int Size
|
||||||
|
{
|
||||||
|
get { return _Size; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public CFramebuffer(int size)
|
||||||
|
{
|
||||||
|
_Size = size;
|
||||||
|
_Frames = new CFrame[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(int dataSize)
|
||||||
|
{
|
||||||
|
_DataSize = dataSize;
|
||||||
|
for (int i = 0; i < _Size; i++)
|
||||||
|
_Frames[i] = new CFrame(dataSize);
|
||||||
|
_Initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Next(int current)
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
return (current < _Size) ? current : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFull()
|
||||||
|
{
|
||||||
|
return _Next(_Last) == _First;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEmpty()
|
||||||
|
{
|
||||||
|
return _First == _Last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Put(IntPtr data, float time)
|
||||||
|
{
|
||||||
|
if (!_Initialized || IsFull())
|
||||||
|
return false;
|
||||||
|
CFrame frame = _Frames[_Last];
|
||||||
|
Marshal.Copy(data, frame.Data, 0, _DataSize);
|
||||||
|
frame.Time = time;
|
||||||
|
_Last = _Next(_Last);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CFrame Get()
|
||||||
|
{
|
||||||
|
return IsEmpty() ? null : _Frames[_First];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetRead()
|
||||||
|
{
|
||||||
|
if (IsEmpty())
|
||||||
|
return false;
|
||||||
|
_First = _Next(_First);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_First = 0;
|
||||||
|
_Last = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -162,10 +162,4 @@ namespace Vocaluxe.Lib.Video
|
|||||||
public void Update(){}
|
public void Update(){}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SFrameBuffer
|
|
||||||
{
|
|
||||||
public byte[] Data;
|
|
||||||
public float Time;
|
|
||||||
public bool Displayed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -211,6 +211,7 @@
|
|||||||
<Compile Include="GameModes\CGameModes.cs" />
|
<Compile Include="GameModes\CGameModes.cs" />
|
||||||
<Compile Include="Lib\Input\CControllerFramework.cs" />
|
<Compile Include="Lib\Input\CControllerFramework.cs" />
|
||||||
<Compile Include="Lib\Video\Acinerella\CDecoder.cs" />
|
<Compile Include="Lib\Video\Acinerella\CDecoder.cs" />
|
||||||
|
<Compile Include="Lib\Video\Acinerella\CFramebuffer.cs" />
|
||||||
<Compile Include="SongQueue\CSongQueue.cs" />
|
<Compile Include="SongQueue\CSongQueue.cs" />
|
||||||
<Compile Include="GameModes\IGameMode.cs" />
|
<Compile Include="GameModes\IGameMode.cs" />
|
||||||
<Compile Include="SongQueue\ISongQueue.cs" />
|
<Compile Include="SongQueue\ISongQueue.cs" />
|
||||||
|
|||||||
Reference in new issue
Block a user