public override BufferedFramesState GetBufferedFramesState()
        {
            BufferedFramesState state = new BufferedFramesState();

            Native.GetBufferedFramesState(_instance, ref state);
            return(state);
        }
        private void LogBufferState()
        {
            BufferedFramesState state = GetBufferedFramesState();
            long   timeStamp          = GetTextureTimeStamp();
            string result             = string.Format("[AVProVideo] {4} - {2},{3}\t\t{0}-{1}   ({5})", state.minTimeStamp, state.maxTimeStamp, state.bufferedFrameCount, state.freeFrameCount, timeStamp, Time.deltaTime);

            Debug.Log(result);
        }
        internal override long InternalUpdateBufferedDisplay()
        {
            BufferedFramesState state = GetBufferedFramesState();

            if (state.bufferedFrameCount > 0)
            {
                if (_frameSelectionMode == BufferedFrameSelectionMode.NewestFrame)
                {
                    SetBufferedDisplayTime(_frameSelectionMode, -1, false);
                }
                else if (_frameSelectionMode == BufferedFrameSelectionMode.OldestFrame)
                {
                    SetBufferedDisplayTime(_frameSelectionMode, -1, false);
                }
                else if (_frameSelectionMode == BufferedFrameSelectionMode.ElapsedTime ||
                         _frameSelectionMode == BufferedFrameSelectionMode.ElapsedTimeVsynced)
                {
                    // Only start consuming frames on these conditions
                    bool needsInitialFrame     = (_textureFrame.texturePointer == System.IntPtr.Zero || _needsInitialFrame);
                    bool playingBufferedFrames = (IsPrerollComplete() && (IsPlaying() || (!IsPlaying() && IsFinished())));
                    if (needsInitialFrame || playingBufferedFrames)
                    {
                        if (needsInitialFrame)
                        {
                            if (SetBufferedDisplayTime(BufferedFrameSelectionMode.OldestFrame, -1, true))
                            {
                                _displayClockTime  = _textureFrame.timeStamp;
                                _needsInitialFrame = false;
                            }
                        }
                        else
                        {
                            // TODO: run without vsync, just show next frame (use media clock for present?)
                            // use our own clock...
                            const double SecondsToHNS       = 10000000.0;
                            double       videoFrameDuration = SecondsToHNS / (double)GetVideoFrameRate();
                            long         videoDuration      = (long)Math.Floor(SecondsToHNS * GetDuration());
                            long         lastFrameTime      = Math.Max(videoDuration, state.maxTimeStamp);
                            double       delta = SecondsToHNS * Time.deltaTime;

                            if (_frameSelectionMode == BufferedFrameSelectionMode.ElapsedTimeVsynced && QualitySettings.vSyncCount > 0)
                            {
                                // Since we're running with vsync enabled, the MINIMUM elapsed time will be 1 monitor refresh (multiplied by QualitySettings.vSyncCount)
                                double monitorDuration = (QualitySettings.vSyncCount * SecondsToHNS) / (double)Screen.currentResolution.refreshRate;

                                int wholeFrames = (int)System.Math.Floor(_timeAccumulation / monitorDuration);
                                wholeFrames = System.Math.Max(1, wholeFrames);
                                delta       = monitorDuration * wholeFrames;

                                //LogBufferState();
                                if (wholeFrames > 1)
                                {
                                    //Debug.Log(Time.frameCount + "] " + Time.deltaTime + " " + wholeFrames + " " + _timeAccumulation + " " + _timeAccumulation / SecondsToHNS);
                                    //LogBufferState();
                                }

                                _timeAccumulation += (Time.deltaTime * SecondsToHNS) - delta;

                                //delta = monitorDuration;

                                /*double actualFrameDuration = Time.deltaTime * SecondsToHNS;
                                 * double idealFrameTimeDifference = (actualFrameDuration);// - minMonitorDuration);
                                 * if (idealFrameTimeDifference > (minMonitorDuration / 2))
                                 * {
                                 *      int droppedFrames = (int)Math.Round(idealFrameTimeDifference / minMonitorDuration);
                                 *      //Debug.Log(Time.maximumDeltaTime + " " + Time.deltaTime + " " + actualFrameDuration + " " + idealFrameTimeDifference + " = " + droppedFrames);
                                 *      delta += minMonitorDuration * droppedFrames;
                                 *
                                 *      //LogBufferState();
                                 * }
                                 * else
                                 * {
                                 *      //Debug.Log(Time.deltaTime);
                                 * }
                                 * // If we're running slower than this or there is a frame drop, the elapsed time will be a multiple
                                 * // of the monitor refresh rate
                                 */
                            }

                            _displayClockTime += delta;

                            int  multiple         = (int)videoFrameDuration;
                            long snappedFrameTime = (long)Math.Floor(_displayClockTime / multiple) * multiple;
                            if (_isLooping && snappedFrameTime > lastFrameTime)
                            {
                                snappedFrameTime  %= lastFrameTime;
                                _needsInitialFrame = true;
                            }
                            else
                            {
                                snappedFrameTime = Math.Min(snappedFrameTime, lastFrameTime);
                            }

                            if (System.Math.Abs(snappedFrameTime - _textureFrame.timeStamp) > 1000)
                            {
                                //Debug.Log("1 " + _displayClockTime + " > " + snappedFrameTime + " d:" + delta);
                                //LogBufferState();

                                if (_needsInitialFrame)
                                {
                                    if (SetBufferedDisplayTime(BufferedFrameSelectionMode.OldestFrame, -1, true))
                                    {
                                        _displayClockTime = _textureFrame.timeStamp;
                                        //Debug.Log("initial: " + _displayClockTime);
                                        _needsInitialFrame = false;
                                    }
                                }
                                else if (!SetBufferedDisplayTime(_frameSelectionMode, snappedFrameTime, false))
                                {
                                    //Debug.LogWarning("[AVProVideo] failed to set time at " + snappedFrameTime);
                                    //LogBufferState();

                                    // Try to snap to oldest buffered time
                                    _displayClockTime = (state.minTimeStamp + state.maxTimeStamp) / 2.0;
                                    snappedFrameTime  = (long)Math.Floor(_displayClockTime / multiple) * multiple;
                                    if (_isLooping && snappedFrameTime > lastFrameTime)
                                    {
                                        snappedFrameTime %= lastFrameTime;
                                    }
                                    else
                                    {
                                        snappedFrameTime = Math.Min(snappedFrameTime, lastFrameTime);
                                    }

                                    if (SetBufferedDisplayTime(BufferedFrameSelectionMode.FromExternalTimeClosest, snappedFrameTime, false))
                                    {
                                        _displayClockTime = _textureFrame.timeStamp;
                                        //Debug.LogWarning("[AVProVideo] Good set: " + _displayClockTime);
                                    }
                                    else
                                    {
                                        //Debug.LogWarning("[AVProVideo] Failed to display frame time " + snappedFrameTime);
                                        //LogBufferState();
                                    }
                                }
                            }
                        }
                    }
                }
                else if (_frameSelectionMode == BufferedFrameSelectionMode.FromExternalTime)
                {
                    if (_masterDisplay != null)
                    {
                        // Use the time from the master
                        long timeStamp = _masterDisplay.UpdateBufferedDisplay();
                        if (timeStamp != GetTextureTimeStamp())
                        {
                            if (!SetBufferedDisplayTime(BufferedFrameSelectionMode.FromExternalTimeClosest, timeStamp, false))
                            {
                                Debug.LogWarning("[AVProVideo] Failed to display frame using external clock at time " + timeStamp);
                            }
                        }
                    }
                }
            }

            return(GetTextureTimeStamp());
        }
 public static extern bool GetBufferedFramesState(System.IntPtr playerInstance, ref BufferedFramesState state);