diff --git a/src/ui/Logic/VideoPlayers/Ffmpeg/FfmpegPlayer.cs b/src/ui/Logic/VideoPlayers/Ffmpeg/FfmpegPlayer.cs index 9d9e4deda3..bb89c75d03 100644 --- a/src/ui/Logic/VideoPlayers/Ffmpeg/FfmpegPlayer.cs +++ b/src/ui/Logic/VideoPlayers/Ffmpeg/FfmpegPlayer.cs @@ -816,6 +816,7 @@ private void VideoLoop() : 1.0 / 25.0; var serial = -1; + var minimumReplaySerial = -1; var dropUntil = -1.0; var presentedForSerial = false; VideoFrame? lastDropped = null; // kept so a target past the last picture still shows something @@ -827,6 +828,19 @@ private void VideoLoop() continue; } + if (minimumReplaySerial >= 0 && entry.Serial < minimumReplaySerial) + { + var stalePacket = entry.Packet; + if (stalePacket != null) + { + ffmpeg.av_packet_free(&stalePacket); + } + + continue; + } + + minimumReplaySerial = -1; + if (entry.Serial != serial) { ffmpeg.avcodec_flush_buffers(codec); @@ -851,6 +865,7 @@ private void VideoLoop() // The hardware decoder rejected the stream - retry it in software. codec = FallBackToSoftware(codec, stream, sendResult, ref hardware); serial = -1; + minimumReplaySerial = RequestHardwareFallbackReplay(); } continue; @@ -958,7 +973,7 @@ private void VideoLoop() // the key frame. codec = FallBackToSoftware(codec, stream, 0, ref hardware); serial = -1; - Seek(Position); + minimumReplaySerial = RequestHardwareFallbackReplay(); continue; } @@ -1012,6 +1027,22 @@ private void VideoLoop() } } + private int RequestHardwareFallbackReplay() + { + var target = Position; + Seek(target); + + // Do not let already-demuxed packets from the failed hardware serial feed the fresh + // software decoder before the demux thread performs the seek. A user seek that races + // with this one has a higher serial and is also safe to accept. + _videoFrames.Flush(); + _presentWake.Set(); + lock (_seekLock) + { + return _requestedSerial; + } + } + private AVCodecContext* FallBackToSoftware(AVCodecContext* codec, AVStream* stream, int error, ref bool hardware) { var reason = error < 0 ? FfmpegLibraries.ErrorText(error) : "picture transfer failed";