diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs
index ea23dade..f5a1d581 100644
--- a/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs
+++ b/Vocaluxe/Lib/Video/Acinerella/CDecoder.cs
@@ -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;
}
diff --git a/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs
new file mode 100644
index 00000000..eb22005f
--- /dev/null
+++ b/Vocaluxe/Lib/Video/Acinerella/CFramebuffer.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs
index d2714b9c..d5b813c7 100644
--- a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs
+++ b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs
@@ -162,10 +162,4 @@ namespace Vocaluxe.Lib.Video
public void Update(){}
}
- struct SFrameBuffer
- {
- public byte[] Data;
- public float Time;
- public bool Displayed;
- }
}
\ No newline at end of file
diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj
index 29172362..35917b34 100644
--- a/Vocaluxe/Vocaluxe.csproj
+++ b/Vocaluxe/Vocaluxe.csproj
@@ -211,6 +211,7 @@
+