RemoveFirst() public method

Removes the first frame and releases it.
public RemoveFirst ( ) : void
return void
Beispiel #1
0
        private void InternalFillFramesCache(TimeSpan timeout)
        {
            var startTime = DateTime.UtcNow;

            while (LeadingFramesCache.IsFull == false && IsAtEndOfStream == false)
            {
                if (DateTime.UtcNow.Subtract(startTime).Ticks > timeout.Ticks)
                {
                    ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalFillFamesCache, MediaPlaybackErrorCode.FillFramesFailed,
                                                                           string.Format("Fill Frames Cache = Failed to fill cache in {0}; Leading Frames: {1}; Lagging Frames: {2}",
                                                                                         timeout, LeadingFramesCache.Count, LaggingFramesCache.Count)));

                    return;
                }

                var frame = this.PullMediaFrame();
                if (frame != null)
                {
                    // reset the start time because we are in fact getting frames.
                    startTime = DateTime.UtcNow;

                    if (frame.Type == LeadingFramesCache.Type)
                    {
                        LeadingFramesCache.Add(frame);
                    }
                    else if (frame.Type == LaggingFramesCache.Type)
                    {
                        if (LaggingFramesCache.IsFull)
                        {
                            LaggingFramesCache.RemoveFirst();
                        }

                        LaggingFramesCache.Add(frame);
                    }
                }
            }
        }
