From 2dc9794434884df6a9ecd20c1cc494c9dd63c714 Mon Sep 17 00:00:00 2001 From: havetc Date: Tue, 25 Apr 2023 01:34:35 +0200 Subject: [PATCH] Updating framerate management Now the lag is registered globally (and not only the delta time to the frame before), which allows to skip frames or to sleep more precisely, if lags accumulate slowly Tested on a 120fps 1080p video, it skipped a lot of frames but the video speed was accurate. On small SD videos, it was displaying the right framerate, without skip and without going too fast. --- tkVideoPlayer/tkvideoplayer.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tkVideoPlayer/tkvideoplayer.py b/tkVideoPlayer/tkvideoplayer.py index b687381..4404a23 100644 --- a/tkVideoPlayer/tkvideoplayer.py +++ b/tkVideoPlayer/tkvideoplayer.py @@ -140,6 +140,7 @@ def _load(self, path): now = time.time_ns() // 1_000_000 # time in milliseconds then = now + lag = 0 time_in_frame = (1/self._video_info["framerate"])*1000 # second it should play each frame @@ -153,15 +154,33 @@ def _load(self, path): self._seek_sec = 0 if self._paused: + lag = 0 # we must keep lag at 0 and timers at now to avoid a massive frame skip when resuming + now = time.time_ns() // 1_000_000 # time in milliseconds + then = now time.sleep(0.0001) # to allow other threads to function better when its paused continue now = time.time_ns() // 1_000_000 # time in milliseconds delta = now - then # time difference between current frame and previous frame then = now - + + # we add the difference between delta and time_in_frame to lag + lag = lag + delta - time_in_frame # print("Frame: ", frame.time, frame.index, self._video_info["framerate"]) try: + if self.consistant_frame_rate: + # for each time_in_frame we are late, we skip a frame + for i in range(0, int(max(0, lag) / time_in_frame)): + frame = next(self._container.decode(video=0)) + lag -= time_in_frame # we skipped a frame so lag is reduced + self._frame_number += 1 + # we must check if second changed, otherwise this event could be skipped + if self._frame_number % self._video_info["framerate"] == 0: + self.event_generate("<>") + + # otherwise if we are too fast (lag < 0), we wait -lag amount + time.sleep(max(0, -lag)/1000) + frame = next(self._container.decode(video=0)) self._time_stamp = float(frame.pts * stream.time_base) @@ -175,11 +194,6 @@ def _load(self, path): if self._frame_number % self._video_info["framerate"] == 0: self.event_generate("<>") - if self.consistant_frame_rate: - time.sleep(max((time_in_frame - delta)/1000, 0)) - - # time.sleep(abs((1 / self._video_info["framerate"]) - (delta / 1000))) - except (StopIteration, av.error.EOFError, tk.TclError): break