From ad2fb1ddc53d2d81a886d29af62d694530f5fd2b Mon Sep 17 00:00:00 2001 From: Alexander Eckart Date: Sat, 10 Mar 2012 09:30:23 +0100 Subject: [PATCH] some code cleanup and changes in ffmpeg decoder thread --- Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs | 176 ++++++++++++---------- 1 file changed, 96 insertions(+), 80 deletions(-) diff --git a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs index 2e3b569b..b8c38f49 100644 --- a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs +++ b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs @@ -214,33 +214,34 @@ namespace Vocaluxe.Lib.Video class Decoder { - private IntPtr _instance = IntPtr.Zero; - private IntPtr _videodecoder = IntPtr.Zero; - private IntPtr _package = IntPtr.Zero; - private Stopwatch _Timer = new Stopwatch(); - private CLOSEPROC _Closeproc; - private int _StreamID; - private string _FileName; + private IntPtr _instance = IntPtr.Zero; // acinerella instance + private IntPtr _videodecoder = IntPtr.Zero; // acinerella video decoder instance + + private Stopwatch _LoopTimer = new Stopwatch(); + private CLOSEPROC _Closeproc; // delegate for stream closing + private int _StreamID; // stream ID for stream closing + private string _FileName; // current video file name - private FileStream _fs; - private TAc_read_callback _rc; - private TAc_seek_callback _sc; + private FileStream _fs; // video file stream + private TAc_read_callback _rc; // read callback for acinerella + private TAc_seek_callback _sc; // seek callback for acinerella private bool _FileOpened = false; - private float _VideoTimeBase = 0f; - private float _VideoTime = 0f; - private float _ActualVideoTime = 0f; - private bool _waiting = false; - private bool _skip = false; + private float _VideoTimeBase = 0f; // frame time + private float _VideoDecoderTime = 0f; // time of last decoded frame + private float _CurrentVideoTime = 0f; // current video position + private bool _BufferFull = false; // buffer is full, waiting for free frame slot + + private bool _skip = false; // do skip private float _Time = 0f; private float _Gap = 0f; private float _Start = 0f; private bool _Loop = false; private float _Duration = 0f; - private float _VideoSkipTime = 0f; - private float _NegativeSkipTime = 0f; - private float _SkipTime = 0f; + private float _VideoSkipTime = 0f; // = VideoGap + private float _SkipTime = 0f; // = Start + VideoGap + private bool _Paused = false; private bool _NoMoreFrames = false; private bool _Finished = false; @@ -292,15 +293,16 @@ namespace Vocaluxe.Lib.Video get { return _Paused; } set { - _Paused = value; lock (MutexSyncSignals) { + _Paused = value; if (_Paused) - _Timer.Stop(); + { + _LoopTimer.Stop(); + } else { - _Timer.Start(); - EventDecode.Set(); + _LoopTimer.Start(); } } } @@ -329,7 +331,7 @@ namespace Vocaluxe.Lib.Video return false; _FileName = FileName; - _thread.Priority = ThreadPriority.Highest; + _thread.Priority = ThreadPriority.Normal; _thread.Name = Path.GetFileName(FileName); _thread.Start(); return true; @@ -347,12 +349,12 @@ namespace Vocaluxe.Lib.Video { lock (MutexSyncSignals) { - _SetTime += _Timer.ElapsedMilliseconds / 1000f; + _SetTime += _LoopTimer.ElapsedMilliseconds / 1000f; VideoTime = _SetTime; - _Timer.Stop(); - _Timer.Reset(); - _Timer.Start(); + _LoopTimer.Stop(); + _LoopTimer.Reset(); + _LoopTimer.Start(); } @@ -361,12 +363,12 @@ namespace Vocaluxe.Lib.Video return true; } - if (_Time - _SetTime >= 0 || _SetTime > Time) + if (_SetTime != Time) { lock (MutexSyncSignals) { _SetTime = Time; - VideoTime = _VideoTime; + VideoTime = _CurrentVideoTime; } UploadNewFrame(ref frame); EventDecode.Set(); @@ -394,17 +396,14 @@ namespace Vocaluxe.Lib.Video private void DoSkip() { string extension = Path.GetExtension(_FileName); //just a workaround for the mkv-search-bug in ffmpeg - lock (MutexSyncSignals) - { - _VideoSkipTime = _Gap; - _NegativeSkipTime = _Start + _Gap; - _SkipTime = _Start + _Gap; - _BeforeLoop = false; - } + + _VideoSkipTime = _Gap; + _SkipTime = _Start + _Gap; + _BeforeLoop = false; if (_SkipTime > 0 && extension != ".mkv") { - _VideoTime = _SkipTime; + _VideoDecoderTime = _SkipTime; try { CAcinerella.ac_seek(_videodecoder, -1, (Int64)(_SkipTime * 1000f)); @@ -417,7 +416,7 @@ namespace Vocaluxe.Lib.Video } else { - _VideoTime = 0f; + _VideoDecoderTime = 0f; try { if (extension != ".mkv") @@ -429,7 +428,10 @@ namespace Vocaluxe.Lib.Video } } - _ActualVideoTime = _VideoTime; + lock (MutexSyncSignals) + { + _CurrentVideoTime = _VideoDecoderTime; + } lock (MutexFramebuffer) { @@ -440,46 +442,41 @@ namespace Vocaluxe.Lib.Video } } - _waiting = false; + _BufferFull = false; + _skip = false; + EventDecode.Set(); } private void Execute() { DoOpen(); - + EventDecode.Set(); + while (!_terminated) { - if (EventDecode.WaitOne(1) || !_waiting) - { - if (_skip) - { - DoSkip(); - _skip = false; - } - - if (!_waiting) - { - DoDecode(); - } - - if (_waiting) - Copy(); - } - if (!_terminated) + if (EventDecode.WaitOne(10)) { lock (MutexSyncSignals) { _Time = _SetTime; if (_SetSkip) _skip = true; - + _SetSkip = false; _Gap = _SetGap; _Start = _SetStart; _Loop = _SetLoop; } + + if (_skip) + DoSkip(); + + if (!_BufferFull) + DoDecode(); + + if (_BufferFull) + Copy(); } - } DoFree(); @@ -545,7 +542,7 @@ namespace Vocaluxe.Lib.Video if (Videodecoder.stream_info.video_info.frames_per_second > 0) _VideoTimeBase = 1f / (float)Videodecoder.stream_info.video_info.frames_per_second; - _VideoTime = 0f; + _VideoDecoderTime = 0f; _Time = 0f; for (int i = 0; i < _FrameBuffer.Length; i++) @@ -564,14 +561,14 @@ namespace Vocaluxe.Lib.Video if (!_FileOpened) return; - if (_Paused || _NoMoreFrames) + if (_Paused || _NoMoreFrames || _BufferFull) return; - if ((_NegativeSkipTime < 0f) && (_Time + _NegativeSkipTime >= 0f)) - _NegativeSkipTime = 0f; + if ((_SkipTime < 0f) && (_Time + _SkipTime >= 0f)) + _SkipTime = 0f; float myTime = _Time + _VideoSkipTime; - float TimeDifference = myTime - _VideoTime; + float TimeDifference = myTime - _VideoDecoderTime; bool DropFrame = false; if (TimeDifference >= (FRAMEDROPCOUNT - 1) * _VideoTimeBase) @@ -634,7 +631,6 @@ namespace Vocaluxe.Lib.Video lock (MutexSyncSignals) { - _ActualVideoTime = 0f; _Start = 0f; _Gap = 0f; _SetTime = 0f; @@ -655,6 +651,7 @@ namespace Vocaluxe.Lib.Video private void Copy() { int num = -1; + lock (MutexFramebuffer) { for (int i = 0; i < _FrameBuffer.Length; i++) @@ -667,24 +664,38 @@ namespace Vocaluxe.Lib.Video } if (num == -1) - _waiting = true; + { + _BufferFull = true; + EventDecode.Reset(); + } else { TAc_decoder Videodecoder = (TAc_decoder)Marshal.PtrToStructure(_videodecoder, typeof(TAc_decoder)); - _VideoTime = (float)Videodecoder.timecode; - _FrameBuffer[num].time = _VideoTime; + _VideoDecoderTime = (float)Videodecoder.timecode; + _FrameBuffer[num].time = _VideoDecoderTime; if (Videodecoder.buffer != IntPtr.Zero) { Marshal.Copy(Videodecoder.buffer, _FrameBuffer[num].data, 0, _Width * _Height * 4); - + _FrameBuffer[num].displayed = false; } - - _waiting = false; + + int numfull = 0; + for (int i = 0; i < _FrameBuffer.Length; i++) + { + if (!_FrameBuffer[i].displayed) + numfull++; + } + + if (numfull < _FrameBuffer.Length) + _BufferFull = false; } } + + if (!_BufferFull) + EventDecode.Set(); } private void UploadNewFrame(ref STexture frame) @@ -707,8 +718,13 @@ namespace Vocaluxe.Lib.Video { CDraw.UpdateTexture(ref frame, ref _FrameBuffer[num].data); } - _ActualVideoTime = _FrameBuffer[num].time; + + lock (MutexSyncSignals) + { + _CurrentVideoTime = _FrameBuffer[num].time; + } _Finished = false; + EventDecode.Set(); } else { @@ -716,7 +732,6 @@ namespace Vocaluxe.Lib.Video _Finished = true; } } - EventDecode.Set(); } private int FindFrame() @@ -728,27 +743,28 @@ namespace Vocaluxe.Lib.Video { float td = _SetTime + _VideoSkipTime - _FrameBuffer[i].time; + if (td > _VideoTimeBase * 2 || td < -1f * _VideoTimeBase * (_FrameBuffer.Length + 1)) + { + _FrameBuffer[i].displayed = true; + } + if (!_FrameBuffer[i].displayed && (td < diff) && (td > _VideoTimeBase)) { diff = Math.Abs(_FrameBuffer[i].time - _SetTime - _VideoSkipTime); Result = i; } - - if (td > _VideoTimeBase * 2) - _FrameBuffer[i].displayed = true; } if (Result != -1) + { _FrameBuffer[Result].displayed = true; + } return Result; } private void DoFree() { - if (_package != IntPtr.Zero) - CAcinerella.ac_free_package(_package); - if (_videodecoder != IntPtr.Zero) CAcinerella.ac_free_decoder(_videodecoder);