Beispiel #2
0
        private void InternalLoadFrames(decimal renderTime)
        {
            if (renderTime < StartTime)
            {
                renderTime = StartTime;
            }
            if (IsAtEndOfStream && LeadingFramesCache.Count > 0 && renderTime >= LeadingFramesCache.EndTime)
            {
                renderTime = LeadingFramesCache.EndTime;
            }

            // The very first thing we do is fill the buffer if it is empty
            if (this.LeadingFramesCache.IsEmpty)
            {
                this.InternalFillFramesCache(Constants.FrameExtractorFillTimeout);

                if (LeadingFramesCache.Count > 0)
                {
                    if (FirstLeadingFrameTime == null)
                    {
                        FirstLeadingFrameTime = LeadingFramesCache.FirstFrameTime;
                    }

                    if (IsLiveStream)
                    {
                        RealtimeClock.Seek(LeadingFramesCache.FirstFrameTime);
                        RealtimeClock.Play();
                        return;
                    }
                }
            }

            var renderFrame      = LeadingFramesCache.GetFrame(renderTime, CheckFrameBounds);
            var renderFrameIndex = LeadingFramesCache.IndexOf(renderFrame);
            var renderFrameFound = renderFrameIndex >= 0;

            // if we can't find the frame . . .
            if (renderFrameFound == false)
            {
                // Perform the seek operation
                this.InternalSeekInput(renderTime);
                renderTime = RealtimeClock.PositionSeconds;

                // try to find the frame now that we have stuff
                var seekFrame = LeadingFramesCache.GetFrame(renderTime, CheckFrameBounds);

                if (seekFrame != null)
                {
                    // seek is successful at this point
                    RealtimeClock.Seek(renderTime);
                    PcmAudioProvider.Clear();
                }
                else
                {
                    // got some frames but not the ones we asked for

                    if (this.LeadingFramesCache.Count > 0)
                    {
                        if (IsAtEndOfStream)
                        {
                            RealtimeClock.Seek(this.LeadingFramesCache.MiddleFrameTime);
                        }
                        else
                        {
                            if (InternalGetIsInFirstTimeSegment(renderTime))
                            {
                                RealtimeClock.Seek(renderTime);
                                ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalLoadFrames, MediaPlaybackErrorCode.LoadFramesFailedInFirstSegment,
                                                                                       string.Format("Could not find frames at {0:0.000} (On first time segment). First Leading Frame occurs at {1:0.000}",
                                                                                                     renderTime, LeadingFramesCache.FirstFrameTime)));
                            }
                            else
                            {
                                RealtimeClock.Seek(this.LeadingFramesCache.LastFrameTime);
                                ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalLoadFrames, MediaPlaybackErrorCode.LoadFramesFailedForCurrentPosition,
                                                                                       string.Format("Could not find frames at {0:0.000} (NOT on first segment). Last Leading Frame occurs at {1:0.000} - This should not have occurred.",
                                                                                                     renderTime, LeadingFramesCache.LastFrameTime)));
                            }
                        }
                    }
                    else
                    {
                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalLoadFrames, MediaPlaybackErrorCode.LoadFramesFailedCritical,
                                                                               string.Format("Could not find frames at {0:0.000} and no Leading Frames exist in the cache - Critical Error.",
                                                                                             renderTime)));
                    }
                }

                return;
            }
            else
            {
                var isInLastTimeSegment  = InternalGetIsInLastTimeSegment(renderTime);
                var isInFirstTimeSegment = InternalGetIsInFirstTimeSegment(renderTime);

                // frward lookup
                if (renderFrameIndex > LeadingFramesCache.MiddleIndex)
                {
                    if (isInLastTimeSegment == false)
                    {
                        if (LeadingFramesCache.IsFull)
                        {
                            var removalCount = 1;

                            if (SpeedRatio >= Constants.DefaultSpeedRatio)
                            {
                                removalCount = (int)Math.Ceiling(SpeedRatio);
                            }

                            removalCount = Math.Min(LeadingFramesCache.Count / 4, removalCount);

                            for (var i = 1; i <= removalCount; i++)
                            {
                                LeadingFramesCache.RemoveFirst();
                            }
                        }

                        this.InternalFillFramesCache(Constants.FrameExtractorFillTimeout);
                        return;
                    }
                    else
                    {
                        if (renderFrameIndex >= LeadingFramesCache.Count - 1)
                        {
                            // All input has been processed up to the last frame now.
                            RealtimeClock.Seek(LeadingFramesCache.EndTime);
                            return;
                        }
                    }
                }

                // backward lookup
                if (renderFrameIndex <= 1 && isInFirstTimeSegment == false && IsLiveStream == false)
                {
                    InternalSeekInput(LeadingFramesCache.StartTime);
                    var frame = LeadingFramesCache.GetFrame(renderTime, CheckFrameBounds);
                    if (frame != null)
                    {
                        RealtimeClock.Seek(renderTime);
                    }
                    else
                    {
                        RealtimeClock.Seek(LeadingFramesCache.MiddleFrame != null ? LeadingFramesCache.MiddleFrame.StartTime : 0M);
                    }

                    return;
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Internals the seek input.
        /// </summary>
        /// <param name="renderTime">The render time.</param>
        private void InternalSeekInput(decimal renderTime)
        {
            if (IsLiveStream)
            {
                if (LeadingFramesCache.IsEmpty == false)
                {
                    RealtimeClock.Seek(LeadingFramesCache.FirstFrameTime);
                }

                return;
            }

#if DEBUG
            var seekStopwatch = new System.Diagnostics.Stopwatch();
            seekStopwatch.Start();
#endif

            if (renderTime < StartTime)
            {
                renderTime = StartTime;
            }

            RealtimeClock.Seek(renderTime);

            var allowedThreshold = Constants.SeekThresholdSeconds;
            var seekOffsetLength = Constants.SeekOffsetSeconds;

            var seekTime         = renderTime - seekOffsetLength;
            var maxSeekStartTime = seekTime - allowedThreshold;

            var bufferedLeadingFrames = new FFmpegMediaFrameCache(LeadingFramesCache);
            var bufferedLaggingFrames = new FFmpegMediaFrameCache(LaggingFramesCache);

            var outerLoopCount        = 0;
            var innerLoopCount        = 0;
            var frameReleaseCount     = 0;
            var doSeekInStream        = true;
            var doSeekByPullingFrames = true;
            var seekFlag            = 0;
            var seekFrameResult     = 0;
            var startTime           = DateTime.UtcNow;
            var lastFailedTimestamp = long.MinValue;
            var seekToLastFrame     = false;

            var seekTimeBase      = LeadingFramesCache.Type == MediaFrameType.Video ? InputVideoStream->time_base : InputAudioStream->time_base;
            var seekStreamIndex   = LeadingFramesCache.Type == MediaFrameType.Video ? InputVideoStream->index : InputAudioStream->index;
            var leadingFrameIndex = -1;

            try
            {
                while (doSeekInStream)
                {
                    outerLoopCount++;

                    if (seekTime < StartTime)
                    {
                        seekTime = StartTime;
                    }

                    if (lastFailedTimestamp == StartDts)
                    {
                        if (LeadingFramesCache.IsEmpty == false)
                        {
                            RealtimeClock.Seek(LeadingFramesCache.FirstFrameTime);
                        }

                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalSeekInput, MediaPlaybackErrorCode.SeekFailedCritical,
                                                                               string.Format("Target Postion @ {0:0.000}s has already failed to seek. First DTS {1} also failed and will not retry.", seekTime, StartDts)));

                        return;
                    }

                    var targetTimestamp = Helper.SecondsToTimestamp(seekTime, seekTimeBase);
                    if (lastFailedTimestamp == targetTimestamp)
                    {
                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalSeekInput, MediaPlaybackErrorCode.SeekFailedWillRetry,
                                                                               string.Format("Target Postion @ {0:0.000}s has already failed to seek. Target timestamp will now be First DTS {1}.", seekTime, StartDts)));

                        targetTimestamp = StartDts;
                    }

                    seekFlag = (seekTime < renderTime || seekTime <= StartTime ? (int)ffmpeg.AVSEEK_FLAG_BACKWARD : 0) | 0; // FFmpegInvoke.AVSEEK_FLAG_ANY;
                    //seekFlag = FFmpegInvoke.AVSEEK_FLAG_BACKWARD; // | FFmpegInvoke.AVSEEK_FLAG_ANY;

                    seekFrameResult = ffmpeg.av_seek_frame(InputFormatContext, seekStreamIndex, targetTimestamp, seekFlag); // significantly faster than seek_file
                    //seekFrameResult = FFmpegInvoke.avformat_seek_file(InputFormatContext, streamIndex, long.MinValue, targetTimestamp, long.MaxValue, seekFlag);
                    if (seekFrameResult < Constants.SuccessCode)
                    {
                        if (LeadingFramesCache.IsEmpty == false)
                        {
                            RealtimeClock.Seek(LeadingFramesCache.FirstFrameTime);
                        }

                        var errorMessage = Helper.GetFFmpegErrorMessage(seekFrameResult);
                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalSeekInput, MediaPlaybackErrorCode.SeekFailedFFmpeg,
                                                                               string.Format("FFmpeg av_seek_frame @ {1:0.000}: Failed with error code {0}. {2}", seekFrameResult, seekTime, errorMessage)));

                        return;
                    }
                    else
                    {
                        if (VideoCodecContext != null)
                        {
                            ffmpeg.avcodec_flush_buffers(VideoCodecContext);
                        }

                        if (AudioCodecContext != null)
                        {
                            ffmpeg.avcodec_flush_buffers(AudioCodecContext);
                        }
                    }

                    leadingFrameIndex = -1;
                    bufferedLeadingFrames.Clear();
                    bufferedLaggingFrames.Clear();

                    doSeekInStream        = false;
                    doSeekByPullingFrames = true;

                    while (doSeekByPullingFrames)
                    {
                        innerLoopCount++;

                        var frame = this.PullMediaFrame();
                        if (frame != null)
                        {
                            if (frame.StartTime < maxSeekStartTime)
                            {
                                frame.EnqueueRelease();
                                frameReleaseCount++;
                                continue;
                            }

                            if (frame.Type == bufferedLeadingFrames.Type)
                            {
                                leadingFrameIndex++;
                                if (leadingFrameIndex == 0 && frame.Type == bufferedLeadingFrames.Type && frame.StartTime - frame.Duration > maxSeekStartTime && maxSeekStartTime > 0M)
                                {
                                    seekTime -= seekOffsetLength;
                                    frame.EnqueueRelease();
                                    doSeekInStream      = true;
                                    lastFailedTimestamp = targetTimestamp;
                                    break;
                                }

                                // We are Full minus 1 at this point. We'll stop buffering
                                if (bufferedLeadingFrames.Count >= bufferedLeadingFrames.Capacity - 1)
                                {
                                    doSeekByPullingFrames = false;
                                }

                                bufferedLeadingFrames.Add(frame);
                            }
                            else if (frame.Type == bufferedLaggingFrames.Type)
                            {
                                // add the lagging frame no matter what
                                if (bufferedLaggingFrames.IsFull)
                                {
                                    bufferedLaggingFrames.RemoveFirst();
                                }

                                bufferedLaggingFrames.Add(frame);
                            }

                            // Find out if we have the frame
                            var seekFrameIndex    = bufferedLeadingFrames.IndexOf(renderTime, true);
                            var minimumFrameCount = (seekFrameIndex - 1) * 2;

                            // if we have more than enough frames in the buffer or we have reached a full or end condition, stop buffering frames
                            if (seekFrameIndex > 0)
                            {
                                if (bufferedLeadingFrames.Count >= minimumFrameCount || bufferedLeadingFrames.IsFull || IsAtEndOfStream)
                                {
                                    doSeekByPullingFrames = false;
                                }
                            }
                        }

                        // We're already padt the end of the stream. Natural duration was wron for the leading frames cache.
                        if (IsAtEndOfStream && bufferedLeadingFrames.Count <= 0)
                        {
                            doSeekInStream   = true;
                            seekTime        -= seekOffsetLength;
                            maxSeekStartTime = seekTime - allowedThreshold;
                            seekToLastFrame  = true;
                        }

                        if (doSeekInStream)
                        {
                            break;
                        }

                        if (doSeekByPullingFrames == false || IsAtEndOfStream)
                        {
                            LeadingFramesCache.Replace(bufferedLeadingFrames);
                            LaggingFramesCache.Replace(bufferedLaggingFrames);

                            if (seekToLastFrame && LeadingFramesCache.Count > 0)
                            {
                                RealtimeClock.Seek(LeadingFramesCache.LastFrameTime);
                            }

                            return;
                        }
                    }
                }
            }
            finally
            {
#if DEBUG
                seekStopwatch.Stop();
                SeekTimes.Add(seekStopwatch.ElapsedMilliseconds);
                InnerLoopCounts.Add(innerLoopCount);
                System.Diagnostics.Debug.WriteLine("Seek @ {6:0.000} = Long: {0:00}\t Short: {1:000}\t Short (AVG): {2:0.000}\t Waste Count: {3:000}\t Elapsed: {4}\tElapsed (AVG): {5:0.000}",
                                                   outerLoopCount, innerLoopCount, InnerLoopCounts.Average(), frameReleaseCount, seekStopwatch.ElapsedMilliseconds, SeekTimes.Average(), renderTime);
#endif
            }
        }
