Added CFramebuffer.cs

Introduced Thread waiting for unused videos
This commit is contained in:
Flamefire committed 2013-05-26 00:17:47 +02:00
1 parent 1c2f67fce2
commit 517db7d43b
4 files changed
+147 -78

No files matched your search

+52 -72
View File
@@ -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;
}
}
+1
View File
@@ -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" />