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 Thread _Thread;
|
||||
//AutoResetEvent EventDecode = new AutoResetEvent(false);
|
||||
private readonly Object _MutexFramebuffer = new Object();
|
||||
private readonly SFrameBuffer[] _FrameBuffer = new SFrameBuffer[5];
|
||||
private readonly CFramebuffer _Framebuffer;
|
||||
private readonly Object _MutexSyncSignals = new Object();
|
||||
|
||||
private bool _FileOpened;
|
||||
@@ -25,7 +24,6 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
private float _FrameDuration; // frame time in s
|
||||
private float _LastDecodedTime; // time of last decoded frame
|
||||
private float _LastShownTime; // current video position
|
||||
private bool _BufferFull; // buffer is full, waiting for free frame slot
|
||||
|
||||
private float _Time;
|
||||
private float _Gap;
|
||||
@@ -40,6 +38,9 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
private bool _Terminated;
|
||||
private bool _FrameAvailable;
|
||||
private bool _NoMoreFrames;
|
||||
private AutoResetEvent _EvWakeUp = new AutoResetEvent(false);
|
||||
private bool _IsSleeping;
|
||||
private int _WaitCount;
|
||||
|
||||
private float _SkipTime; // = Start + VideoGap
|
||||
|
||||
@@ -51,6 +52,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
public CDecoder()
|
||||
{
|
||||
_Thread = new Thread(_Execute);
|
||||
_Framebuffer = new CFramebuffer(10);
|
||||
}
|
||||
|
||||
public float Length { get; private set; }
|
||||
@@ -173,11 +175,9 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
|
||||
lock (_MutexFramebuffer)
|
||||
{
|
||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
||||
_FrameBuffer[i].Displayed = true;
|
||||
_Framebuffer.Clear();
|
||||
}
|
||||
|
||||
_BufferFull = false;
|
||||
_FrameAvailable = false;
|
||||
}
|
||||
|
||||
@@ -202,9 +202,25 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
if (!_FrameAvailable)
|
||||
_Decode();
|
||||
|
||||
if (_FrameAvailable && !_BufferFull)
|
||||
_Copy();
|
||||
Thread.Sleep(1);
|
||||
if (_FrameAvailable)
|
||||
{
|
||||
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();
|
||||
@@ -261,14 +277,9 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
_FrameDuration = 1f / (float)videodecoder.StreamInfo.VideoInfo.FramesPerSecond;
|
||||
|
||||
_LastDecodedTime = 0f;
|
||||
_Time = 0f;
|
||||
_SetTime = 0f;
|
||||
|
||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
||||
{
|
||||
_FrameBuffer[i].Displayed = true;
|
||||
_FrameBuffer[i].Data = new byte[_Width * _Height * 4];
|
||||
}
|
||||
_BufferFull = false;
|
||||
_Framebuffer.Init(_Width * _Height * 4);
|
||||
_FrameAvailable = false;
|
||||
return true;
|
||||
}
|
||||
@@ -277,7 +288,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
{
|
||||
const int framedropcount = 4;
|
||||
|
||||
if (_Paused || _NoMoreFrames || _BufferFull)
|
||||
if (_Paused || _NoMoreFrames)
|
||||
return;
|
||||
|
||||
float myTime = _Time + _Gap;
|
||||
@@ -335,43 +346,12 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
{
|
||||
lock (_MutexFramebuffer)
|
||||
{
|
||||
int num = -1;
|
||||
for (int i = 0; i < _FrameBuffer.Length; i++)
|
||||
{
|
||||
if (_FrameBuffer[i].Displayed)
|
||||
{
|
||||
num = i;
|
||||
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;
|
||||
}
|
||||
var videodecoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder));
|
||||
if (videodecoder.Buffer == IntPtr.Zero)
|
||||
return;
|
||||
_LastDecodedTime = (float)videodecoder.Timecode;
|
||||
_Framebuffer.Put(videodecoder.Buffer, _LastDecodedTime);
|
||||
_FrameAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,50 +359,50 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
{
|
||||
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)
|
||||
{
|
||||
_LastShownTime = _FrameBuffer[num].Time;
|
||||
_LastShownTime = curFrame.Time;
|
||||
}
|
||||
if (_IsSleeping)
|
||||
{
|
||||
_IsSleeping = false;
|
||||
_EvWakeUp.Set();
|
||||
}
|
||||
Finished = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_NoMoreFrames)
|
||||
if (_NoMoreFrames && _Framebuffer.IsEmpty())
|
||||
Finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _FindFrame()
|
||||
private CFrame _FindFrame()
|
||||
{
|
||||
int result = -1;
|
||||
CFrame result = null;
|
||||
float now = _SetTime + _Gap;
|
||||
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)
|
||||
continue;
|
||||
|
||||
float frameEnd = _FrameBuffer[i].Time + _FrameDuration;
|
||||
float frameEnd = frame.Time + _FrameDuration;
|
||||
//Don't show frames that are shown during or after now
|
||||
if (frameEnd >= now)
|
||||
continue;
|
||||
break; //All following frames are after that one
|
||||
|
||||
_FrameBuffer[i].Displayed = true;
|
||||
_BufferFull = false;
|
||||
_Framebuffer.SetRead();
|
||||
//Get the last(newest) possible frame and skip the rest to force in-order showing
|
||||
if (frameEnd <= maxEnd)
|
||||
continue;
|
||||
maxEnd = frameEnd;
|
||||
result = i;
|
||||
result = frame;
|
||||
}
|
||||
|
||||
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(){}
|
||||
}
|
||||
|
||||
struct SFrameBuffer
|
||||
{
|
||||
public byte[] Data;
|
||||
public float Time;
|
||||
public bool Displayed;
|
||||
}
|
||||
}
|
||||
@@ -211,6 +211,7 @@
|
||||
<Compile Include="GameModes\CGameModes.cs" />
|
||||
<Compile Include="Lib\Input\CControllerFramework.cs" />
|
||||
<Compile Include="Lib\Video\Acinerella\CDecoder.cs" />
|
||||
<Compile Include="Lib\Video\Acinerella\CFramebuffer.cs" />
|
||||
<Compile Include="SongQueue\CSongQueue.cs" />
|
||||
<Compile Include="GameModes\IGameMode.cs" />
|
||||
<Compile Include="SongQueue\ISongQueue.cs" />
|
||||
|
||||
Reference in new issue
Block a user