From ae042222477b9b9c7b7df5c0be4c195b578ad962 Mon Sep 17 00:00:00 2001 From: Zaggy1024 Date: Tue, 9 Jun 2026 17:11:46 -0500 Subject: [PATCH] LibMedia: Don't display video frames that are late Frames are considered late if the time is ahead by half their duration. The fudging is necessary because Matroska (and perhaps other formats) store their frame durations in different time units than their timestamps. Skipping these should make it clear when decoding is running behind, instead of displaying the video in slow motion while audio runs at a normal rate. To give an accurate counting for video playback quality when it is implemented, we'll most likely want to count all pulled frames in an update as dropped if the last frame is dropped. Otherwise the frame drop count will only increase at the display rate when decoding is continually running behind. --- Libraries/LibMedia/Sinks/DisplayingVideoSink.cpp | 16 ++++++++++++++++ Libraries/LibMedia/Sinks/DisplayingVideoSink.h | 1 + 2 files changed, 17 insertions(+) diff --git a/Libraries/LibMedia/Sinks/DisplayingVideoSink.cpp b/Libraries/LibMedia/Sinks/DisplayingVideoSink.cpp index 2909864c85..77e8667c4c 100644 --- a/Libraries/LibMedia/Sinks/DisplayingVideoSink.cpp +++ b/Libraries/LibMedia/Sinks/DisplayingVideoSink.cpp @@ -85,6 +85,8 @@ void DisplayingVideoSink::seek(AK::Duration timestamp) auto can_resolve_seek_within_cached_frames = [&] { if (m_seek_status != SeekStatus::None) return false; + if (m_cached_frames_are_discontinuous) + return false; auto available_start = AK::Duration::max(); auto available_end = AK::Duration::min(); auto include_frame = [&](RefPtr const& frame) { @@ -150,7 +152,21 @@ DisplayingVideoSinkUpdateResult DisplayingVideoSink::update() break; if (m_next_frame->timestamp() > current_time) break; + if (current_time > conservative_frame_end(*m_next_frame)) { + consume_moved_position_signals(last_status); + if (m_next_frame == nullptr) + continue; + if (!is_terminal(last_status)) { + if (last_status == PipelineStatus::HaveData) { + m_next_frame.clear(); + m_cached_frames_are_discontinuous = true; + continue; + } + break; + } + } m_current_frame = m_next_frame.release_nonnull(); + m_cached_frames_are_discontinuous = false; result = DisplayingVideoSinkUpdateResult::NewFrameAvailable; } diff --git a/Libraries/LibMedia/Sinks/DisplayingVideoSink.h b/Libraries/LibMedia/Sinks/DisplayingVideoSink.h index 53f765a935..5274a716e3 100644 --- a/Libraries/LibMedia/Sinks/DisplayingVideoSink.h +++ b/Libraries/LibMedia/Sinks/DisplayingVideoSink.h @@ -49,6 +49,7 @@ private: RefPtr m_next_frame; RefPtr m_current_frame; + bool m_cached_frames_are_discontinuous { false }; enum class SeekStatus : u8 { None,