private bool _OpenVideoStream() { int videoStreamIndex; SACDecoder decoder; try { _Videodecoder = CAcinerella.AcCreateVideoDecoder(_Instance); decoder = (SACDecoder)Marshal.PtrToStructure(_Videodecoder, typeof(SACDecoder)); videoStreamIndex = decoder.StreamIndex; } catch (Exception) { CLog.LogError("Error opening video file (can't find decoder): " + _FileName); return(false); } if (videoStreamIndex < 0) { return(false); } _Width = decoder.StreamInfo.VideoInfo.FrameWidth; _Height = decoder.StreamInfo.VideoInfo.FrameHeight; if (decoder.StreamInfo.VideoInfo.FramesPerSecond > 0) { _FrameDuration = 1f / (float)decoder.StreamInfo.VideoInfo.FramesPerSecond; } _Framebuffer.Init(_Width * _Height * 4); _FrameAvailable = false; return(true); }
private void _Decode() { const int minFrameDropCount = 4; // With => seekThreshold frames to drop use seek instead of skip const int seekThreshold = 25; // 25 frames = 0.5 second with _FrameDuration = 0.02f if (_NoMoreFrames) { return; } float videoTime = RequestTime; float timeDifference = videoTime - _LastDecodedTime; bool dropFrame = timeDifference >= (minFrameDropCount - 1) * _FrameDuration; bool hasFrameDecoded = false; if (dropFrame) { var frameDropCount = (int)Math.Ceiling(timeDifference / _FrameDuration); if (!_DropSeekEnabled || frameDropCount < seekThreshold) { hasFrameDecoded = _DropWithSkip(frameDropCount); } else { hasFrameDecoded = _DropWithSeek(videoTime, frameDropCount); } } if (!hasFrameDecoded) { try { hasFrameDecoded = CAcinerella.AcGetFrame(_Instance, _Videodecoder); } catch (Exception) { CLog.LogError("Error AcGetFrame " + _FileName); } } if (hasFrameDecoded) { _FrameAvailable = true; } else { if (Loop) { RequestTime = _LoopedRequestTime; _Skip(); } else { _NoMoreFrames = true; } } }
//Just call this if thread is not alive private void _Free() { if (_Videodecoder != IntPtr.Zero) { CAcinerella.AcFreeDecoder(_Videodecoder); } if (_Instance != IntPtr.Zero) { CAcinerella.AcClose(_Instance); CAcinerella.AcFree(_Instance); } }
private bool _DropWithSkip(int frameDropCount) { bool hasFrameDecoded = false; // Add 1 dropped frame per 16 frames (Power of 2 -> Div is fast) as skipping takes time too and we don't want to skip again frameDropCount += frameDropCount / 16; try { hasFrameDecoded = CAcinerella.AcSkipFrames(_Instance, _Videodecoder, frameDropCount); } catch (Exception) { CLog.LogError("Error AcSkipFrame " + _FileName); } return(hasFrameDecoded); }
// Skip to a given time (in s) private void _Skip() { float skipTime = RequestTime; //Copy to variable to have consistent checks if (skipTime < 0 || skipTime >= Length) { skipTime = 0; } try { CAcinerella.AcSeek(_Videodecoder, -1, (Int64)(skipTime * 1000f)); } catch (Exception e) { CLog.LogError("Error seeking video file \"" + _FileName + "\": " + e.Message); } _LastDecodedTime = skipTime; _FrameAvailable = false; }
private bool _DropWithSeek(float videoTime, int frameDropCount) { bool hasFrameDecoded = false; try { hasFrameDecoded = CAcinerella.AcSeek(_Videodecoder, 0, (long)videoTime * 1000L); } catch (Exception) { CLog.LogError("Error AcSeek " + _FileName); } if (!hasFrameDecoded) { // Fallback to frame skipping _DropSeekEnabled = false; hasFrameDecoded = _DropWithSkip(frameDropCount); } return(hasFrameDecoded); }
//Open the file and get the length. public bool LoadFile(String fileName) { _FileName = fileName; try { _Instance = CAcinerella.AcInit(); CAcinerella.AcOpen2(_Instance, fileName); var instance = (SACInstance)Marshal.PtrToStructure(_Instance, typeof(SACInstance)); Length = instance.Info.Duration / 1000f; bool ok = instance.Opened && Length > 0.001f; _DropSeekEnabled = true; if (ok) { return(true); } _Free(); } catch (Exception) {} CLog.LogError("Error opening video file: " + _FileName); _Instance = IntPtr.Zero; return(false); }