From 2d7d447b464eb2b5a5d18c4870e56d56b27559c2 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Thu, 28 Aug 2025 16:21:27 +0200 Subject: [PATCH 1/2] Consider hidden frames in FrameFromPTS/Pos when seeking 01cae8948d809610c2f5864d40f18256aa09a8c6 added the AllowHidden parameter to FrameFromPTS/Pos to be able to recognize the current packet in DecodePacket, but kept it set to false in the other invocations to change as little existing behavior as possible. However, it looks like it's actually correct to also allow hidden frames in the other invocations in GetFrame, since those call FrameFromPTS to find out what packet the demuxer ended up at after a seek. FFMS/ffms2#456 shows a file where this makes a difference, since its first few frames are marked as hidden. Setting AllowHidden to true everywhere in the decoding loop (just not in GetFrameByTime) also causes no regressions on the Doom9 seeking sample collection (https://forum.doom9.org/showthread.php?p=1992736#post1992736). --- src/core/track.cpp | 4 ++-- src/core/track.h | 6 +++--- src/core/videosource.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/track.cpp b/src/core/track.cpp index 604e1493df..0acf022f9d 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -177,12 +177,12 @@ int FFMS_Track::FrameFromPos(int64_t Pos, bool AllowHidden) const { return -1; } -int FFMS_Track::ClosestFrameFromPTS(int64_t PTS) const { +int FFMS_Track::ClosestFrameFromPTS(int64_t PTS, bool AllowHidden) const { FrameInfo F; F.PTS = PTS; auto Pos = std::lower_bound(begin(), end(), F, PTSComparison); - while (Pos != end() && Pos->Skipped() && Pos->PTS == PTS) + while (Pos != end() && (!AllowHidden && Pos->Skipped()) && Pos->PTS == PTS) Pos++; if (Pos == end()) diff --git a/src/core/track.h b/src/core/track.h index dde1321881..ad6960681e 100644 --- a/src/core/track.h +++ b/src/core/track.h @@ -82,9 +82,9 @@ struct FFMS_Track { void FillAudioGaps(); int FindClosestVideoKeyFrame(int Frame) const; - int FrameFromPTS(int64_t PTS, bool AllowHidden = false) const; - int FrameFromPos(int64_t Pos, bool AllowHidden = false) const; - int ClosestFrameFromPTS(int64_t PTS) const; + int FrameFromPTS(int64_t PTS, bool AllowHidden = true) const; + int FrameFromPos(int64_t Pos, bool AllowHidden = true) const; + int ClosestFrameFromPTS(int64_t PTS, bool AllowHidden = true) const; int RealFrameNumber(int Frame) const; int VisibleFrameCount() const; diff --git a/src/core/videosource.cpp b/src/core/videosource.cpp index c27b5d6f98..15cfcdc86d 100644 --- a/src/core/videosource.cpp +++ b/src/core/videosource.cpp @@ -498,7 +498,7 @@ FFMS_VideoSource::~FFMS_VideoSource() { FFMS_Frame *FFMS_VideoSource::GetFrameByTime(double Time) { // The final 1/1000th of a PTS is added to avoid frame duplication due to floating point math inexactness // Basically only a problem when the fps is externally set to the same or a multiple of the input clip fps - int Frame = Frames.ClosestFrameFromPTS(static_cast(((Time * 1000 * Frames.TB.Den) / Frames.TB.Num) + .001)); + int Frame = Frames.ClosestFrameFromPTS(static_cast(((Time * 1000 * Frames.TB.Den) / Frames.TB.Num) + .001), false); return GetFrame(Frame); } @@ -743,7 +743,7 @@ bool FFMS_VideoSource::DecodePacket(AVPacket *Packet) { std::swap(DecodeFrame, LastDecodedFrame); ResendPacket = false; - int PacketNum = Frames.FrameFromPTS(Frames.UseDTS ? Packet->dts : Packet->pts, true); + int PacketNum = Frames.FrameFromPTS(Frames.UseDTS ? Packet->dts : Packet->pts); bool PacketHidden = !!(Packet->flags & AV_PKT_FLAG_DISCARD) || (PacketNum != -1 && Frames[PacketNum].MarkedHidden); bool SecondField = PacketNum != -1 && Frames[PacketNum].SecondField; From 22750af5dbf289ce640a587f1ca2219bed01e6cd Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Fri, 29 Aug 2025 12:34:14 +0200 Subject: [PATCH 2/2] Remove workaround for h264 decoder bug FFMS2 requires ffmpeg 7.1 now, which fixes this bug. --- src/core/videosource.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/videosource.cpp b/src/core/videosource.cpp index 15cfcdc86d..cc579ba78e 100644 --- a/src/core/videosource.cpp +++ b/src/core/videosource.cpp @@ -918,11 +918,6 @@ bool FFMS_VideoSource::SeekTo(int n, int SeekOffset) { // Is the +1 necessary here? Not sure, but let's keep it to be safe. int EndOfStreamDist = CodecContext->has_b_frames + 1; - if (CodecContext->codec_id == AV_CODEC_ID_H264) - // Work around a bug in ffmpeg's h264 decoder where frames are skipped when seeking too - // close to the end in open-gop files: https://trac.ffmpeg.org/ticket/10936 - EndOfStreamDist *= 2; - TargetFrame = std::min(TargetFrame, Frames.RealFrameNumber(std::max(0, VP.NumFrames - 1 - EndOfStreamDist))); if (SeekMode < 3)