Beispiel #4
0
        /// <summary>
        /// Internals the seek input.
        /// </summary>
        /// <param name="renderTime">The render time.</param>
        private void InternalSeekInput(decimal renderTime)
        {
            if (IsLiveStream)
            {
                if (PrimaryFramesCache.IsEmpty == false)
                    RealtimeClock.Seek(PrimaryFramesCache.FirstFrameTime);

                return;
            }

#if DEBUG
            var seekStopwatch = new System.Diagnostics.Stopwatch();
            seekStopwatch.Start();
#endif

            if (renderTime < StartTime)
                renderTime = StartTime;

            RealtimeClock.Seek(renderTime);

            var allowedThreshold = Constants.SeekThresholdSeconds;
            var seekOffsetLength = Constants.SeekOffsetSeconds;

            var seekTime = renderTime - seekOffsetLength;
            var maxSeekStartTime = seekTime - allowedThreshold;

            var bufferedLeadingFrames = new FFmpegMediaFrameCache(PrimaryFramesCache);
            var bufferedLaggingFrames = new FFmpegMediaFrameCache(SecondaryFramesCache);

            var outerLoopCount = 0;
            var innerLoopCount = 0;
            var frameReleaseCount = 0;
            var doSeekInStream = true;
            var doSeekByPullingFrames = true;
            var seekFlag = 0;
            var seekFrameResult = 0;
            var startTime = DateTime.UtcNow;
            var lastFailedTimestamp = long.MinValue;
            var seekToLastFrame = false;

            var seekTimeBase = PrimaryFramesCache.Type == MediaFrameType.Video ? InputVideoStream->time_base : InputAudioStream->time_base;
            var seekStreamIndex = PrimaryFramesCache.Type == MediaFrameType.Video ? InputVideoStream->index : InputAudioStream->index;
            var leadingFrameIndex = -1;

            try
            {
                while (doSeekInStream)
                {
                    outerLoopCount++;

                    if (seekTime < StartTime) seekTime = StartTime;

                    if (lastFailedTimestamp == StartDts)
                    {
                        if (PrimaryFramesCache.IsEmpty == false)
                            RealtimeClock.Seek(PrimaryFramesCache.FirstFrameTime);

                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalSeekInput, MediaPlaybackErrorCode.SeekFailedCritical,
                            string.Format("Target Postion @ {0:0.000}s has already failed to seek. First DTS {1} also failed and will not retry.", seekTime, StartDts)));

                        return;
                    }

                    var targetTimestamp = Helper.SecondsToTimestamp(seekTime, seekTimeBase);
                    if (lastFailedTimestamp == targetTimestamp)
                    {
                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalSeekInput, MediaPlaybackErrorCode.SeekFailedWillRetry,
                            string.Format("Target Postion @ {0:0.000}s has already failed to seek. Target timestamp will now be First DTS {1}.", seekTime, StartDts)));

                        targetTimestamp = StartDts;
                    }

                    seekFlag = (seekTime < renderTime || seekTime <= StartTime ? (int)ffmpeg.AVSEEK_FLAG_BACKWARD : 0) | 0; // FFmpegInvoke.AVSEEK_FLAG_ANY;
                    //seekFlag = ffmpeg.AVSEEK_FLAG_BACKWARD; // | ffmpeg.AVSEEK_FLAG_ANY;
                    
                    seekFrameResult = ffmpeg.av_seek_frame(InputFormatContext, seekStreamIndex, targetTimestamp, seekFlag); // significantly faster than seek_file
                    //seekFrameResult = ffmpeg.avformat_seek_file(InputFormatContext, seekStreamIndex, targetTimestamp - 2, targetTimestamp, targetTimestamp + 2, seekFlag);
                    if (seekFrameResult < Constants.SuccessCode)
                    {
                        if (PrimaryFramesCache.IsEmpty == false)
                            RealtimeClock.Seek(PrimaryFramesCache.FirstFrameTime);

                        var errorMessage = Helper.GetFFmpegErrorMessage(seekFrameResult);
                        ErrorOccurredCallback(this, new MediaPlaybackException(MediaPlaybackErrorSources.InternalSeekInput, MediaPlaybackErrorCode.SeekFailedFFmpeg,
                            string.Format("FFmpeg av_seek_frame @ {1:0.000}: Failed with error code {0}. {2}", seekFrameResult, seekTime, errorMessage)));

                        return;
                    }
                    else
                    {
                        if (VideoCodecContext != null)
                            ffmpeg.avcodec_flush_buffers(VideoCodecContext);

                        if (AudioCodecContext != null)
                            ffmpeg.avcodec_flush_buffers(AudioCodecContext);
                    }

                    leadingFrameIndex = -1;
                    bufferedLeadingFrames.Clear();
                    bufferedLaggingFrames.Clear();

                    doSeekInStream = false;
                    doSeekByPullingFrames = true;

                    while (doSeekByPullingFrames)
                    {
                        innerLoopCount++;

                        var frame = this.PullMediaFrame();
                        if (frame != null)
                        {
                            if (frame.StartTime < maxSeekStartTime)
                            {
                                frame.EnqueueRelease();
                                frameReleaseCount++;
                                continue;
                            }

                            if (frame.Type == bufferedLeadingFrames.Type)
                            {
                                leadingFrameIndex++;
                                if (leadingFrameIndex == 0 && frame.Type == bufferedLeadingFrames.Type && frame.StartTime - frame.Duration > maxSeekStartTime && maxSeekStartTime > 0M)
                                {
                                    seekTime -= seekOffsetLength;
                                    frame.EnqueueRelease();
                                    doSeekInStream = true;
                                    lastFailedTimestamp = targetTimestamp;
                                    break;
                                }

                                // We are Full minus 1 at this point. We'll stop buffering
                                if (bufferedLeadingFrames.Count >= bufferedLeadingFrames.Capacity - 1)
                                    doSeekByPullingFrames = false;

                                bufferedLeadingFrames.Add(frame);
                            }
                            else if (frame.Type == bufferedLaggingFrames.Type)
                            {
                                // add the lagging frame no matter what
                                if (bufferedLaggingFrames.IsFull)
                                    bufferedLaggingFrames.RemoveFirst();

                                bufferedLaggingFrames.Add(frame);
                            }

                            // Find out if we have the frame
                            var seekFrameIndex = bufferedLeadingFrames.IndexOf(renderTime, true);
                            var minimumFrameCount = (seekFrameIndex - 1) * 2;

                            // if we have more than enough frames in the buffer or we have reached a full or end condition, stop buffering frames
                            if (seekFrameIndex > 0)
                                if (bufferedLeadingFrames.Count >= minimumFrameCount || bufferedLeadingFrames.IsFull || IsAtEndOfStream)
                                    doSeekByPullingFrames = false;

                        }

                        // We're already padt the end of the stream. Natural duration was wron for the leading frames cache.
                        if (IsAtEndOfStream && bufferedLeadingFrames.Count <= 0)
                        {
                            doSeekInStream = true;
                            seekTime -= seekOffsetLength;
                            maxSeekStartTime = seekTime - allowedThreshold;
                            seekToLastFrame = true;
                        }

                        if (doSeekInStream)
                            break;

                        if (doSeekByPullingFrames == false || IsAtEndOfStream)
                        {
                            PrimaryFramesCache.Replace(bufferedLeadingFrames);
                            SecondaryFramesCache.Replace(bufferedLaggingFrames);

                            if (seekToLastFrame && PrimaryFramesCache.Count > 0)
                                RealtimeClock.Seek(PrimaryFramesCache.LastFrameTime);

                            return;
                        }
                    }
                }
            }
            finally
            {
#if DEBUG
                seekStopwatch.Stop();
                SeekTimes.Add(seekStopwatch.ElapsedMilliseconds);
                InnerLoopCounts.Add(innerLoopCount);
                System.Diagnostics.Debug.WriteLine("Seek @ {6:0.000} = Long: {0:00}\t Short: {1:000}\t Short (AVG): {2:0.000}\t Waste Count: {3:000}\t Elapsed: {4}\tElapsed (AVG): {5:0.000}",
                    outerLoopCount, innerLoopCount, InnerLoopCounts.Average(), frameReleaseCount, seekStopwatch.ElapsedMilliseconds, SeekTimes.Average(), renderTime);
#endif
            }

        }