/// <summary>
        /// Waits for the frame extractor to be ready for playback.
        /// Returns true if successful, false if it timed out.
        /// </summary>
        private bool WaitForPlaybackReadyState()
        {
            RealtimeClock.Pause();

            var renderTime = RealtimeClock.PositionSeconds;
            var startTime  = DateTime.UtcNow;
            var cycleCount = -1;
            FFmpegMediaFrame playbackFrame = null;

            while (IsCancellationPending == false)
            {
                if (DateTime.UtcNow.Subtract(startTime) > Constants.WaitForPlaybackReadyStateTimeout)
                {
                    ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.WaitForPlaybackReadyState,
                                                                           MediaPlaybackErrorCode.WaitForPlaybackTimedOut,
                                                                           string.Format("Waiting for playback ready state @ {0:0.000} timed Out in {1} cycles", renderTime, cycleCount)));
                    return(false);
                }

                cycleCount++;

                // Wait for a decoding cycle.
                MediaFramesExtractedDone.Wait(Constants.FrameExtractorWaitMs);
                renderTime    = RealtimeClock.PositionSeconds;
                playbackFrame = PrimaryFramesCache.GetFrame(renderTime, CheckFrameBounds);

                if (playbackFrame == null && PrimaryFramesCache.Count > 0)
                {
                    playbackFrame = PrimaryFramesCache.FirstFrame;
                    RealtimeClock.PositionSeconds = playbackFrame.StartTime;
                }

                if (playbackFrame != null)
                {
                    break;
                }
            }

            // Do some additional logging
            System.Diagnostics.Debug.WriteLineIf(
                cycleCount >= 0,
                string.Format("WaitForPlaybackReadyState @ {0:0.000} = {1} cycles. Leading Frames: {2}, Frame Index: {3}, Frame Start: {4}",
                              renderTime,
                              cycleCount,
                              PrimaryFramesCache.Count,
                              PrimaryFramesCache.IndexOf(playbackFrame),
                              (playbackFrame != null ?
                               playbackFrame.StartTime.ToString("0.000") : "NULL")));

            return(true);
        }
 /// <summary>
 /// Queries if a leading frame for the given position is immediately available.
 /// </summary>
 /// <param name="position">The position.</param>
 /// <returns></returns>
 public bool QueryIsFrameAvailable(decimal position)
 {
     return(PrimaryFramesCache.GetFrame(position, true) != null);
 }
        /// <summary>
        /// Releases all managed and unmanaged resources
        /// </summary>
        public void Dispose()
        {
            if (IsCancellationPending)
            {
                return;
            }

            this.IsCancellationPending = true;

            this.VideoRenderTimer.Stop();

            if (this.AudioRenderer != null)
            {
                if (this.AudioRenderer.HasInitialized)
                {
                    this.AudioRenderer.Stop();
                }

                this.AudioRenderer.Dispose();
                this.AudioRenderer = null;
            }

            if (MediaFrameExtractorThread != null)
            {
                MediaFrameExtractorThread.Join();
                MediaFrameExtractorThread = null;
            }

            if (MediaFramesExtractedDone != null)
            {
                try
                {
                    MediaFramesExtractedDone.Dispose();
                    MediaFramesExtractedDone = null;
                }
                finally { }
            }

            if (PrimaryFramesCache != null)
            {
                PrimaryFramesCache.Clear();
                PrimaryFramesCache = null;
            }

            if (SecondaryFramesCache != null)
            {
                SecondaryFramesCache.Clear();
                SecondaryFramesCache = null;
            }

            if (VideoCodecContext != null)
            {
                fixed(AVCodecContext **videoCodecContextRef = &VideoCodecContext)
                {
                    ffmpeg.avcodec_close(VideoCodecContext);
                    ffmpeg.avcodec_free_context(videoCodecContextRef);
                    VideoCodecContext = null;
                }
            }

            if (AudioCodecContext != null)
            {
                fixed(AVCodecContext **audioCodecContextRef = &AudioCodecContext)
                {
                    ffmpeg.avcodec_close(AudioCodecContext);
                    ffmpeg.avcodec_free_context(audioCodecContextRef);
                    AudioCodecContext = null;
                }
            }

            if (VideoResampler != null)
            {
                ffmpeg.sws_freeContext(VideoResampler);
                VideoResampler = null;
            }

            if (AudioResampler != null)
            {
                fixed(SwrContext **audioResamplerRef = &AudioResampler)
                {
                    ffmpeg.swr_close(AudioResampler);
                    ffmpeg.swr_free(audioResamplerRef);
                    AudioResampler = null;
                }
            }

            if (InputFormatContext != null)
            {
                fixed(AVFormatContext **inputFormatContextRef = &InputFormatContext)
                {
                    ffmpeg.avformat_close_input(inputFormatContextRef);
                    ffmpeg.avformat_free_context(InputFormatContext);
                    InputFormatContext = null;
                }
            }

            if (DecodedPictureHolder != null)
            {
                ffmpeg.av_free(DecodedPictureHolder);
                DecodedPictureHolder = null;
            }

            if (DecodedWaveHolder != null)
            {
                ffmpeg.av_free(DecodedWaveHolder);
                DecodedWaveHolder = null;
            }
        }